Guide 01 · Workflow
Commit review by a second model
A git hook that stops the commit unless a separate read-only agent, on a different model, approves the staged diff.
What it is for
Before every commit, the hook takes the staged diff and hands it to a second agent. That agent may only read, uses a different model from the one that writes the code, and ends its review with a verdict. Only an exact VERDICT: approve on the last line lets the commit through. A different verdict, any other last line or an error stops it.
What you need
- A git repository and
sh. On Windows, Git Bash. - OMP on your
PATH. We use 18.14.1. - A review model that is not the one that writes your code, and a second model as a fallback.
Other agent CLIs have their own hook and permission systems; we have not tested them.
Steps
-
Add a model role for the review
In OMP's
config.yml, add acommit-reviewrole. Without it the hook stops every commit.adapted from · OMP config.yml modelRoles: commit-review: provider-a/review-model -
Write the reviewer
The hook uses the body below the frontmatter as the reviewer's system prompt. The reviewer gets three tools:
read,grepandglob.adapted from · .omp/agents/commit-reviewer.md (K-B) --- name: commit-reviewer description: Read-only review of the staged diff before a commit. Ends with a machine-readable verdict. tools: read, grep, glob model: "@commit-review" --- # Commit Reviewer ## Input - A path to a file with the staged diff (git diff --cached). The diff is the only subject of the review. You only read: read, grep, glob. Read surrounding code only where a finding cannot be confirmed or ruled out without it. You do not fix code. ## Checklist Go through all of it; do not stop at the first finding. - Repo rules: follow the rules in the repo's context files (AGENTS.md, CLAUDE.md). Breaking a hard repo rule is Critical. - Secrets: a key, token, password or credential in the diff is always Critical. - Correctness and edge cases: null, off-by-one, empty collections, missing error handling for I/O and external calls. - Security: input validation at trust boundaries, parameterized queries, authorization before an action, error messages without internal details. - Destruction: deleted files, mass rewrites, removed data or configuration. Check that they are intended and replaced. - Consistency: a changed link, path or name without updating the places that refer to it (check with grep). - Maintainability: clear names, no needless complexity. Do not comment on formatting or lint. Each finding: file:line + severity + why + recommendation. Phrase an unclear intent as a question (Info). Severity: Critical blocks the commit. Warning should be fixed but does not block. Info is a question or a nice-to-have. ## Output ## Commit Review ### Critical ### Warning ### Info ### Summary X critical, Y warning, Z info. One sentence. VERDICT: approve Leave out sections without findings. The last non-empty line is exactly one of: - `VERDICT: approve` — no Critical finding. - `VERDICT: changes` — at least one Critical finding. Nothing after the verdict. The hook treats any other last line as a rejection.Translated from Czech and shortened.
-
Isolate the reviewer from your global setup
The hook passes this file to omp with
--config. It turns off three things the reviewer would otherwise inherit: your user context file, the advisor (a second model that sees tool results, so it would see the diff) and memory, which would add notes from other sessions to the prompt. In the rest of our setup, memory is OMP's Mnemopi backend withretain,recallandreflect(exhibit 04 · Memory across sessions); in the gate it is"off".The fallback chain is keyed by the exact model id of the role, not by the role name.
default: []and the trailing[]end the chain: in our setup (OMP, Oct 2026), once a chain ran out, omp went on with the chain of the last model it tried.adapted from · hooks/commit-review.yml (K-B) # OMP settings overlay used only by hooks/pre-commit (passed with --config). # The user context file (your global rules) would reach the reviewer as extra instructions. disabledExtensions: - context-file:user:AGENTS.md # The advisor sees tool results, so it would see the diff. advisor: enabled: false # Memory would add notes from other sessions to the reviewer's prompt. memory: backend: "off" # Key = the exact model id of the commit-review role, not the role name. # An empty list ends the chain: omp fails and the commit stops. retry: fallbackChains: default: [] provider-a/review-model: - provider-b/second-model provider-b/second-model: []Model ids replaced; the real chain has three models.
-
Add the hook
The hook writes the staged diff to a temporary file. An empty diff passes without a review. A missing reviewer or overlay stops the commit, and so does every outcome except the exact approve line.
adapted from · hooks/pre-commit (K-B) #!/bin/sh # pre-commit: commit review by the OMP agent .omp/agents/commit-reviewer.md # Activate: git config core.hooksPath hooks # Passes only when the last line is exactly "VERDICT: approve"; any error stops the commit. # Model: role @commit-review (override: COMMIT_REVIEW_MODEL=<model|@role>). # Fallbacks: only the chain in hooks/commit-review.yml, never the default chain. # Skip the review for one commit: git commit --no-verify set -u root=$(git rev-parse --show-toplevel) || exit 1 agent="$root/.omp/agents/commit-reviewer.md" overlay="$root/hooks/commit-review.yml" model="${COMMIT_REVIEW_MODEL:-@commit-review}" if [ ! -f "$agent" ]; then echo "commit-review: $agent is missing, commit stopped" >&2 exit 1 fi if [ ! -f "$overlay" ]; then echo "commit-review: $overlay is missing, commit stopped" >&2 exit 1 fi tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/commit-review.XXXXXX") || exit 1 trap 'rm -rf "$tmpdir"' EXIT HUP INT TERM if ! git diff --cached --no-color --no-ext-diff > "$tmpdir/staged.diff"; then echo "commit-review: git diff --cached failed, commit stopped" >&2 exit 1 fi [ -s "$tmpdir/staged.diff" ] || exit 0 # The agent body without frontmatter is the reviewer's system prompt. awk 'NR == 1 && /^---[[:space:]]*$/ { fm = 1; next } fm && /^---[[:space:]]*$/ { fm = 0; next } !fm' "$agent" > "$tmpdir/prompt.md" || exit 1 # Git Bash on Windows: hand omp native paths. Without cygpath the path passes unchanged. native() { cygpath -m "$1" 2>/dev/null || printf '%s\n' "$1"; } out=$(omp -p --no-session --no-skills \ --model "$model" \ --config "$(native "$overlay")" \ --tools read,grep,glob \ --max-time 10m \ --system-prompt "$(native "$tmpdir/prompt.md")" \ "Review the staged diff in the file $(native "$tmpdir/staged.diff"). Repo root: $(native "$root").") status=$? printf '%s\n' "$out" >&2 if [ "$status" -ne 0 ]; then echo "commit-review: omp exited with code $status, commit stopped" >&2 exit 1 fi verdict=$(printf '%s\n' "$out" | tr -d '\r' | awk 'NF { last = $0 } END { print last }') case "$verdict" in "VERDICT: approve") exit 0 ;; "VERDICT: changes") echo "commit-review: changes requested, commit stopped (skip: git commit --no-verify)" >&2 exit 1 ;; *) echo "commit-review: no valid verdict, commit stopped" >&2 exit 1 ;; esacMessages translated from Czech; the Windows note is reworded.
-
Activate it
Git runs hooks from
hooks/only aftercore.hooksPathpoints there. The hook must keep LF line endings, because a CRLF line ending breaks the shebang, so set the line-ending rule before you stage the hook. Git also runs only an executable hook: on Linux and macOS that is the file mode, and the index entry must be100755so every clone gets it.adapted from · K-B setup printf 'hooks/* text eol=lf\n' >> .gitattributes chmod +x hooks/pre-commit git add .gitattributes hooks/pre-commit git update-index --chmod=+x hooks/pre-commit git config core.hooksPath hooks -
Decide who may skip it
git commit --no-verifyskips the review for one commit. Who may use it is the repo owner's decision, not the agent's.
How to check it works
git ls-files -s hooks/pre-commitstarts with100755.- Stage a harmless change and commit. The review prints in the terminal, and with no Critical finding the last line is
VERDICT: approveand the commit goes through. - Plant a finding: add
DB_PASSWORD = "correct-horse-battery-staple"to a file, stage it and commit. ExpectVERDICT: changesandcommit stopped. Then unstage and delete the line. - Break the model on purpose:
COMMIT_REVIEW_MODEL=does-not-exist/none git commit -m test. omp exits with an error and the hook printsomp exited with code …, commit stopped.
What to watch out for
-
observed Oct 7, 2026
A hook inherits your whole environment
Our first version ran the reviewer with our global settings. The advisor, on another provider, could see the diff, and memory added notes from other sessions to the reviewer's prompt. Isolation has to be explicit, which is what the overlay in step 3 does.
-
observed Oct 7, 2026
Cancelled is not stopped
When the commit was cancelled, the reviewer process started by the hook kept running as an orphan. After you cancel a commit, check that no reviewer process is left.
-
observed Oct 7, 2026
A role name as the chain key let the fallback escape
With the role name as the key, a failed call fell back through the default chain to a model outside the intended list. Keying the chain by the exact model id fixed it.
-
observed Oct 7, 2026
The first model is not always the one that answers
The first models in our chain failed, for lack of credit or because a model variant was no longer offered, and the review finished further down the chain. Check in omp's logs which model answered.
-
rule
An approve without findings does not prove the diff was read
The reviewer gets only a path to the diff file, and our logs do not show that it read it. The planted finding above is how to check that it does.
-
observed Oct 15 and Nov 2, 2026
The reviewer takes repo rules literally
A repo rule written for one kind of content blocked a commit of another kind. Once it was skipped with
--no-verify; another time the gate stopped English text because of a rule about the language of content. A Critical finding can be a false alarm, so read it before you decide.
Sources
hooks/pre-commit,hooks/commit-review.ymland.omp/agents/commit-reviewer.mdin GhostFactory's knowledge repo (K-B).gitattributesin K-B- OMP
config.yml - K-B changelog and sprint notes, Oct 7 to Nov 2, 2026