Files
AILang/docs/journals/2026-05-11-iter-or.2.md
T
Brummel 5c3bd9ab24 or.2: orchestrator-agent design correction — no nested subagent dispatch
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).
2026-05-11 13:01:38 +02:00

190 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
> `Agent` in a subagent's `tools` array."
> — 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.md` files 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.1` to 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 (`Agent` removed 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 "`Agent` tool 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.md` and
`docs/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.md` and 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
`/implement` run 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 15 in
`docs/specs/2026-05-11-implement-orchestrator-agent.md`) was
written for the nested-dispatch architecture. Items 13
(Boss-side dispatch, branch creation, journal write) carry over
unchanged. Items 45 (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
`/implement` runs 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).