Skip to content

feat(agent): lint and format staged changes on commit - #843

Merged
patroza merged 1 commit into
mainfrom
feat/lint-staged-on-commit
Aug 4, 2026
Merged

feat(agent): lint and format staged changes on commit#843
patroza merged 1 commit into
mainfrom
feat/lint-staged-on-commit

Conversation

@patroza

@patroza patroza commented Aug 4, 2026

Copy link
Copy Markdown
Member

Why

Staged changes were formatted on commit but not linted, so a lint error survived
the commit and first surfaced at the push gate or in CI — far from the change
that caused it, and after the history had already been written. Fixing it then
costs a follow-up commit on a branch that is meant to read as one increment per
change.

What

Staged code files now run oxlint --fix before dprint fmt.

How

oxlint here is the fast, non-type-aware pass — what can run per file in the
time a commit should take. The full --type-aware lint (and eslint, where the
repo has it) still runs in the ship gate and CI, so this narrows the feedback
loop rather than replacing those.

Two details that are load-bearing rather than stylistic:

  • Lint and format share one array, not two glob entries. lint-staged runs
    separate entries concurrently, and both commands rewrite the file. The globs
    are disjoint for the same reason.
  • --no-error-on-unmatched-pattern is required. .oxlintrc.json ignores
    whole categories of file, and without the flag oxlint exits non-zero on "No
    files found to lint" — so staging only an ignored file would block the commit
    for no reason. This was found the direct way: the first commit of this config
    failed on itself.

The hook also calls the lint-staged binary directly instead of pnpm lint-staged, for the same reason the pre-push hook stopped using pnpm exec: a
moved lockfile makes pnpm try to purge node_modules and abort for want of a
TTY, failing the commit with an error that says nothing about linting.

Remarks

Verified both directions, since a lint step that never fails is worse than none:
a clean commit passes, and a file with debugger / no-eval / no-unused-vars
is reported and exits 1 even under --quiet.

Flow doc updated: n/a (agent tooling)
E2E coverage: n/a — commit hook, no product behaviour; exercised by every commit
Design angles: assumed goal — catch a lint error at the commit that introduced
it; pragmatic (fast oxlint pass per file, full lint stays at the gate) vs.
greenfield (one lint definition shared by hook, gate and CI, so the three cannot
drift). Pragmatic chosen — the three differ today mainly in scope and type-aware
mode, which is a larger consolidation than this change warrants.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

This repo had no pre-commit hook at all, so nothing checked a change until the
push gate — by which point the history was already written and a lint error had
to be fixed in a follow-up commit.

Adds lint-staged with a hook that runs `oxlint --fix` then `dprint fmt` on staged
files. oxlint here is the fast non-type-aware pass, which is what fits in the
time a commit should take; the full `--type-aware` lint and the format check
still run in the ship gate and CI, so this narrows the loop rather than replacing
them.

`--no-error-on-unmatched-pattern` is required rather than cosmetic:
`.oxlintrc.json` ignores whole categories of file — `.js`, `.jsx`, `.d.ts` and
`repos/**` among them — and without it oxlint exits non-zero on "No files found
to lint", so staging only an ignored file would block the commit for no reason.

The hook calls the lint-staged binary directly rather than `pnpm lint-staged`,
for the same reason the pre-push hook stopped using `pnpm exec`: a moved lockfile
makes pnpm try to purge node_modules and abort for want of a TTY.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Aug 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

@effect-app/cli

npm i https://pkg.pr.new/effect-app/libs/@effect-app/cli@843

effect-app

npm i https://pkg.pr.new/effect-app/libs/effect-app@843

@effect-app/eslint-codegen-model

npm i https://pkg.pr.new/effect-app/libs/@effect-app/eslint-codegen-model@843

@effect-app/eslint-shared-config

npm i https://pkg.pr.new/effect-app/libs/@effect-app/eslint-shared-config@843

@effect-app/infra

npm i https://pkg.pr.new/effect-app/libs/@effect-app/infra@843

@effect-app/vue

npm i https://pkg.pr.new/effect-app/libs/@effect-app/vue@843

@effect-app/vue-components

npm i https://pkg.pr.new/effect-app/libs/@effect-app/vue-components@843

commit: b4157b9

@patroza
patroza marked this pull request as ready for review August 4, 2026 05:31
@patroza
patroza merged commit 87708e6 into main Aug 4, 2026
6 checks passed
@patroza
patroza deleted the feat/lint-staged-on-commit branch August 4, 2026 05:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant