Telling an AI agent to "check with a human when unsure" does not work — the Claude Code subagent constraint, and the delegation redesign that followed
Introduction
I have written twice before about splitting subordinate AIs (subagents) by role and building a mechanism that cuts in and stops them right before execution.
This article is the continuation of those, and at the same time their inversion. At the very core of the discipline I had assembled — the fleet, the enforcement layer and all — sat a sentence that a subordinate AI is physically unable to carry out. What follows is how I re-read the Claude Code official documentation to pin down the cause, redid the delegation design, and verified it.
The sentence at the core of the discipline
The operating rules I gave the subordinate AIs said this: “when you are unsure of a judgement, do not decide on your own — check with the owner.” I had thought it a reasonable sentence. You would say the same thing on a human team. If you are not confident about a call, do not push ahead; ask.
But a subordinate AI has not been handed the tool for asking in the first place. Below, I confirm the grounds for that one by one from the official documentation (sub-agents; measured environment Claude Code 2.1.215).
Defect 1: there is no means of asking (the main one)
The official documentation carries a list of tools removed from subagents, both unconditionally and conditionally. I quote the original as it stands.
The first filter removes these tools, even when listed in the
toolsfield:
Agent, when the subagent is at the depth limit; in a fork the tool stays listed but returns an error instead of spawningAskUserQuestionEndConversation, which can end only the main conversationEnterPlanModeExitPlanMode, unless the subagent’spermissionModeisplanScheduleWakeupTaskOutputWaitForMcpServersWorkflow
This list is not uniform. Agent carries the condition “only when the depth limit has been reached”, and ExitPlanMode carries “unless the operating mode is plan”. Against that, AskUserQuestion — the tool for putting a question to the owner — carries no such condition at all. Whatever settings a subordinate AI is running under, and however explicitly it is written into the tools allow-list, it is removed across the board.
In other words, the discipline “when unsure, check with the owner” had been written for a counterpart that holds no tool for asking. All that counterpart can do is decide for itself without checking. What I meant as a thickening of the discipline had become an instruction to act on its own judgement.
A subordinate AI becomes unsure of a judgement mid-task
│
┌──────────────────┼───────────────────┐
▼ ▼ ▼
tries to call the wants the result at once, so tries to hand work
"ask the owner" tool tries to run in a mode that further down
│ waits for a direct reply │
│ │ │
▼ ▼ ▼
⛔ removed unconditionally ⛔ refused by a safety (the depth of the
by the official spec device I built myself hierarchy is capped)
│ (see below)
│ │
└────────┬─────────┘
▼
no means available, so it "decides for itself"
│
▼
the on-the-spot judgement is written into long-term memory
│
▼ ……(in a different session)
the next subordinate AI to reach the same situation
follows it as "there is a precedent"
│
▼
it falls into the same hole again (the return edge)
Defect 2: results cannot be received
When does the result of work handed to a subordinate AI come back? The official explanation runs:
As of v2.1.198, subagents run in the background by default.
Claude runs a subagent in the foreground when it needs the result before continuing.
A background subagent’s results reach Claude as a completion notification in a later turn.
“Background” is an execution mode in which the delegating side moves on without waiting for the result; “foreground” is its opposite — waiting until the result is in before proceeding. The default is background, and the result arrives as a notification in a “later turn”.
The problem arises when the delegating side is itself a subordinate AI. Suppose an AI whose only role is dispatching throws work further down. Its report arrives in a “later turn”. But the dispatcher’s “later turn” only comes after the dispatcher itself has wrapped up and ended its turn. There is no one left at the destination to receive the notification.
the dispatcher's "current turn" ① throws work to a subordinate AI ──▶ returns a reply and ends
│
the subordinate AI ② keeps working in the background
│
③ finishes; the report is ready
│
the dispatcher's "later turn" the report was supposed to arrive here
(the destination) but the dispatcher ended its own turn back at ①
and is not even waiting
│
▼
nothing happens; it stalls
│
a human notices and wakes it ─┘
(the return edge: this shape occurred three times in practice)
A safety device I built myself was blocking the officially documented way out
There is a workaround for this structure, provided officially. If you need the result right away, run it in the foreground rather than the background. That is exactly the “Claude runs a subagent in the foreground when it needs the result before continuing” quoted above.
In practice, though, that way out was blocked. A few days earlier, to prevent a subordinate AI from going a long time without responding, I had added a safety device (a hook) of my own that cuts in immediately before execution. That hook was written to refuse the foreground-execution setting unconditionally. The very means the official documentation prescribes for “when you need the result, do this” was being blocked by my own safety device.
For weeks I had been repeatedly observing that many of the subordinate AIs I ran in parallel would stall with no completion report. But I kept using them, without confirming why they stalled and without changing how I operated. Knowing something is broken and continuing to operate it without chasing the cause was the most dangerous state of all.
Defect 3: reports cannot be verified
The dispatcher’s definition did not include the tool for checking state itself (permission to run shell commands). So when a subordinate AI reported “done”, the dispatcher had no way to corroborate it and could only pass it upward as it stood.
There was in fact an occasion when a report came back from the dispatcher saying “I had a branch created”. Measuring it gave the following.
$ git status --porcelain
(no output)
$ git branch --list <branch name>
(no output)
$ git log --oneline develop..HEAD
(no output)
No changed files, no branch created, no commit. Nowhere was there any trace corresponding to the reported “done”. Route work through a dispatcher that holds no tool for verifying reports, and this kind of empty swing gets relayed upward as it is.
Another finding — I had been putting the discipline in the wrong place
Partway through the investigation came a finding that felt like a by-product. My understanding of the range of settings a subordinate AI loads was out of date. The official documentation says:
…every level of the CLAUDE.md hierarchy the main conversation loads, including
~/.claude/CLAUDE.md
Explore and Plan are the only subagents that omit CLAUDE.md and git status. There is no frontmatter field or per-agent setting to change which agents skip them.
That is: not just the per-project settings but the top-level settings common to every project reach almost every subordinate AI automatically. The ones they do not reach are only two special operating modes specialised for investigation and planning, and no per-agent setting exists to change that.
My design notes, however, said only “what a subordinate AI loads goes as far as the per-project settings”, missing this line about the common settings reaching them too. That gap produced a mistaken premise: “the common discipline does not reach subordinate AIs, so the only option is to burn the same wording into each definition file one by one.” The result was a bloat in which the same caution had been copied into nearly ten definition files. Put in one place, it would have reached almost all of them.
Redoing the design
Since all three causes turned out to be structural defects with grounds in the official spec, I put the countermeasures in structurally as well.
Countermeasure 1: narrowing the safety device’s scope. I made it judge, from the presence or absence of an identifier included in the call information, whether the caller is the main conversation talking directly with a person or a subordinate AI, and limited the condition that refuses foreground execution to calls originating from the main conversation. The clue used for that judgement was aligned with one already in use by another notification mechanism.
guard scope test: PASS 15 / FAIL 0
That is the result after passing 4 normal cases and abnormal cases including adversarial input, confirming that the route by which a subordinate AI can choose foreground execution had been restored.
Countermeasure 2: writing the executable options at the top of every definition file. I removed the premise “you can check with the owner” itself, and wrote instead — the only options available are (a) decide yourself and execute, or (b) do not execute; report and end. Whenever a judgement is involved, always choose (b). I deleted “check” from the discipline as an option and replaced it with “if you cannot check, stop and report”.
Countermeasure 3: retiring the dispatch-only role. The roots of defects 2 and 3 both lie in “a dispatcher tier existing while unable to receive results or corroborate them”. I removed the role itself and went back to a form in which the delegating side directly directs the executor and the verifier.
reminder-correction verification: PASS 9 / FAIL 0
I checked across the settings that no description recommending the retired role remained anywhere.
Confirm first whether it can be carried out
What the three defects have in common is that at the moment I wrote the discipline, I had not confirmed whether the counterpart could physically carry it out. “Ask when unsure” is, to a counterpart with no tool for asking, synonymous with “decide for yourself”. And that solo judgement does not end there once it is recorded. The record of the judgement lands in long-term memory, and the next subordinate AI to reach the same situation follows it as an existing precedent. One drift in interpretation repeats until the structure is fixed.
The same pitfall applies to writing rules of prohibition or permission. This hook was written so as to block “the foreground-execution path”, and it swept in territory beyond its original purpose of “preventing hangs”. A rule should be written in terms of what you want to prevent; write it in terms of which route it touches, and it will kill off legitimate routes added later along with it.
One more thing. There was a period during which I watched something being broken and kept using it without confirming the cause. Whether done by a person or with an AI involved, that is the most dangerous state. A discrepancy you observe should have its identity confirmed before it is carried over into the next piece of work. Actually doing that this time is what let me fix the discipline, the safety device, and the division of roles all at the same time.
Afterwards, re-reading the official spec quoted in this article one character at a time, down to the conditional clauses, turned up one omission on my own side. The details are recorded below.