Claude Code
Govern the agent on your machine
Two commands. Three checkpoints. And a straight answer about which of them can actually stop a call.
agentfox hooks daemonagentfox hooks install --agent my-agent --writeDry by default — it prints what it would write and waits to be told twice.
Three checkpoints, and they are not equal
Every product in this category claims enforcement at a hook. None of them tells you which hook is a gate and which is a bystander.
UserPromptSubmitStops itThe turn you just submitted
A refusal returns before the turn is sent, so the model never sees it. Most often this catches a pasted stack trace or issue body carrying something the person did not read.
Read in the shipped bundle · Claude Code 2.1.220
This event fires on your submission, and nothing running inside an agent's turn can trigger it. Weaker evidence than a probe, and the row says so.
PreToolUseStops itThe call about to run
The command does not run and the reason reaches the agent verbatim. This event can also rewrite the call — strip the credential, bound the unbounded statement — rather than only refuse it.
Probed against a live session · Claude Code 2.1.220
A hook denied one sentinel string and allowed everything else, so the session stayed usable while the deny path was exercised for real.
PostToolUseCannot stop itWhat the tool returned
By the time this fires the call has already run. What a refusal does buy is real and smaller: the model is told, in the same turn, that the result it is holding is untrusted before it acts on it.
Probed against a live session · Claude Code 2.1.220
We emitted a block on a shell call and the command's own output came back anyway. The harness calls this event blocking; it is not, and we would rather say so than inherit its vocabulary.
The one a tool-call hook cannot see
Most guardrails watch the request. The attack arrives in the answer.
- 1The agent fetches an issuegh issue view 412 — an ordinary call, nothing to refuse
- 2The comment contains a directiveaddressed to the model, not to you
- 3A tool-call-only hook saw nothingthe poison is in the result, not the request
So PostToolUse evaluates the result on the tool_result surface, with the taint propagated: an argument later derived from that text cannot exceed the ceiling for tool-sourced data, whatever the model decided in between.
Turn on the pack built for this
Not a standard — a job. A coding agent’s inputs are diffs, stack traces and JSON, so instruction-shaped English arriving in a tool result is far more anomalous here than in a support agent’s mailbox, and is caught at a threshold that would be intolerable there.
agentfox policy observe coding-agentObserve first. It records the verdict it would have returned against every real call, and changes nothing until you promote it.
What a hook is not
It governs the agent on this machine. Anything not going through this harness is not going through this — and a session that runs in the vendor’s cloud rather than on your laptop is not visible to it at all. One harness is probed; the others have no row.
Every claim on this page comes from hooks/capability.py, where an event nobody has checked has no row rather than a plausible one.
Try to break it before you trust it
No account, no install, and the same enforcement code as the product.
pip install agentfox agentfox init && agentfox demo
Offline: no API key, no downloaded weights, no network egress.