How it works
A hook is a handler you register against a lifecycle event in the agent loop. The events that matter most are the action boundaries — the moments where intent becomes effect. Concretely, the loop runs like this:
- The model decides to call a tool and emits a structured request (name plus arguments).
- Before the runtime executes that call, it pauses and hands the pending request to your pre-action hook.
- The hook returns a decision: allow, deny, modify the arguments, or escalate to a human.
- The tool runs (or doesn't). The result — and any error — is passed to your post-action hook for logging, redaction, or a follow-up check.
The handler itself can be a local script, an HTTP endpoint, or an MCP tool. What makes it a hook rather than a wrapper is who owns the control flow: the handler is deterministic code that you wrote, running outside the model's reasoning, and the agent cannot talk its way past it. A prompt instruction is a suggestion the model may ignore under pressure or injection. A hook is a gate the runtime enforces. That difference — advisory versus enforced — is the whole point.
Why it matters in an agent harness
Hooks are where an agent stops being a demo and becomes an operable system. Three properties come from them directly.
Enforcement lives in code, not prose. Least-privilege and permission boundaries only hold if something outside the model checks them. A pre-action hook is the natural place to deny a shell command that touches production, or to reject a tool call whose arguments fall outside an allowlist. The model's cooperation is not required.
Reversibility gets cheap. A post-action hook that records every mutating call — with its arguments and result — gives you the ledger a rollback or checkpoint needs. You can't undo what you never observed. Hooks are the observation point that makes containment possible after the fact.
Failure gets contained at the boundary. Because the hook sees the action before it fires, it can shrink blast radius on the way in: rewrite a --force flag out of a command, cap a batch size, or route a risky call to an approval gate. Containment at the action boundary beats cleanup after the effect.
The cost is real: every hook adds latency and a place where your own code can be wrong. A hook that throws is now part of your failure surface. Treat handlers as production code, not glue.
Agent hooks vs. guardrails
These are routinely conflated, and the conflation produces bad designs. A hook is the insertion point; a guardrail is the policy that runs there. You need both, but keep them separate.
| Agent hooks | Guardrails | |
|---|---|---|
| What it is | A mechanism — the point where you intercept an action | A rule — the decision applied at that point |
| Owned by | The harness / runtime | The policy layer |
| Lifecycle | Fires per action (pre/post) | Evaluated when invoked |
| Failure mode if missing | No interception point exists | Interception happens but decides nothing |
The practical consequence: if your only guardrails live in the system prompt, you have policy with no enforced insertion point. Hooks give the policy a place to run where the model can't route around it.
The Rifty take
We optimize for enforced control at the action boundary over trusting a model to police itself. A hook is the smallest, most durable unit of that discipline: deterministic code at the exact seam where intent becomes effect. We accept the latency and the extra code to maintain, because the alternative — asking the model nicely in a prompt — is not a boundary, it's a hope. Put the enforcement where the action is, and keep it dumb, fast, and yours.
Implementation checks
- Hook the mutating actions first. Reads can wait; every write, delete, deploy, and external send should pass a pre-action hook before anything else is instrumented.
- Make the deny path total. A hook that only logs is observability, not control. Decide explicitly what a deny returns to the agent so the loop degrades sanely instead of retrying blindly.
- Keep handlers deterministic and side-effect-light. A hook that itself calls an LLM or a flaky endpoint has moved your non-determinism into the control plane. Fail closed on hook errors for high-risk actions.
- Record arguments and results, not just events. Reversibility needs the full call, not a count. Redact secrets in the post-action hook so the ledger is safe to keep.
- Test hooks against adversarial arguments. Assume the model, under prompt injection, will try to produce the argument shape that slips past your check. The hook is only as strong as its worst-case input handling.
Frequently asked questions
How are agent hooks different from just writing rules in the system prompt?
A prompt rule is advisory — the model can ignore it under pressure or prompt injection. A hook is enforced by the runtime as deterministic code outside the model's reasoning. If a boundary must hold, it belongs in a hook, not in prose the agent is free to reinterpret.
Where in the agent loop should hooks fire?
At the action boundaries: a pre-action hook before a tool call executes, and a post-action hook after its result returns. Pre-action is where you allow, deny, or modify; post-action is where you log, redact, and run follow-up checks. Instrument mutating actions before read-only ones.
Can an agent hook block or modify an action, or only observe it?
Both, depending on where it fires. A pre-action hook can deny a call outright, rewrite its arguments, or escalate to a human before anything runs. A post-action hook mainly observes and logs. A hook that only observes is instrumentation, not control.
What are the main risks of adding hooks?
Hooks add latency and become part of your failure surface — a handler that throws can stall the loop. They also invite non-determinism if the handler itself calls an LLM or a flaky service. Keep hooks fast, deterministic, and fail-closed for high-risk actions.
Do agent hooks replace guardrails or approval gates?
No. Hooks are the mechanism; guardrails and approval gates are policies that run inside them. A hook gives a guardrail an enforced place to execute, and can route a risky action to an approval gate. You implement the others through hooks, not instead of them.