Surface tracked corrections
When a session ends on a durable correction in the user’s own words, point them at
capt-hook statusso the session reviewer can mine it into a hook PR.
You keep correcting Claude on the same rule — “never force-push”, “use uv, not pip” — and writing the hook by hand is friction you skip in the moment. The session reviewer already mines those corrections into hook PRs. The nudge below scores the last few transcript messages for that correction shape and, when one clears the threshold, points you at uvx capt-hook status so you can watch the lifecycle instead of hand-writing the hook.
"""Nudge toward the corrections lifecycle when a session ends on a durable correction."""
from __future__ import annotations
import re
from captain_hook import Allow, Event, Input, Signal, Signals, T, Warn, nudge
CORRECTION_SIGNALS = Signals(
patterns=[
Signal(pattern=r"\bnever\b", weight=2, flags=re.IGNORECASE),
Signal(pattern=r"\b(always|from now on)\b", weight=2, flags=re.IGNORECASE),
Signal(pattern=r"\b(use|prefer)\b.+\b(not|instead of)\b", weight=2, flags=re.IGNORECASE),
Signal(pattern=r"\b(stop|don'?t)\b", weight=1, flags=re.IGNORECASE),
Signal(pattern=r"\b(no,|actually,|that'?s wrong|i told you)\b", weight=1, flags=re.IGNORECASE),
],
threshold=3,
window=6,
origin="any",
)
nudge(
"You just took a durable correction from the user. You don't have to hand-write the hook: "
"captain-hook's session reviewer is already mining corrections like this one. Run "
"`uvx capt-hook status` to watch it climb toward a hook pull request.",
signals=CORRECTION_SIGNALS,
events=Event.Stop,
max_fires=1,
tests={
Input(transcript=[T.user("No — never force-push to main, always open a pull request.")]): Warn(
pattern="capt-hook status"
),
Input(transcript=[T.user("Looks good to me, ship it.")]): Allow(),
},
)What it catches
"No — never force-push to main, always open a pull request." # stacks "No —", "never", and "always" past threshold=3What it allows
"Looks good to me, ship it." # plain approval, no correction signalsThe catch / allow split mirrors the hook inline tests, so it stays true as the hook evolves.
Run it yourself
uvx capt-hook --hooks docs/examples test