Skip to content
Agentic Control Plane

Interactive vs. autonomous agents: the empty-chair test

David Crowe David Crowe · · 6 min read
engineering agents policy autonomy
Share X HN LinkedIn

Run agents? ACP lets you see, control, and price every tool call they make — free on-device install for Claude Code, Cursor, Codex, and OpenClaw, nothing leaves your machine:

curl -sf https://agenticcontrolplane.com/install.sh | bash -s -- --local

Getting started →  ·  or use the free cloud console →  ·  free for individuals

There’s a sentence that keeps showing up, in slightly different words, whenever builders talk about letting an agent run without them: the whole point of handing off is that I stop watching.

That sentence is the actual boundary in agent control. Not model capability, not framework, not how many tools the agent has. The line that changes everything is whether a human is present at decision time. Most teams know this intuitively — and then write one policy and run it on both sides of the line.

The problem is that control primitives don’t mean the same thing on both sides. Here is a test we use: take each control you rely on and ask what it does when the chair is empty.

The ask

Attended, an approval prompt is a genuine question. A human reads it, brings context the policy doesn’t have, answers, and the answer is itself a record. The failure mode on this side is well known — approval fatigue. A copilot that asks about everything trains you to say yes to everything, and then the asks protect nothing. The design pressure is to ask rarely, so each ask means something.

Unattended, the same prompt is not a question. It’s whatever your stack resolves an unanswered question to. There are only three possibilities, and two of them are bad:

  • Auto-approve — the ask silently becomes a yes. Your “human in the loop” control is now a logging statement.
  • Hang — the agent stops mid-job and waits for a person who isn’t coming. For an always-on worker this is an outage with extra steps.
  • Deny — the call is refused, the agent adapts or the job fails cleanly, and the request lands somewhere a human can review it later.

Deny is the only honest resolution: an unattended agent cannot self-approve. The harnesses are starting to converge on this. DeepSeek Harness ships it natively — in a headless composition with no approval service mounted, dsh resolves ask to deny by design. Where a harness can’t express an ask at all, the mapping should be the same: our Codex integration turns ask into a deny plus an approval link on the dashboard, so the human answers on their own schedule instead of the agent’s.

The empty-chair question for your stack: when an approval times out, what actually happens? If you don’t know, the answer is probably one of the two bad ones.

The failure posture

Attended, failing open is a defensible availability choice. If the policy check itself can’t run — network blip, gateway slow — blocking every tool call bricks the session of a person who is sitting right there and can see the warning. Fail open, loudly, with the lapse recorded, and the human notices within seconds.

Unattended, “loudly” has no audience. An always-on agent that fails open during a control-plane outage runs exactly as ungoverned as an agent with no controls at all, for as long as the outage lasts, with nobody to see the warning banner. The same posture that was reasonable at the keyboard is unbounded in the empty chair. That’s why our dsh plugin defaults differ by tier: interactive sessions fail open with a loud ungoverned warning and a lapse log; unattended tiers fail closed. Policy denies hold either way.

This is the least intuitive item on the list, because the right answer flips. Teams pick one failure posture and feel consistent. The consistent choice is the wrong one on one side of the line.

The audit trail

Attended, the audit log is a convenience — a searchable record of things you mostly watched happen.

Unattended, the audit log is the only witness. Nobody saw the run. The session transcript is the agent’s own account of itself, written by the same model whose behavior is in question. If the record isn’t written by a layer the agent routes through — per call, decision included, before and after execution — then for unattended operation you don’t have an audit trail; you have a diary.

The empty-chair question: could you reconstruct what the agent did last night, from evidence the agent didn’t author?

The stopping point

Attended, the stopping point is you. You get bored, suspicious, or done, and you hit Ctrl-C. Every interactive session has a natural end because a human’s attention is finite.

Unattended, there is no natural end. A loop with no human in it will loop. Rate limits and budgets stop being billing hygiene and become the actual brake — the thing that bounds a retry storm, a runaway delegation fan-out, or a scheduled job that starts scheduling itself. If your unattended agents have no per-agent rate and spend limits, their stopping point is your credit card’s.

The self-modification set

This one barely exists on the attended side, which is why it gets missed. A copilot that edits its own config does it in front of you.

An unattended agent that can rewrite its own memory, edit its own skills, change its own schedule, or mint its own delegations is an agent whose next-week behavior you didn’t write. Each of those writes is individually mundane — that’s what makes the set dangerous. We covered the concrete policy in the archetype recommendations: for the unattended worker, the self-modification set is a flat deny. One production workspace denies its always-on agent’s memory writes hundreds of times a week, and the agent keeps doing its job. The denials aren’t friction; they’re the fence holding, in writing.

And when an agent spawns others — attended or not — the subagents should inherit the fences, not the trust. A delegation is not an exemption.

One policy set, two resolutions

The wrong conclusion from all this is “maintain two policies.” Two policies drift, and the unattended one rots because nobody works under it day to day.

The workable shape is one policy set where every rule resolves per tier. Each governed call in ACP carries a tier — interactive, subagent, background, api — attached by the integration, not asserted by the agent. The same rule then lands differently on each side of the line: pause on file deletes is an approval prompt for the interactive tier and a clean deny for the background tier, because that’s what a pause honestly is when nobody can answer it. Failure posture, rate limits, and the self-modification set hang off the same split.

That’s the whole trick. You don’t write different rules for autonomous agents. You write rules whose unattended resolution you chose on purpose, instead of inheriting whatever the timeout does.

The test, compressed

Before you hand an agent a job you won’t watch:

  1. Every ask resolves. No rule whose unattended outcome is “wait for a human.” Ask becomes deny-and-surface.
  2. The failure posture flips. Open and loud at the keyboard; closed in the empty chair.
  3. The record is independent. Written by the layer the calls route through, not by the agent.
  4. The stopping point is explicit. Rate and budget limits per agent, because Ctrl-C left the building.
  5. The agent can’t edit its future self. Memory, skills, schedule, delegation — denied unless a human is in the loop.

If the safety only holds while you’re watching, you haven’t handed off. You’ve just stopped looking.

Share X HN LinkedIn
Get the next data drop
What agents actually cost, new tool-surface captures, and the occasional incident post-mortem — sent when we publish something worth your inbox, not on a schedule. Unsubscribe anytime.
Share: Twitter LinkedIn
Related posts

← back to blog