I run about a dozen Claude Code projects on one laptop. Each owns its own domain, and they open sessions against each other to ask questions they aren't allowed to answer themselves. The rules governing that are a separate piece. This one is the plumbing: six things that broke while making those rules actually run, and what each one cost to diagnose.
Everything below was observed on Claude Code builds 2.1.234 through 2.1.241 in August 2026. Two items have since been re-verified on 2.1.252 and are marked; the rest have not been re-tested, so read them as dated observations rather than permanent properties. Where a fix is a workaround rather than a cure, I say so.
Two different stalls that look identical
A session that tries to touch anything outside its own working tree raises a permission dialog. Unattended, nobody answers it. The session hangs, and a hung session is visually indistinguishable from one that is thinking hard.
Separately, shell commands the permission system cannot statically verify (a loop with variable expansion, say) prompt every time, with the same silent hang.
These look like one failure and need different cures. Pre-approving read-only tools at launch and forbidding shell use in the request itself, sub-agents included, cures the shell class. It does not touch the cross-tree class: pre-approving the Read tool authorises the tool, not paths outside the session's tree. A session launched under that same recipe still blocked forever when asked to read one file in another project.
Only confinement cures the second one. Give the receiving session nothing that requires leaving its own project, and there is no dialog to hang on.
One consolation, and it is a real one: a stalled session is recoverable. Attach to it from a terminal and the pending dialog renders. Either answer resolves it, and the session then drains every message that queued while it was blocked. Nothing is lost.
A trust prompt that fires before your message arrives
A project whose MCP servers nobody has approved yet blocks at startup, before it receives anything at all. Your message never lands, and nothing tells you that. From the sending side it looks exactly like a session that is ignoring you.
A human at a terminal can clear it one session at a time. The only fix that scales is a standing trust decision for that server.
The receiving model refusing on safety grounds
One request came back refused because several terms in it read as security-related in combination. The receiving agent classified the request and declined to answer it.
Re-sending with that section removed worked. That is the one cure I measured; rephrasing in place seems plausible and I did not try it.
Worth naming because it is a structural property rather than a bug: when the receiver is a model, the content of a request can prevent its delivery. No transport-layer guarantee survives that.
The silent stall that looks like working
A background session with no usage credits left accepts your message, prints it, and dies. It goes idle without replying, which is visually identical to still thinking.
The cause is almost never a real budget problem. A background session does not inherit the model of the session that launched it. It takes the default from user settings. An interactive session running one model therefore spawns background sessions on a different one, and those die on the second model's quota while the first sits untouched.
Passing the model explicitly at launch fixes it. Before that, read the session's log rather than inferring from its silence: idle-with-no-reply and still-working are the same picture from outside, and only the log distinguishes them.
An addressing bug, and how I isolated it
Background sessions print an id at launch. After processing their first task they rename themselves from that task's subject, and the launch id then stops resolving for messaging, reporting the session as unreachable, while every other surface still accepts it: logs, stop, and the id field in the JSON agent listing.
I isolated it with a negative control. A session that blocked before producing any output never renamed itself, and messaging its launch id worked. I then unblocked that same session, watched it rename, and messaged the identical address again: same session, same process, same build. Rejected. The rename was the only variable.
That is filed as anthropics/claude-code#89946. An issue's status is live state owned by someone else, so check the link rather than trusting a sentence I wrote weeks ago.
The workaround is small: re-discover a session by its current name before any follow-up message.
One sign the addressing layer is moving. On a newer build, a bad address now returns a disambiguating error naming the candidate sessions instead of a bare "not reachable." That is a different failure from the rename bug, but it shows the surface is being worked on.
Re-verified on 2.1.252: cross-session delivery and typed message exchange still work as described.
The one that isn't a bug: a read-only transport can carry a ruling, but not work
The recipe above deliberately strips the receiving session down to read-only tools. That confinement is exactly what makes unattended delivery safe: nothing can prompt, so nothing can hang.
The cost surfaced on the first real cross-tree job: a project rename whose final stage required edits a confined background session had no way to make. The job finished only because a human instructed a different session to run shell commands inside the other tree. That was outside the protocol, on explicit instruction, and recorded in our own log with the sentence "it worked, and it is not a precedent."
A fair summary of the field state: the mechanics reliably move questions and answers. They have not yet executed a real cross-tree modification end to end.
The rule that came out of this responds to it rather than solving it. Constrain what a session may touch, not which tools it holds. Launching a head stripped of the tools it needs and then asking it a question only those tools could answer is the mistake underneath the whole class. Pre-approve what the work requires, bound the scope, and let it refuse if it still cannot answer.
Whether a full cross-tree modification runs cleanly under that rule is untested.
Re-verified on 2.1.252: a session rooted in a directory that contains other projects' trees still reads all of them with no prompt at all.
What the list is for
Two of these six are bugs. Two are consequences of running models rather than services on the receiving end. Two are properties of the permission model that no configuration removes. Only the first pair will be fixed by someone else.
That distribution is the useful part. When you wire independent agent projects together, the failures you should budget for are not the ones in the transport layer. They are the ones where a session's silence has three possible meanings and the interface shows you the same thing for all three. Most of my diagnosis time went to telling those apart, not to fixing them once told.
A protocol write-up with no failures in it is a design document wearing field-report clothes.
The rules these sessions were carrying, and who answers to whom, are set out in the companion piece.
Top comments (0)