blog · july 2026
Your agent has hands. It needs reflexes.
A coding agent will, on a good day, refactor a module, run your tests, and open a clean PR. On a bad day the same agent will git push --force to main, rm -rf a directory it misread, or cat .envinto its context window on the way to “debugging” something. The capability that makes it useful is the capability that makes it dangerous. There is no version of an agent that acts on your machine where this isn’t true.
So every serious agent grew a hook system: a place to intercept what the agent is about to do and say no, or ask first, or change it. Claude Code has PreToolUse. Cursor has beforeShellExecution. Copilot CLI, Gemini CLI, Windsurf, OpenCode — each has its own. Good. The problem is that none of them are the same, and none of them talk to each other.
The wall you hit on the second agent
Write a hook that blocks force-pushes to main in Claude Code and you’ve solved it — in Claude Code. Open Cursor and that protection does not exist. Different format, different event names, different payload shape, different way of saying “deny.” So you re-implement it. Then Gemini ships and you re-implement it again, against a third API, and you find out halfway through that Gemini has no native way to say “ask the human” — only allow or block.
Most people don’t re-implement it three times. They write it once, for their main agent, and accept that the guardrail evaporates the moment they switch tools. Or they skip it and write it down instead — a line in AGENTS.md or .cursorrulesthat says “don’t force-push to main.” But a rules file is advice. It’s a prompt. The model can read it, agree with it, and force-push anyway, because nothing ran between the decision and the command. Instructions are not enforcement.
Three layers, and only one is missing
Step back and the tooling around coding agents sorts into three layers:
- Instructions — what the agent should do. Prose. AGENTS.md, skills files. This is standardizing.
- Capabilities — what the agent cando. The outbound tools it can call. MCP owns this, and it’s standardizing fast.
- The lifecycle layer — what actually happens the instant the agent acts. Intercept the tool call, decide, and let it through, block it, change it, or ask.
The first two layers have a name and a shared shape that any harness can target. The third one doesn’t. Every agent ships its own version and everyone hand-rolls adapters to it. That’s the gap. MCP gives your agent hands. Nothing gives it reflexes.
What a reflex is
A reflex is deterministic logic that runs the moment an agent is about to act, and returns one of four verdicts: pass, deny, ask, or modify. That’s the whole model. It’s small on purpose.
// .reflex/no-force-push.mjs
export default {
name: "no-force-push",
onToolCall(ctx) {
if (ctx.tool === "Bash" && /git\s+push\b.*--force\b/.test(ctx.command ?? ""))
return { action: "deny", reason: "no force-push — open a PR instead" };
return { action: "pass" };
},
};The important part is what you don’tsee. You didn’t parse Claude Code’s payload, or Cursor’s, or Gemini’s. ctx is a canonical context — normalized tool name, a shell-aware-parsed command (so cd build && git push --forceis caught, which naive substring matching misses), paths, cwd, which agent. agentreflex sits under every agent as a single dispatcher; each agent calls it through its own native hook, the dispatcher normalizes the event, runs your reflexes, and translates the verdict back into whatever that agent expects. Where an agent can’t express a verdict — Gemini and “ask” — a capability descriptor on the adapter degrades it gracefully instead of silently dropping it.
Write the reflex once. It fires everywhere.
A reflex is a file, not a package
The other deliberate choice: a reflex is a folder with a manifest, not an npm package. It lives in .reflex/ in your repo. You own it, you edit it, you commit it alongside the code it protects. Editing it is instantly live — no build, no publish, no version bump. The contract is JSON over stdin/stdout, so a reflex can be TypeScript, JavaScript, Python, or a shell script; the language is yours.
That’s the shadcn lesson applied here: the unit you share is the code, not a dependency you pull in and can’t see. Sharing is opt-in and rises in friction only when you want it to — agentreflex add no-secrets from the commons, add github:you/repo, add ./path, add https://…. The official registry is the best-known URL, not the only one. And because the reflexes you rely on are committed, every collaborator inherits them on agentreflex install, the way they inherit .editorconfig.
The part that has to be true: trust
A tool that runs code on every agent action has to be honest about that. Reflexes are code, and code you don’t read is code you shouldn’t run. So: add shows you the source before anything is wired in. Reflexes declare the capabilities they use. And the dispatcher fails open — if a reflex is slow, throws, or the runtime itself breaks, the agent proceeds. agentreflex will never block or crash your agent because of its own bug. A safety layer that takes down your workflow when itfails isn’t a safety layer.
And to be clear about what it is and isn’t: this is seatbelts, not a sandbox. A reflex runs before the tool call and parses commands properly, but a determined model or user can route around any single rule. It’s built to catch the agent doing the thing you’d have flinched at — the 99% case — not to contain an adversary. Anyone who tells you a hook layer is a security boundary is selling something.
What ships today
MIT, v0.x. Six enforcing adapters, verified against live agents, and about ten official reflexes to start: protective ones (no-secrets, no-rm-rf, ask-on-prod, stay-in-repo, no-curl-bash) and proactive ones (recover, which snapshots files before the agent edits them so any change is undoable; prefer-rg; conventional-commits), plus abide, where you write your human↔agent working agreement in plain language and it’s enforced everywhere.
Harness APIs churn; keeping the adapters current is the job — and the moat. The longer arc is a language-neutral spec, so any harness can implement reflex support and any language can author one, and a registry so the useful reflexes find the next person who needs them. A library earns stars. A shared layer everyone can build on is the thing worth trying for.
If you use more than one coding agent, try it on a repo:
npx agentreflex init
npx agentreflex add no-secretsThen tell me what reflex you’d write first — or where it breaks.