How it works¶
The flow¶
flowchart LR
A[git commit / git push] --> B[hook: grip hook stage]
B --> C{Skip?}
C -- GRIP_SKIP / CI / no TTY / empty diff / recently passed --> Z[exit 0]
C -- no --> D[collect diff]
D --> E[provider: 5 questions + rubrics]
E --> F[ask in the terminal]
F --> G[provider: grade answers]
G --> H{score >= passing_score?}
H -- yes --> I[remember pass, exit 0]
H -- no --> J[show feedback, exit 1]
- Collect the diff. For
pre-committhat is the staged changes. Forpre-pushgrip reads the refs git passes on stdin and diffs each remote SHA against the local SHA; for a brand-new branch it diffs against the parent of the oldest commit not on any remote. Under the pre-commit framework it usesPRE_COMMIT_FROM_REF/PRE_COMMIT_TO_REF. Paths matchingexcludeare dropped and the patch is capped atmax_diff_bytes. - Generate questions. One request to the provider returns a summary plus exactly five questions. Each comes with a hidden rubric: the points a complete answer must cover.
- Ask. Questions are shown one at a time on the controlling terminal. You answer in a line; an empty line skips (and scores zero).
- Grade. A second request sends the diff, the questions, the rubrics and your answers. Each answer gets 0 to 20 points and a sentence of feedback.
- Decide. The Grip Score is the sum, 0 to 100. At or above
passing_scorethe hook exits 0 and the diff's digest is remembered; below it the hook exits 1 and the commit or push is blocked.
The Grip Score¶
| Part | Value |
|---|---|
| Questions per quiz | 5, always |
| Points per question | 0 to 20 |
| Grip Score | sum, 0 to 100 |
| Default pass mark | 70 |
Grading is deliberately rubric-based: the questions are written with the rubric, before you answer, so the grader is checking substance rather than improvising. Spelling, grammar and brevity are explicitly ignored in the grading prompt.
difficulty shifts both ends: easy asks about visible behaviour and grades leniently,
hard probes failure modes and interactions with code outside the diff and grades strictly.
What leaves your machine¶
Only two things are sent to the provider: the diff (after exclusions and truncation) and
your answers. No history, no other files, no telemetry. The diff is wrapped in <diff>
delimiters and the model is told to treat anything inside as data, never as instructions.
Reports (questions, answers, grades, score) are written to
.git/grip/last-report.json, or to the path given with --report. Passed digests live in
.git/grip/passed.json.
When grip steps aside¶
grip exits 0 without asking anything when:
GRIP_SKIPis set to a truthy value, or git runs with--no-verify;CIis set (hooks in CI have nobody to answer);- there is no interactive terminal and
require_ttyis false (the default); - the diff is empty after exclusions;
- the exact same diff passed within
remember_passes_hours.
Provider failures (no key, network down, model unavailable) block by default so a
broken setup is noticed rather than silently bypassed. Set fail_open = true to prefer
availability over strictness.