Claude Code categorically forbids subagents from spawning other subagents (code.claude.com/docs/en/sub-agents and the Agent SDK subagents page). The `or.1` architecture (and `pr.1` that ran on top of it) presumed a named-exception for `ailang-implement- orchestrator` to dispatch implementer / spec-reviewer / quality- reviewer / tester per task. That exception never existed at the platform level; the `Agent` tool was silently dropped from the orchestrator-agent's tool set at dispatch time. Architecture revised, doc-only: - Per-task phases (implementer → spec-compliance check → quality check) now run as sequential role-switches in the orchestrator- agent's own context, not as nested subagents. - The four role-files (implementer / spec-reviewer / quality- reviewer / tester) become phase reference files the orchestrator-agent consults at role-switch boundaries. - Boss-context offload preserved; fresh-per-phase context given up (the property that drove or.1's nested-dispatch design is not buildable in Claude Code). Files touched: - skills/implement/agents/ailang-implement-orchestrator.md (frontmatter, Iron Law, Phase 2/3 rewrite, rationalisations, red flags) - skills/implement/SKILL.md (frontmatter, Iron Law, sub-status vocabulary note, cross-references) - skills/README.md (Conventions: no more named exception; agent roster: role-files recast as phase references) - docs/journals/INDEX.md (or.2 entry appended) - docs/journals/2026-05-11-iter-or.2.md (new — full rationale) - docs/roadmap.md (P1 tool-wiring item removed; resolved as categorically-not-fixable) - docs/WhatsNew.md (user-facing correction entry appended) No code changes; no bench impact; CLAUDE.md untouched (no stale references to fix there).
8.7 KiB
iter or.2 — orchestrator-agent design correction
Date: 2026-05-11 Branch: none (trivial-mechanical carve-out — doc-only revision, single commit on main) Status: DONE Tasks completed: N/A (doc revision, not a plan-driven iter)
Summary
This entry corrects a factual error in the or.1 architecture that
surfaced during the first real dispatch (pr.1, same day). The
revision lands as one direct-on-main commit because the change is
doc-only: no code, no tests, no behaviour shift in any compiler
crate. The Iron-Law mini-fix from earlier today (origin/main →
main) is preserved unchanged — that fix remains correct.
What was wrong
or.1 and pr.1 shipped the ailang-implement-orchestrator agent
with frontmatter tools: Read, Edit, Write, Bash, Glob, Grep, Agent
and an architecture that depended on the orchestrator-agent
spawning further subagents per task (implementer → spec-reviewer →
quality-reviewer → tester, each in fresh context). The architecture
was framed in skills/README.md as "agents do not call other
agents — one named exception" (the orchestrator-agent being the
exception).
The exception never existed in Claude Code. The platform forbids all nested-subagent dispatch, categorically:
"Subagents cannot spawn other subagents, so
Agent(agent_type)has no effect in subagent definitions." — https://code.claude.com/docs/en/sub-agents
"Subagents cannot spawn their own subagents. Don't include
Agentin a subagent'stoolsarray." — https://code.claude.com/docs/en/agent-sdk/subagents
The Agent tool was silently dropped from the orchestrator-agent's
tool set at dispatch time (no error, no warning). The pr.1 run
caught this empirically; the diagnosis closed the question today.
Why the failure took the form it did
The Boss-Orchestrator (me) designed or.1 on the false premise
that the project's house rule "agents do not call other agents"
was a local convention with a documented exception. In reality the
house rule was a restatement of an external constraint — and the
"named exception" was incompatible with the constraint itself.
This is a verification-of-capability failure: the architecture was
locked in before checking the platform docs for what subagents can
do. The right order is the other way around. (Memorised as a
feedback memory for future architecture decisions.)
The corrected architecture
Same skill body, same skill triggers, same branch-and-merge discipline, same Boss-side end-report contract. What changes is inside the orchestrator-agent's run:
- Per-task phases (implementer → spec-compliance check → quality check) run sequentially as role-switches in the orchestrator- agent's own context, not as nested subagents.
- The
ailang-implementer.md/ailang-spec-reviewer.md/ailang-quality-reviewer.md/ailang-tester.mdfiles now serve as phase reference files — the orchestrator-agent consults them at each role-switch to inhale the discipline of that role, but does not dispatch them as separate subagents. - The Boss-context offload property is preserved (the Boss still sees only the ≤500-token end-report; per-task chatter stays inside the orchestrator-agent's context).
- The fresh-per-phase context property — which was the design goal
that drove
or.1to attempt nested dispatch — is given up. Pure role-switching inside one context is a weaker discipline than fresh-context-per-phase. The trade-off is named openly: the cost is the loss of fresh-eyes review per phase; the benefit is that the architecture is buildable in Claude Code at all. - The pr.1 "degraded mode" was not actually degraded — it was the only mode this agent can run in. The pr.1 journal's degraded- mode caveat is preserved as-is (historical record of how the constraint was discovered).
Why option (A), not (B) or (C)
Three options were on the table:
- (A) Single-context inline phases (what landed) — preserves Boss-context offload, gives up fresh-per-phase context.
- (B) Roll back to pre-or.1: Boss dispatches each per-task subagent itself. Preserves fresh-per-phase context, gives up Boss-context offload.
- (C) Hybrid: orchestrator-agent for setup / branch / journal, Boss for per-task dispatches in between. Preserves both theoretically but multiplies moving parts.
(A) was chosen because the Boss-context offload is the scarce resource (user chat budget). Empirically, the pr.1 run with the plan template's verbatim per-task content blocks made fresh-per- phase context contribute little additional signal beyond a careful single-context phase loop. The decision was made by the user 2026-05-11 after the diagnosis was presented; the rationale belongs in the user's hands, not the agent's.
Files changed
skills/implement/agents/ailang-implement-orchestrator.md— frontmatter (Agentremoved from tools, description rewritten), Iron Law (sequential role-switches instead of fresh subagents), Phase 2.1 / 2.2 / 2.3 rewritten as inline phases, Phase 3 likewise, common rationalisations and red flags updated.skills/implement/SKILL.md— frontmatter description, Iron Law, per-task sub-status mechanics note (vocabulary is preserved but now describes inline role-phase status), one new Common-Rationalisation row, Cross-references rewritten (role-files recast as phase references, with a "Why inline phases" subsection pointing here).skills/README.md— Conventions: "Agents do not call other agents — one named exception" → "Agents do not call other agents" (the exception is gone, with an explanation of why). Agent roster rows for implementer / spec-reviewer / quality-reviewer / tester recast as phase references for the orchestrator-agent.docs/roadmap.md— P1 entry "Agenttool wiring for the dispatched orchestrator-agent" removed (resolved as categorically-not-fixable).docs/journals/INDEX.md— this entry appended.docs/WhatsNew.md— user-facing correction entry appended.
Files NOT changed (and why)
CLAUDE.md— no stale references; the file does not encode the named-exception story.skills/implement/agents/ailang-implementer.md,ailang-spec-reviewer.md,ailang-quality-reviewer.md,ailang-tester.md— these remain unchanged. Their content (discipline, reading list, output format) is correct in the new architecture; their role in the system has shifted from "dispatched subagent" to "phase reference for the orchestrator- agent". The shift is documented in the README roster row and the SKILL.md Cross-references; no in-file edits are required for correctness. A future cleanup iter may rewrite their frontmatter to drop the "subagent" framing if it begins to mislead — for now the cost of touching four files outweighs the marginal clarity gain.docs/specs/2026-05-11-implement-orchestrator-agent.mdanddocs/specs/2026-05-11-plan-recon-subagent.md— specs are historical records of the design as conceived; they remain accurate to that moment. Drift between spec and the corrected architecture is acknowledged here, not by editing the specs.
Concerns
None. The revision is deliberate and self-contained.
Known debt
- Phase reference files frame themselves as dispatched subagents.
ailang-implementer.mdand its three siblings still read like files describing a subagent receiving a carrier from a dispatcher. In the corrected architecture, the orchestrator-agent IS the dispatcher and the worker for those phases. If the next/implementrun shows the orchestrator-agent confused by this framing during phase reads, a follow-up cleanup iter rewrites the four files. Not pre-emptive — wait for an empirical signal. - No verification ladder for the corrected design.
or.1's verification ladder (items 1–5 indocs/specs/2026-05-11-implement-orchestrator-agent.md) was written for the nested-dispatch architecture. Items 1–3 (Boss-side dispatch, branch creation, journal write) carry over unchanged. Items 4–5 (intentional BLOCKED, intentional re-loop) are weaker in the inline-phase world — re-loop is a same-context retry, not a fresh-context re-dispatch — and a new ladder entry for the inline phase-switch should be added the next time/implementruns against a non-trivial plan. Tracked informally; no ticket.
Blocked detail
N/A — DONE.
Commits
This entry's revision lands as a single trivial-mechanical commit
on main (no iter branch, no plan template). The commit subject is
or.2: orchestrator-agent design correction — no nested subagent dispatch.
Stats
N/A — no orchestrator-agent dispatch (this is a doc-only revision made directly by the Boss-Orchestrator).