
You push. GitHub Actions spins. CodeRabbit or some other bot takes four minutes, then you have nine comments, three of which are real, one of which is a typo you actually wanted to fix. Stop. A 50-line pre-commit hook reviews your staged diff with Claude before the push. Five minutes from zero to a working reviewer that blocks on real bugs and costs roughly $0.005 per commit.
1. git commit fires the pre-commit hook. 2. The hook captures git diff --staged and ships it to Claude. 3. Claude replies with severity-tagged issues. 4. The hook blocks the commit on HIGH severity. 5. You amend, force the commit with --no-verify, or fix it first.
That is the entire flow. No new SaaS, no GitHub App, no telemetry, no vendor lock-in.
bash pip install pre-commit pre-commit install
pre-commit 3.x. One global install handles every repo you will ever touch.
Create .pre-commit-hooks/llm-review/llm-review.sh:
```bash #!/usr/bin/env bash set -euo pipefail
DIFF=$(git diff --staged | head -c 32000) [ -z "$DIFF" ] && exit 0
PROMPT="Review this git diff. Flag:
Format: SEVERITY: file:line - description If clean, reply exactly: LGTM"
REVIEW=$(claude -p "$PROMPT" --output-format text <<< "$DIFF") echo "$REVIEW"
if echo "$REVIEW" | grep -q "^HIGH"; then echo "" echo "❌ LLM review flagged HIGH-severity issues. Fix or use --no-verify." exit 1 fi ```
chmod +x it. That is the entire engine. It shells out to the claude-code CLI in -p (non-interactive, piped) mode, which is the right primitive for hook-style automation.
```yaml repos:
hooks:
name: LLM Code Review entry: .pre-commit-hooks/llm-review/llm-review.sh language: system stages: [pre-commit] pass_filenames: false ```
Commit the config. Every subsequent commit runs the review before it lands in your local history.
The naive version sends 200KB diffs and burns $0.50 per commit. Three rules keep it cheap.
Truncate hard. head -c 32000 is roughly 8K tokens. Raise to 100K if you regularly commit 500+ line refactors; cap at 200K beyond that and split the review per file.
Skip docs-only commits. Quick gate at the top of the hook:
bash if ! git diff --staged --name-only | grep -vqE '\.(md|txt|rst)$'; then exit 0 fi
Cache by diff hash. Hash the staged diff with git diff --staged | git hash-object --stdin; if you reviewed that hash in the last 24 hours, skip. Worth adding once you commit more than 20 times a day.
Catches: null-deref, hardcoded secrets, missing error handling on file I/O, SQL string concatenation, accidental print(secret), off-by-one in pagination, leftover console.log in shipped JS, missing input validation on public functions.
Misses: business-logic bugs without a syntactic signal, multi-file race conditions, performance regressions in hot paths, anything that needs domain knowledge of your problem space.
Treat it as a strict static analyzer with better coverage of modern idioms, not a human replacement. It catches the cheap 80% a reviewer would catch on a first read, and it catches them in five seconds instead of five hours.
50 lines of bash, 5 minutes of setup, $0.005 per commit, and you will never push a credential inside a print() again. Wire it in. The first time it catches your own bug before CI does, you will not uninstall it.
— Mr. Technology
*Tested with pre-commit 3.5+, claude-code CLI 1.0.18+, Anthropic Claude Sonnet 4.5. Requires ANTHROPIC_API_KEY in your env. For GPT-4.1, swap claude -p for codex -p or call the OpenAI SDK directly. Diff cap of 32K chars is conservative; raise it for repos with frequent large refactors, drop it for tightly-budgeted CI-style commits.*