# Push Flow Convention

> Enforce pre-commit/pre-push hooks, lint-staged checks, and semver version bump on every push

- Skill: `kana-consultant/push-flow-convention` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kana-consultant/push-flow-convention`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kana-consultant/push-flow-convention/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kana-consultant (https://skillmd.com/u/kana-consultant)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kana-consultant/push-flow-convention

---


# Push Flow Convention

Every repository MUST enforce the same pre-commit, pre-push, and versioning flow. No push lands without hooks, lint-staged, and a version bump.

## Required Setup

### 1. Lefthook (pre-commit + pre-push)

> **Always use [Lefthook](https://lefthook.dev/) for git hooks. Never use husky.**

Install once per repo:

```bash
pnpm add -D lefthook lint-staged
pnpm exec lefthook install
```

Create `lefthook.yml` in project root:

```yaml
pre-commit:
  commands:
    lint-staged:
      run: pnpm exec lint-staged

pre-push:
  commands:
    lint-staged:
      run: pnpm exec lint-staged --diff="origin/{push_remote_branch}...HEAD"
    bump:
      run: pnpm run bump
```

### 2. lint-staged

Declared in `package.json`. Runs ONLY on staged files so commits stay fast.

```json
{
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,yml,yaml}": [
      "prettier --write"
    ]
  }
}
```

### 3. Version bump script

`package.json` MUST expose a `bump` script used by `pre-push`:

```json
{
  "scripts": {
    "bump": "node scripts/bump-version.mjs"
  }
}
```

The script inspects the diff between the current branch and its upstream, applies the semver rule below, and writes the new version back to `package.json`. Commit the bump before pushing (amend the previous commit or create a `chore: adjust package.json version (bump)` commit — see `commit-convention`).

## Semver Rules (applied on every push)

The bump is based on the changes in the commits being pushed:

| Change size / kind | Bump |
|--------------------|------|
| `< 5` changed files across pushed commits | **patch** (`x.y.Z`) |
| `>= 5` changed files across pushed commits | **minor** (`x.Y.0`) |
| New feature OR new behaviour (any `feat:` commit) | **major** (`X.0.0`) |

Rules in order of precedence:
1. If ANY commit being pushed is a `feat(...)` → **major** bump.
2. Otherwise, count files changed (`git diff --name-only origin/<branch>...HEAD | wc -l`):
   - fewer than 5 → **patch**
   - 5 or more → **minor**

The `feat` rule always wins — a new feature is always a major bump regardless of file count.

## Non-negotiables

1. NEVER push without pre-commit and pre-push hooks installed.
2. NEVER bypass hooks with `--no-verify` — if a hook fails, fix the root cause.
3. NEVER push without a version bump. Every push = new version.
4. The bump commit MUST use the `chore: adjust package.json version (bump)` message (see `commit-convention`).
5. lint-staged MUST run on every commit. A green lint-staged is a prerequisite for the commit to be created.
6. If `pnpm` is not the package manager, substitute with `npm` or `yarn` but keep the same flow.

## Quick verification checklist

Before declaring the push flow set up, confirm:

- [ ] `lefthook.yml` exists with `pre-commit` and `pre-push` hooks
- [ ] `pnpm exec lefthook install` has been run (hooks registered in `.git/hooks/`)
- [ ] `package.json` has a `lint-staged` block
- [ ] `package.json` has a `bump` script
- [ ] A dry-run commit triggers lint-staged
- [ ] A dry-run push triggers the version bump

