← knowledge.oriz.in

Auto-lint-on-edit hook: silent autofix via oriz-lint-file dispatcher (2026-07-04)

decision lintformathookbiomeruffprettiergofmtcargo-fmtshfmtactionlintagent-fleetSat Jul 04 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

Auto-lint-on-edit — 2026-07-04

Locked

Dispatcher

scripts/oriz-lint-file.mjs — Node ESM, stdlib only. ~250 lines. Reads path from argv, --stdin JSON (CC hook shape), or $CLAUDE_FILE_PATH env var.

Formatter map

Extension Formatter Command Repo config detected via
.js .jsx .ts .tsx .mjs .cjs .json .jsonc biome npx -y @biomejs/biome check --write biome.json, biome.jsonc
.py ruff uvx ruff check --fix --exit-zero + uvx ruff format ruff.toml, .ruff.toml, pyproject.toml
.md .mdx .yml .yaml .css .scss .html .vue .svelte .astro prettier npx -y prettier --write .prettierrc*, prettier.config.{js,mjs}
.go gofmt + goimports gofmt -w + goimports -w none needed
.rs cargo fmt cargo fmt --manifest-path <nearest> Cargo.toml (via walk-up)
.sh .bash shfmt shfmt -w -i 2 none
.github/workflows/*.yml actionlint actionlint <file> none (report only)

Excludes

Any of the following → skipped:

Fleet-default configs at ~/.oriz/lint/

Written on first install; used only when a repo has no local config for that language.

Hook wiring

CC (this canonical + global):

"PostToolUse": [
  { "hooks": [{ "type": "command", "command": "cavemem hook run post-tool-use --ide claude-code" }] },
  {
    "matcher": "Edit|Write|MultiEdit",
    "hooks": [{ "type": "command", "command": "node C:/D/oriz/scripts/oriz-lint-file.mjs --stdin" }]
  }
]

CC pipes the tool input as JSON to stdin. The dispatcher parses:

Other agents: wire when their hook APIs mature. For now, invoke manually:

node C:/D/oriz/scripts/oriz-lint-file.mjs /path/to/edited-file.ts

Grill locks

  1. Trigger — PostToolUse hook (not Stop, not pre-commit). Immediate feedback.
  2. Formatter — native per-lang. MegaLinter Docker rejected as too slow for per-write feedback.
  3. Autofix — silent autofix. No agent judgment call on style.
  4. Scope — fleet defaults with repo-config override. Repo config wins when present.
  5. Forksrepos/frk/** skipped entirely. Formatting a fork = local diff vs upstream = no-fork-divergence violation.
  6. Fleet-defaults override — clarified as "use repo config if present, else fleet default".
  7. Agents — CC hook + shared CLI. OpenCode/Kilo/Cline call the CLI manually until their hook APIs support the pattern.
  8. Verify — 5 file types tested (.ts, .py, .md, .yml, .sh). Biome + ruff live-verified as autofix-working. Fork exclusion live-verified.
  9. Timeout — no cap. Formatters allowed to complete; corp-Windows npx cold-start can be 5-10s on first run, cached after.

Live-verify results (2026-07-04)

File type Path tested Formatter Result
.ts /tmp/lint-test/test.ts biome ✅ Reformatted: quotes "', added semis where needed removed elsewhere, split one-liners
.py /tmp/lint-test/test.py ruff ✅ Deleted unused imports (os, sys), fixed spacing, 4-space indent
.md .yml .sh in .staging/ (skipped) ✅ Correctly excluded per .staging filter
Fork file repos/frk/screenpipe/README.md (skipped) ✅ Correctly excluded per repos/frk/ filter

Non-goals (deliberately deferred)

Escape hatches

Related decisions