AxiomCode
Verifiable intelligence for AI software engineering. Everything starts with a formally grounded code graph.
Engineering patterns from building and running an AI agent fleet: Reusable Decision Units (RDU), falsifier-driven decisions, FACT vs INFERENCE provenance, Claude Code stop hooks, read-only cron/launch
PluginsPython · ShellGitHub @hexistemeOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Two Stop hooks for Claude Code — block challenge-triggered reversals, flag decisions handed back to you. Local-only, MIT, tests included.
Loading the full README. The saved excerpt is shown below.
Two Stop hooks for Claude Code. They catch two failures I kept hitting in my own
agent fleet and couldn't see from the transcript:
• stop_challenge_reverify.sh — an agent reverses a correct conclusion the
moment you push back, not because you found a flaw but because you asked "are
you sure?" The hook blocks a reversal whose trigger was a challenge rather than
new evidence, and asks for the evidence.
• stop_decision_ownership_check.sh — a turn reads six files, has everything
it needs, and hands the decision back to you anyway. The hook flags it.Read the full README ↗Two Stop hooks for Claude Code. They catch two failures I kept hitting in my own agent fleet and couldn't see from the transcript:
stop_challenge_reverify.sh — an agent reverses a correct conclusion the
moment you push back, not because you found a flaw but because you asked "are
you sure?" The hook blocks a reversal whose trigger was a challenge rather than
new evidence, and asks for the evidence.stop_decision_ownership_check.sh — a turn reads six files, has everything
it needs, and hands the decision back to you anyway. The hook flags it.Both are free and MIT, and both ship with their tests. Installing them adds two
Stop hooks and nothing else: they read the transcript of the turn that just
ended, append one JSON line to a ledger under your own .claude/, and stop
there. No account, no email, no signup, no network call — nothing leaves your
machine, and there is nothing here for me to collect.
The two failures are written up — measured sycophancy under a challenge and the "you decide" reflex — with the published research each one leans on and the reasoning that produced the rule. What those two posts do not carry is the firing counts from my own machine; I checked, and I'd rather say so here than let the link imply otherwise.
On my machine on 2026-09-06, across 3,498 evaluated turn-endings,
stop_challenge_reverify.sh blocked 11 reversals whose trigger was a challenge
rather than new evidence. Across 3,524, stop_decision_ownership_check.sh
flagged 32 turns that handed a decision back after reading everything needed to
make it. Eleven and thirty-two, in roughly thirty-five hundred turns each: the
moments where the agent quietly got worse and the transcript still read fine.
That is the entire offer. Two named failure modes, two files you can read in a sitting, and a ledger you can point a scanner at afterwards. Nothing here tries to be a framework.
Those rates are mine, on my workload, and they are the wrong number for deciding
whether to keep these — python3 plugin/gate-scan.py prints yours after a week
of real work. What transfers between machines is the pair of failure modes; the
frequency does not.
Five reasons to close the tab now rather than after the install:
stop_decision_ownership_check.sh decides with a fixed phrase list. On 2026-09-07
I finally measured that list against my own transcripts — 28,406 Korean and 8,446
English turn-final replies, main sessions only, because subagent reports have no
user to defer to and they were 75% of the raw English pool. The English side
matched zero of the 8,446. Its single raw hit was a sentence quoting the regex
back at itself. So the English half was not weak; it was dead, and the older
version of this paragraph told you so without knowing how badly.
It is rebuilt: 17 English alternations against 10 Korean, written against that
corpus with every surviving hit read by hand. What it catches now are real
(would you rather paste the four rows yourself?), and the largest English phrase
family in the corpus — your call / needs your sign-off, 23 hits — is
deliberately not a marker. Deferring a button you are not allowed to press is
correct behaviour; deferring the analysis is the violation, and only the second is
this hook's business.
In that measurement it fired less often in English: 0.036% of English replies against 0.278% of
Korean ones, after the tool-evidence gate. I do not know how much of that gap is
under-detection and how much is that I deflect less when I write in English, so
take the English side as improved and still unequal. The first hook was always the
portable one — its list matches are you sure, double-check, reconsider,
that's wrong from you, and you're right, I was wrong, good catch from the
agent.
A later regression check also caught contractions such as I've ... I'll
being mistaken for quotation marks and erasing a real offload between them.
That parser defect is fixed in both distributions; the dated corpus rates above
have not been remeasured after this additional fix.stop_challenge_reverify.sh fires only when the agent admits the flip. One
that changes its answer without a word of capitulation walks straight through.
That miss is deliberate — requiring the admission is what keeps the
false-positive rate low enough to run in blocking mode — but if your failure
mode is the quiet flip, this is the wrong tool.Stop
hooks. They read a turn that is already over; they never sit between the agent
and a tool call.stop_challenge_reverify.sh fired on 11 of 3,498
evaluated turn-endings (0.3%), on 32 of
3,524 (0.9%). The ordinary outcome is a one-word reason in the trace and
nothing else.claude plugin marketplace add hexisteme/hard-gate-hooks
claude plugin install hard-gate-hooks@hard-gate-hooks
Requires Claude Code v2.1.163 or newer. These hooks return
hookSpecificOutput.additionalContext, which landed in 2.1.163. On an older CLI
the block still works — that has been supported since 1.0.41 — but the
self-correction scaffold is dropped silently, which is a partial degradation
rather than a visible failure. Check with claude --version.
Don't assume both hooks are blocking. stop_decision_ownership_check.sh is wired
with MODE=shadow: it logs and blocks nothing. That is deliberate — it is
the newer of the two and I don't trust its false-positive rate on someone else's
workflow yet. To make it actually block, change MODE=shadow to MODE=block in
the plugin's hooks/hooks.json command line.
Here is the same synthetic transcript in both modes, captured from the actual hook. The block-mode JSON is an excerpt; the additional self-correction context is omitted from the image.
That hook also reads an exemption registry at
$CLAUDE_DIR/hooks/decision-ownership-exemptions.json, shaped
{"exemptions": [{"branch": "no_recent_data", "expires_on": "2026-10-05"}]}. Two
behaviors are worth knowing before you rely on it. A missing or unparseable file
exempts that branch rather than turning the hook into a blanket block — a broken
config means "not checked", not "guilty". But an entry whose expires_on has
passed does not exempt: an expired exemption means nobody re-reviewed it, which
is not a reason to keep trusting it. Each outcome lands in the fire trace as
exemption=registry_missing, exemption=active, or exemption=expired.
stop_challenge_reverify.sh is wired in blocking mode (MODE=block), which is how
I ran it for about three months. Blocking here means once per challenge/response
pair: it hashes the pair and won't re-block the same one, so it can't trap you in a
loop. It also stands down on its own when the response both names a verification
and shows a tool call after your challenge — self-reported verification alone is
not enough, and neither is a tool call with no claim attached. Where an earlier
writeup of mine calls this "notify-once", it means the same behavior.
Full disclosure on what I run right now: both hooks ran enforcing on my own machine from June until 2026-09-05. On that day I moved both to shadow to measure their false-positive rate over thirty days; I decide on 2026-10-05. So neither is currently blocking anything on my machine. The defaults above are the modes I have run, not modes I am running today.
gate-scan.py reads the two ledgers these hooks write and prints what they actually did
on your machine — turns evaluated, turns blocked, and which non-firing reason dominated.
No arguments, no network, standard library only:
python3 plugin/gate-scan.py
The hooks write that ledger themselves — one JSON line per fire to
${CLAUDE_PROJECT_DIR:-~}/.claude/hook-fire-trace.jsonl — so you can also check a hook
actually ran rather than assuming it did. If hook_trace.py can't be imported the hooks
still work, but they say so on stderr; they don't fail quietly.
It is read-only, and it never prints your project paths, session ids or prompt ids — only
counts of them. If you have just installed the hooks it says so rather than showing you an
empty table: a fresh install reports empty, a thin one reports low_sample and names how
many more rows it wants before the numbers mean anything. Exit code 3 means the Stop-hook
ledger itself is missing, which usually means the hooks are not wired. The second ledger it
reports on belongs to the PreToolUse gates, which are not in this plugin — if you only have
these two hooks, that one is supposed to be absent and the scan still exits 0.
I wrote it because the numbers I publish about my own machine are the wrong numbers for
deciding whether these hooks help you. Read the two hooks separately when you run it:
stop_decision_ownership_check.sh ships in shadow, so it records a fire and blocks nothing —
its count is what it would have stopped, not what it did. If a hook comes back with a
healthy sample of evaluated turns and a fire count of zero, that is the tool doing its job,
and the honest reading is that it isn't worth wiring up on your workload. The rates I
quoted above are mine. Yours will say something else, and that is the number worth having.
python3 -m pytest plugin/tests -q
68 pytest items, including wrappers around the Stop hooks' individual cases.
Three of them exist because an earlier version of these hooks
resolved hook_trace by guessing a path ($CLAUDE_DIR/hooks), which is wrong
under a plugin install — the import failed, the exception was swallowed, the
hook exited 0, and the traces silently vanished. That is exactly the class of
failure these hooks are for, so it is regression-tested now.
Five more exist because the scanner's low-sample guidance contradicted itself. It closed only on a missing span, not a span too short to carry a rate, so three rows two minutes apart became 2,160 rows/day and the same paragraph read "56 more rows are needed" and then "about 0 days from now". The reader it hurt most is the one this report is written for: a fresh install with one busy session was told it had effectively arrived, so the branch that says these hooks may not be worth wiring up for your workflow could not reach the person whose ledger is genuinely too quiet.
So you don't have to guess at the boundary: this plugin contains the two Stop
hooks above, gate-scan.py, hook_trace.py, and their tests. It does not contain
pretooluse-delegate-gate.py or pretooluse-model-gate.py — the two PreToolUse gates
I run — the measured thresholds inside them, or verify_install.py, which checks that
hooks named in a config are actually wired and permissioned. Those three are a separate
paid kit, and those three filenames are the whole boundary — you can hold this paragraph
next to the paid page and check that the two lists name the same files. There is no link
here yet because it isn't published yet; nothing in this plugin is time-limited or
degraded to make you want it.
So this paragraph doesn't leave you at a dead end: the next step that costs nothing and
doesn't involve me is python3 plugin/gate-scan.py, after a week of real work. It reads
your ledgers, not mine, and it will say plainly if these hooks never fired — which is the
honest reason to uninstall them.
MIT — see LICENSE.
AI-assisted authorship disclosure: these hooks, their tests, and this README were written with the assistance of Claude (Anthropic) and Codex (OpenAI). The release includes automated tests and isolated execution checks. Read the hooks before you install them — they're two shell files and one Python file.
stop_decision_ownership_check.shhooks/hooks.json — the next two
sections are the whole story on that.