salt-prepush
v0.1.0
Published
AI-powered pre-push code review installer. Runs lint and AI code review against docs/code-standard.md on every git push.
Maintainers
Readme
salt-prepush
AI-powered pre-push code review for any git repository. Runs your project's lint, then has an AI agent (Claude Code, Codex CLI, or Gemini CLI) review the diff against your docs/code-standard.md before every git push.
npx salt-prepush init # one-time setup
git push # lint + AI review, blocks on critical issues
git push --no-verify # bypass when neededReplaces the slow "open MR → wait for review → fix → re-push" loop with fast feedback at the moment of commit. Complements your existing code review process by catching mechanical violations (lint, hardcoded secrets, naming, file-size limits) automatically.
Quick start
# 1. From inside your project, run the installer
npx salt-prepush init --agent claude --lint "npm run lint"
# 2. (Optional) Seed your code-standard.md from the bundled default
npx salt-prepush init --init-rules
# 3. Push normally. The hook fires automatically.
git pushThe init command writes two files:
.git/hooks/pre-push— the bash hook (lint → build prompt → invoke agent → parse verdict).salt-prepush.json— your config (agent, lint, rules path)
That's it. No daemon, no server, no token to manage beyond what your AI agent already needs.
What it does
git push
↓
.git/hooks/pre-push (bash)
├─ Step 1: run lint command
│ └─ non-zero exit → block push
├─ Step 2: build prompt (diff + changed files + docs/code-standard.md)
├─ Step 3: invoke your AI agent with the prompt
├─ Step 4: grep agent output for "VERDICT: FAIL"
│ ├─ found → block push
│ └─ not found / agent errored → allow push (safety net)The AI agent reads your project's rules, your diff, and the changed files in context. It emits findings tagged [BLOCKING] (blocks push), [WARNING] (reported only), or [INFO] (style nits). The hook only acts on VERDICT: FAIL; everything else is shown to you and push proceeds.
If the agent crashes, times out, or returns malformed output, the safety net allows the push with a yellow warning. A flaky LLM call never bricks your push — you can always use --no-verify.
Configuration
Init flags
| Flag | Default | Notes |
|---|---|---|
| --agent <name> | (prompts) | claude, codex, or gemini |
| --lint <command> | npm run lint | Anything shell-runnable (e.g. pnpm lint, make lint, echo ok) |
| --rules <path> | docs/code-standard.md | Path to your rules file |
| --init-rules | — | Copy the bundled default rules if missing |
If you omit flags and stdin is a TTY, init prompts interactively. If stdin is not a TTY (CI), required flags must be passed.
.salt-prepush.json
{
"version": 1,
"agent": "claude",
"lint": "npm run lint",
"rulesPath": "docs/code-standard.md",
"generatedBy": "salt-prepush v0.1.0",
"generatedAt": "2026-08-28T..."
}Re-run npx salt-prepush init to update. The hook is regenerated from your latest flags; your .salt-prepush.json is updated in place.
Supported AI agents
| Agent | Command | Notes |
|---|---|---|
| claude | claude -p "<prompt-file>" | Claude Code — Anthropic |
| codex | codex exec "<prompt-file>" | Codex CLI — OpenAI |
| gemini | gemini -p "<prompt-file>" | Gemini CLI — Google |
The agent must be installed and authenticated on your machine. salt-prepush does not ship or proxy API keys — it assumes you've already set up the agent you want to use.
Adding a new agent: edit lib/agents.js (one entry per agent), submit a PR.
Customizing
The bundled review prompt lives in prompts/review.md and is embedded into every installed hook. To customize the review for your team, fork salt-prepush and edit the prompt there — or open an issue with your rule additions and we'll consider adding them upstream.
The bundled default rules live in templates/code-standard.md (619 lines, SALT TypeScript/React standards). When you run --init-rules, this gets copied to your project's docs/code-standard.md. After that, edit your local copy freely — salt-prepush never overwrites it again unless you re-run with --init-rules.
Troubleshooting
"agent failed" warning / push allowed when it shouldn't be
The hook couldn't parse VERDICT: FAIL from the agent's output. Most often this means:
- Agent not authenticated. Run your agent directly (
claude -p "hi") to confirm auth. - Agent response is too large / got truncated. The prompt includes the full diff + files + rules; very large diffs can exceed the agent's context window.
- Agent not following the structured format. Stock Claude Code / Codex / Gemini follow the format from prompts/review.md. Custom models or wrappers may not.
Verify by running the hook manually:
salt-prepush runLint command fails on every push
The lint command is run exactly as you configured it. Debug by running the same command in your shell:
# What you configured:
"pnpm lint"
# What salt-prepush runs:
sh -c "pnpm lint"If it fails inside salt-prepush but works in your shell, the issue is environment (PATH, working directory, env vars). Use bash .git/hooks/pre-push </dev/null from the repo root to debug.
"Not a git repository"
npx salt-prepush init must be run inside a git repository. If you want it elsewhere, cd to the repo root first.
Hook didn't run on push
Check that the hook is installed and executable:
ls -la .git/hooks/pre-push # should be -rwxr-xr-x
cat .git/hooks/pre-push | head -5 # should show the salt-prepush headerIf the file is missing or empty, re-run npx salt-prepush init. If it's there but git ignores it, check git config core.hooksPath — if it's set to a custom directory, git looks for hooks there instead of .git/hooks/.
I want to skip the hook for one push
git push --no-verifyI want to disable salt-prepush entirely
rm .git/hooks/pre-push(Or git config core.hooksPath /dev/null on Unix.) The .salt-prepush.json config stays around as a record; delete it if you want a fully clean slate.
Development
git clone https://github.com/salt-id/salt-prepush
cd salt-prepush
npm install # no deps, just to enable `npm test`
npm test # runs node --test test/, ~300msTest the package locally in a scratch project:
mkdir /tmp/my-app && cd /tmp/my-app
git init
npm install /path/to/salt-prepush
npx salt-prepush init --agent claude --lint "echo ok"
git push # watch the hook fireSee test-app/ for a worked example (it's in .gitignore, but the structure is documented above).
How it works (architecture)
salt-prepush/
├── bin/salt-prepush.js # CLI entry, dispatches init | run
├── lib/
│ ├── index.js # main(argv) dispatcher
│ ├── init.js # interactive + flag-driven install
│ ├── run.js # stub for manual hook debugging
│ ├── agents.js # 3 agent command shapes
│ ├── hook-template.sh # bash template with placeholders
│ ├── write-hook.js # renders template → .git/hooks/pre-push
│ └── write-config.js # writes .salt-prepush.json
├── prompts/review.md # bundled AI review prompt (embedded in hook)
├── templates/code-standard.md # bundled default rules (copied by --init-rules)
└── test/ # 34 unit tests, node --test, zero depsThe hook script is self-contained: the prompt is embedded at init time, so push-time has no dependency on salt-prepush being installed. Update flow: re-run npx salt-prepush init to refresh the hook.
License
MIT — see LICENSE.
Related
- docs/salt-prepush-spec.md — the 12-decision spec that drove this design
- docs/code-standard.md — the bundled rules reference
- .claude/commands/mr-reviewer.md — the deprecated GitLab MR reviewer (in
legacy/)
