The gated agent can't restart its own gate: four lockouts in one session

August 26, 2026

agent-supervisor runs as a daemon. A PreToolUse hook checks with it before Claude Code touches anything, and if the daemon is unreachable the hook fails closed and blocks the tool.

Fail-closed is the right posture for a security gate. I’d argue for it again.

It also produced a chicken-and-egg that bit me four times in one session.

The loop

The daemon goes down. Claude Code notices, and tries to restart it. The restart is a Bash call. Bash is one of the supervised tools. The hook checks with the daemon, finds it unreachable, and denies the call.

So the agent is locked out of fixing its own lockout.

Recovery came from outside the gated shell every time. Either I started the daemon by hand, or I set AGENT_SUPERVISOR_DISABLE=1 in the session environment. Four times, same shape, same fix.

That isn’t a bug in any one place. It’s the structural consequence of a fail-closed gate plus self-service recovery.

Two things made it worse

The auto-heal only runs in one deployment mode. Spawn-on-demand — the hook booting the daemon itself — requires CLAUDE_PLUGIN_ROOT, which is only set for the installed plugin. A dev-source-tree session running in the repo has none. So it silently never auto-spawns and the operator has to start it by hand.

I’d been carrying a mental model of “it heals itself.” That was true for about half my sessions. The other half failed quietly, and I didn’t know which half I was in.

The spawn swallows its own output. The hook spawns with nohup … >/dev/null 2>&1, and the dev-mode bail is a bare return 1. A failed or refused auto-start leaves no log. You can tell that it didn’t come back. Never why.

What I changed

The gate’s availability turned out to be load-bearing in a way I hadn’t priced. Everything it gates stops when it’s down, so its uptime is a hard requirement rather than a nice-to-have. That means running it as a managed service that survives terminal-close, crashes and reboots. Not as a child of the session it’s protecting, and not as npm run dev in a babysit terminal, which is what I’d actually been doing.

The out-of-band recovery affordance needs to exist and be written down, because the in-band one is blocked exactly when you need it.

And the auto-recovery path shouldn’t be silent. A gate that can’t tell you why it didn’t come back is one you’ll fight at the worst possible moment.

I get that fail-closed makes the uptime problem sharper, and I’m not proposing fail-open. That trade is already settled — a gate that waves things through when it’s confused isn’t a gate. The point is narrower: if you choose fail-closed, you’ve made the gate infrastructure, and you have to fund it like infrastructure.

Generalizes

Any fail-closed checkpoint in front of an actor, where the actor’s own tools are how you’d normally restart the checkpoint. A network proxy the app must reach to restart the proxy. An auth gateway whose admin console sits behind the gateway. A CI gate that blocks the very commit that would fix the CI gate.

The structural fix is the same every time. The gate’s lifecycle is owned by something outside the gated path, and its failure to recover is observable.

SOs

SOs — standing orders you can lift and prime your own agent with. Paste them into a session for a one-time dose, or commit them to your CLAUDE.md / AGENTS.md and they stay in force.

STANDING ORDERS — Fail-closed gate lifecycle
  Source: "The gated agent can't restart its own gate" — bensimon.dev

  1. Never propose that a gated process restart its own gate. The restart
     command runs through the gate. Recovery must come from outside the
     gated context — a process manager, or a human at the session level.

  2. When a fail-closed gate is in play, treat its uptime as a hard
     requirement and say so. Recommend a managed service that survives
     terminal-close and reboot, not a foreground dev process.

  3. Never silence an auto-recovery path. Log the bail reason and the
     spawn's stderr, so "why didn't it come back" is answerable.

  4. Verify which deployment mode is actually running before relying on
     any auto-heal. The recovery you believe in may be inactive in this
     configuration.

  5. Document the out-of-band escape hatch alongside the gate itself. The
     in-band one is blocked exactly when it is needed.