Session reviewer
The session reviewer closes the loop on hook authoring. The corrections you give Claude during a session — “never force-push”, “use uv, not pip”, “you weakened that test” — are exactly the rules a hook should enforce, but writing the hook by hand is friction you skip in the moment. The reviewer notices those corrections for you. When a session ends, it reads the transcript, finds the durable corrections and the hooks that misfired, and once a pattern proves itself, opens a pull request that adds or fixes a hook. You review the PR like any other.
It is on by default after uvx capt-hook init. This page explains the path from a session to a PR, what it takes to run, and the knobs that decide what crosses the bar.
How it works
The reviewer runs entirely on your machine, riding captain-hook’s own event dispatch:
- The plugin’s hook wiring runs
capt-hook run <Event>for every lifecycle event, and the reviewer rides that dispatch natively — the asyncSessionStartandSessionEndpasses fire the enrollment-gated reviewer, and the throttled sweep ridesStop. There is no dedicated reviewer hook entry to wire or break. The pass detaches into the background and returns immediately, so a utility command likeclaude updatenever blocks on it, and a non-interactiveclaude -psession end is skipped — it carries no corrections worth mining. - The background pass resolves the repo, checks that you are watching it, then scans the ended transcript for two things: durable corrections you gave, and hooks that fired when they should not have.
- Each finding is judged by an LLM for whether it states a durable, enforceable rule.
- A judged finding becomes a candidate. The reviewer tracks it across sessions and only acts once it clears its thresholds.
- An eligible candidate spawns a headless brain (
claude -prunning thescanning-sessionsskill) inside the repo, which drafts the hook, proves it withuvx capt-hook test, and opens one pull request carrying the verbatim evidence.
Candidates come in two kinds. A create candidate turns a recurring correction into a new hook. A fix candidate amends a hook that misfired, adding a regression test that reproduces the misfire. Fix candidates clear the bar faster — a hook firing when it should not is a concrete, actionable defect.
Turn it on
uvx capt-hook init arms the reviewer for the current repo. To arm a repo without re-running init, enable it directly:
uvx capt-hook review enableBoth paths set up what the reviewer needs:
- the captain-hook plugin registered in
.claude/settings.json— its event wiring carries the reviewer along with every other hook, and the brain loads the plugin’sscanning-sessionsandauthoring-hooksskills directly; - a per-machine watching flag for this repo.
The plugin owns the event wiring; review enable writes no hook entries of its own. Watching is stored once per machine, and the reviewer enrolls a repo the first time it runs in it — a plugin-wired clone is watched from its first session end with no manual step. review enable arms a repo immediately instead of waiting for that first session; review disable is the durable opt-out, which auto-enrollment never overrides.
Prerequisites
The reviewer shells out to two CLIs, so both must be authenticated:
claude— the judge and the PR-drafting brain both call it. Log in withclaudeonce.gh— the brain opens the PR with it. Authenticate with push and pull-request scope (gh auth login).
The repo also needs a git remote; the reviewer keys candidates to the normalized origin.
What crosses the bar
A correction does not become a PR the moment you say it. It has to recur, survive an LLM verdict, and clear thresholds — so a one-off aside never turns into noise. Every threshold is an environment variable with the HOOKS_REVIEW_ prefix:
| Setting | Default | What it gates |
|---|---|---|
HOOKS_REVIEW_MIN_SESSIONS |
3 |
Distinct sessions a correction must recur across before a create candidate is eligible. |
HOOKS_REVIEW_MIN_DAYS |
2 |
Days a create candidate must span before it is eligible. |
HOOKS_REVIEW_MIN_SESSIONS_FIX |
2 |
Sessions a hook-misfire fix candidate must recur across. |
HOOKS_REVIEW_JUDGE_TIER |
medium |
LLM tier that judges each candidate (small, medium, large). |
HOOKS_REVIEW_MIN_JUDGE_CONFIDENCE |
0.6 |
Minimum judge confidence for a candidate to count. |
HOOKS_REVIEW_MAX_OPEN_PRS |
2 |
Open reviewer PRs allowed per repo at once. |
HOOKS_REVIEW_BRAIN_MAX_BUDGET_USD |
5.0 |
Spend cap on the PR-drafting brain per session. |
HOOKS_REVIEW_BRAIN_MAX_TURNS |
80 |
Turn cap on the PR-drafting brain. |
Set them in your Claude Code settings.json env block, or export them in the shell that ends the session.
Watch the queue
uvx capt-hook status shows everything the reviewer is tracking — every correction, how close each one is to a PR, and what that PR would do — grouped by lifecycle stage:
uvx capt-hook statuscaptain-hook · github.com/you/app [watching] PR slots 1/2
WATCHING building toward the bar
#3 fix sessions █░ 1/2
would fix hooks.style:nudge_1 (.claude/hooks/style.py): stop firing on its own output
#1 create sessions ██░ 2/3 days ██ 2/2
would add a hook: "block force-push to main"
ELIGIBLE a PR opens next session
#2 create ready · sessions ███ 3/3 days ██ 2/2
would add a hook: "run the test suite before every commit"
PR OPEN pull request awaiting your review
#4 create https://github.com/you/app/pull/214 · 4d open
would add a hook: "use uv instead of pip"
ACCEPTED PR merged
#5 create https://github.com/you/app/pull/208
would add a hook: "use loguru instead of print"
The same view lives under the reviewer namespace as uvx capt-hook review status. Read it top to bottom as a funnel — a correction climbs from WATCHING to a merged hook.
The header
The top line is the repo the reviewer keys candidates to, whether you are [watching] it, and the open-PR slots in use (1/2 here). At the cap, eligible candidates wait for a slot before a new PR opens. An unwatched repo says so and tells you to run uvx capt-hook review enable.
The stages
Each candidate sits in exactly one stage:
- Watching — tracked, still under the bar. The bars show judge-accepted progress toward the thresholds: distinct sessions and distinct days for a
createcandidate, a lower bar for afix. A correction has to recur and survive an LLM verdict before it counts, so a one-off aside never climbs. See the thresholds for the exact gates. - Eligible — over the bar and watched, with a free PR slot. The next session that ends drafts and opens the PR; you do nothing.
- PR open — the reviewer opened a pull request, shown with its URL and age. Review it like any other.
- Accepted / rejected / stale — a merged PR accepts the candidate, a closed PR rejects it, and a PR left open past the staleness cutoff goes stale and frees its slot.
Each row
A row reads #id kind progress, then the one-sentence summary of what its PR would do — the verdict the judge wrote when it accepted the correction. A create candidate adds a new hook; a fix candidate amends an attributed hook that misfired and adds a regression test. Pull the verbatim evidence and the full thresholds for one candidate with uvx capt-hook review show <id>.
Refresh and manual passes
status prints the last-synced PR state immediately, then refreshes open PRs against GitHub in the background and updates the frame when gh answers. Skip the network round-trip with --no-sync:
uvx capt-hook status --no-syncCorrections only land after a session ends with the reviewer watching the repo, so an empty queue usually means no session has closed yet. To backfill from a transcript you already have, run the ingest and judge passes by hand:
uvx capt-hook review scan --transcript path/to/session.jsonl
uvx capt-hook review triageFor one candidate, or to script against the queue, the narrower views print plain lines:
uvx capt-hook review list # the repo's candidates and their status
uvx capt-hook review show <id> # one candidate's row and threshold status
uvx capt-hook review threshold-check # which candidates currently cross the bar
uvx capt-hook review sync-prs # fold merged/closed PR states back into candidatesupdate moves a candidate’s status by hand — useful when you want to override the automatic flow.
Turn it off
The reviewer is opt-out per repo:
uvx capt-hook review disable # stop watching this repo (candidates stay recorded)
uvx capt-hook init --no-review # scaffold without arming the reviewerdisable stops new sessions from being reviewed; the candidates already recorded stay, so re-enabling later picks up where it left off.
Cost and privacy
The reviewer reads your transcripts locally and never uploads them — it sends only the specific correction text to the judge, and the brain runs in your own claude session. It does spend tokens: one judge call per new candidate at the configured tier, and, when a candidate is eligible, one brain session bounded by HOOKS_REVIEW_BRAIN_MAX_BUDGET_USD. The max_open_prs cap keeps it from flooding your repo with pull requests while you catch up.
For the kind of correction signal the reviewer mines — and a hook that points you back here when you give one — see Surface tracked corrections.