agent-org · part 1

The Agent Org Chart That Couldn't Dispatch Itself

I spent a few days, and it felt like a lot longer, building what I thought would be an autonomous AI development team. Sr SDM at the top. Team Lead in the middle. Specialists below: SWE, QA, Reviewer, Designer, DevOps. A proper hierarchy, and it did look great in a diagram.

Why

The reason was boring. I run several projects at once and I am the bottleneck on all of them, partly for decisions and mostly for remembering where I left off. Twenty minutes of every session went to reconstructing state before I could get anything done. I figured if I drew the org properly, the structure would hold that for me.


What

The shape was simple enough. I hand a project spec to the Sr SDM agent. It manages two teams, breaks the work down, and decides what can run in parallel. The teams execute. Specialists report up through their lead, the lead escalates to the SDM, and I read whatever comes out of the top.

How

I did not want to write the personas out of my own assumptions, so I ran a research spike first and set Opus loose on GitHub, documentation and technical articles to find multi-agent patterns people had actually used. Two days of collecting, with citations I could check myself. Then I wrote the personas: tool permissions per role, rules for what each one keeps in context, anti-hallucination guardrails in every system prompt.

What I built

Everything is a Claude Code agent defined as a custom persona, with its own system prompt, tool permissions and role constraints. The Sr SDM dispatches the Team Lead. The Team Lead dispatches specialists. The specialists do the work, write completion signals into a shared file, and the Lead checks those before escalating anything back up.

There were guardrails too. A loop_gate.sh hook that blocks doom-loop retries, a gate.sh that catches force-push attempts, and permission constraints on each persona so that the SWE cannot touch .claude/ files and the designer cannot run shell commands at all. I put real work into this part.

The first real cycle shipped. Night Focus Hardening for MonoHome, PR #3, merged. I declared Phase 1 done and felt good about it for about a day, until I went back and read the retrospective I had written.


The failure I almost glossed over

From the Phase 1 notes:

F1 (HIGH): Main session acted as orchestrator throughout the entire cycle — every dispatch, stall detection, revert, and commit was done by the main session, not by team-a-lead.

Every specialist dispatch, every stall I noticed, every worktree I checked: all of it was me, in the main session, pretending to be the Sr SDM while actually being the entire org. The chart was not running anything. I was, and the agents were tools I called by hand. What I had built was a fairly elaborate way of getting Claude to do things that I then went and did myself.


The platform wall

There is a technical reason for it. When you define a custom agent persona in Claude Code, the Agent tool, which is the thing that lets a session spawn a subagent, is not available once that persona is itself running as a subagent. Subagents cannot spawn subagents. Team-a-lead tried anyway. It logged "Agent tool unavailable for subagent dispatch" and stopped there.

So the chart I had drawn, main → lead → specialists, could not run itself past the first dispatch. The main session is always the structural orchestrator. That is platform architecture rather than a configuration mistake, and no amount of better prompting gets around it.

I wrote a doc I called “Autonomy Ground Truth.” The bottom line:

True autonomy is structurally impossible today because Claude Code does not support nested subagent spawning. The org chart was a social model, not a technical one.

I sat with that for a day.


What I tried instead

The constraint applies to in-context agent hierarchies. An agent running as a subagent inside Claude Code cannot spawn further subagents. But a process launched from a shell command with claude -p is an independent OS process, and nothing stops that process from launching another claude -p of its own. It is a completely different mechanism.

So I built a spike, about 250 lines of shell script:

  • A file-based task queue (queue/pending/, queue/claimed/, queue/done/)
  • A stateless dispatcher that ticks every 8 seconds, claims pending tasks, and launches claude -p workers in isolated git worktrees
  • Proof verification, so that a task is only marked done when a known token turns up in a known file, rather than on exit code alone
# dispatcher.sh core dispatch loop
for tid_file in queue/pending/*.json; do
  tid=$(basename "$tid_file" .json)
  mv "$tid_file" "queue/claimed/$tid.json"   # atomic claim

  prompt=$(jq -r .prompt "queue/claimed/$tid.json")
  git worktree add "worktrees/$tid" -b "$tid"

  claude -p "$prompt" \
    --output-format json \
    --permission-mode acceptEdits \
    --allowedTools Write,Read,Edit \
    --max-turns 6 \
    > "workers/$tid.result.json" 2>"workers/$tid.log" &

  echo $! > "workers/$tid.pid"
done

Spike v1 ran end to end in 16 seconds. One task, one worker, AUTONOMY_OK written to the proof file, session ID captured, and it cost 11 cents. Then I made it two-tier.


Spike v2: the decisive one

Spike v2 ran May 18, 2026. Three processes:

  1. SDM: the dispatcher. Stateless, holding zero LLM context between ticks.
  2. Lead (fe5a881b): a claude -p process told to get slugify() implemented without writing any of the code itself, and to delegate that to a SWE subprocess over Bash.
  3. SWE (21e2975a): a second claude -p process, spawned by the Lead.
# Lead's prompt (excerpt)
You must NOT write any code yourself.
Your only job: spawn a SWE subprocess via Bash and delegate.
Run: claude -p "implement slugify() in src/textutil.py..." \
  --allowedTools Write,Read,Edit --max-turns 4 \
  > /tmp/swe.result.json
Capture the session ID from the result and write it to sessions/$TASK_ID.swe.session

The dispatcher only accepted the task as done when:

  • lead_session and swe_session were both present and distinct
  • verify_cmd returned the expected output
  • Signal file contained tests=PASS
{
  "tier_chain": ["sdm", "lead", "swe"],
  "distinct_processes": 2,
  "verified": true,
  "lead_cost": "$0.155"
}

The whole thing took 72 seconds and produced a real slugify implementation with three tests passing, including Unicode normalization. Nobody touched it after the run script started.

The doc that had said “structurally blocked” now says “PROVEN PATH.”


What this actually proves

The constraint is real, and as of May 2026 there is no way around it from inside Claude Code. Subagents cannot spawn subagents, so if you are building an autonomous system on top of it and your architecture depends on in-context nesting, you are going to hit the same wall I did.

What worked was treating autonomy as a process-tree problem instead of an agent-nesting one. Every tier is a top-level OS process, they coordinate through files, the orchestrator holds nothing between ticks, and no context leaks from one tier into another.

What this does not prove yet:

  • A real git branch → PR → CI → merge cycle (the spike worked in an isolated worktree)
  • Multi-task concurrency
  • Resume-on-crash under real conditions
  • Cost at fan-out scale

Those are spike v3 and beyond. The architecture question, at least, is answered.


Writing the honest doc was the useful part

Writing the Autonomy Ground Truth doc, the one that said plainly that we had not proved anything yet, was worth more than a week of implementation. Having a single document that said exactly where things stood, with evidence and without spin, meant the next session started from reality instead of from optimism.

I have started treating honest status docs the way I treat tests. If I am reluctant to write something down, that reluctance is usually the bug.


Where this lands

The org chart did not fail because the personas were bad. It failed because I drew a management structure and assumed the platform would run it for me. It will not. There is one orchestrator, there is no nesting, and everything underneath is tooling.

What survived is smaller and works better: three OS processes coordinating through files, verified by proof tokens rather than by trust, and that version dispatched itself. Autonomy was an operating systems problem wearing an org chart costume the whole time.

I still keep the diagram. It is a good diagram, it just describes people rather than processes, and the machine only runs one of those.

Written May 2026. Platform limits move, and this one did. Part 2 picks up what changed and what it cost me to find out.