<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohammad Fauzel Sadeghizad</title>
    <description>The latest articles on DEV Community by Mohammad Fauzel Sadeghizad (@sadeghizad).</description>
    <link>https://dev.to/sadeghizad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4110255%2Ffaa50c68-6598-45c6-aac8-acb223cc67cd.png</url>
      <title>DEV Community: Mohammad Fauzel Sadeghizad</title>
      <link>https://dev.to/sadeghizad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sadeghizad"/>
    <language>en</language>
    <item>
      <title>Giving a Coding Agent an Org Chart</title>
      <dc:creator>Mohammad Fauzel Sadeghizad</dc:creator>
      <pubDate>Fri, 04 Sep 2026 18:48:03 +0000</pubDate>
      <link>https://dev.to/sadeghizad/giving-a-coding-agent-an-org-chart-dbl</link>
      <guid>https://dev.to/sadeghizad/giving-a-coding-agent-an-org-chart-dbl</guid>
      <description>&lt;p&gt;Every agent harness eventually grows a "spawn a subagent" tool, and every one hits the same wall: the child's transcript flows back into the mother's context. Spawn three children to refactor three modules and the mother now carries three full transcripts — tool calls, failed attempts, whole-file reads — most of which she never needed. Context is an agent's scarcest resource, and the default subagent design spends it as if the children's work were the point. The &lt;em&gt;outcome&lt;/em&gt; is the point. &lt;strong&gt;Subsessions&lt;/strong&gt; is our answer: a protocol layer over the continuable-subagent runtime in our fork of the DeepSeek Harness. The hero picture is the whole idea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              ┌───────────────────────────────┐
              │   mother session (planner)    │   sees: briefs + reports
              └──────┬────────┬────────┬──────┘   never: transcripts
           ┌─────────┘        │        └──────────┐
    ┌──────▼──────┐    ┌──────▼───────┐    ┌──────▼──────┐
    │  worker A   │    │  worker B    │    │  verifier   │
    │ owns a/*    │    │ owns b/*     │    │ leaf role   │
    └──────┬──────┘    └──────┬───────┘    └─────────────┘
           │ progress         │ final report
           └────────┬─────────┘
                    ▼
     bounded reports only → mother pays O(report)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The design rests on one invariant that outranks every convenience:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The mother's context grows by O(report), never by O(child transcript). The human sees the whole org tree; the mother sees only structured reports.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The shape of a subsession
&lt;/h2&gt;

&lt;p&gt;A subsession is a real session — its own runtime &lt;code&gt;SessionId&lt;/code&gt;, context window, tool permissions — that differs from a plain subagent in four ways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is role-typed.&lt;/strong&gt; Spawn takes a &lt;em&gt;role&lt;/em&gt;, never a model id; the preset's role table maps roles to tiers and depth caps. A role with &lt;code&gt;depthCap: 0&lt;/code&gt; is a leaf: the system &lt;em&gt;asserts&lt;/em&gt; its tool filter denies &lt;code&gt;subsession_spawn&lt;/code&gt;, so a worker can never become a mother — checked at role-definition time, not left to prompt goodwill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is brief-initialized.&lt;/strong&gt; The mother writes a versioned brief (&lt;code&gt;briefVersion: 1&lt;/code&gt;): mission, owned file globs, token cap, depth allowance, report contract (required sections + max report tokens), an optional verify list and &lt;code&gt;continues: &amp;lt;predecessorId&amp;gt;&lt;/code&gt;. Validated field-by-field before anything starts; a rejection names the exact fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is report-communicating.&lt;/strong&gt; The child talks back through exactly one tool. A &lt;em&gt;progress&lt;/em&gt; report is a heartbeat — quiet delivery, no wake. A &lt;em&gt;final&lt;/em&gt; report settles the node forever and must satisfy the report contract, with a size gate that runs &lt;em&gt;before&lt;/em&gt; structural validation: an over-cap report is rejected as &lt;code&gt;REPORT_TOO_LARGE&lt;/code&gt; even if also malformed, so the size invariant is never traded away for a better error message. Reports are append-only, bounded to the last 50.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is continuable.&lt;/strong&gt; At any point a child can append a &lt;em&gt;checkpoint&lt;/em&gt; to its journal — phase, state, decisions so far, next step — an append-only JSONL file per child; the registry holds only a pointer (&lt;code&gt;workspaceFile:&amp;lt;path&amp;gt;#&amp;lt;line&amp;gt;&lt;/code&gt;). When a child dies, is killed, or finishes blocked, a fresh child can be spawned with &lt;code&gt;continues: &amp;lt;predId&amp;gt;&lt;/code&gt;, the seed text carrying the checkpoint ref. Predecessors are never deleted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The spawn pipeline is a pinned order, not vibes
&lt;/h2&gt;

&lt;p&gt;Child creation runs nine checks in a fixed order, each short-circuiting into a canonical error code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;validateBrief → role exists → role safety → depth → tool filter
→ scope overlap vs live siblings → tree budget → concurrency caps
→ start child exactly once → register
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two deserve comment. &lt;em&gt;Scope overlap&lt;/em&gt; is a conservative glob check against live siblings under the same mother — two children can't silently own the same files (&lt;code&gt;SCOPE_OVERLAP&lt;/code&gt; names the sibling and the paths; &lt;code&gt;allowOverlap: true&lt;/code&gt; is allowed but logged). &lt;em&gt;Tree budget&lt;/em&gt; is declared-arithmetic: the sum of live descendant caps plus the new cap must fit inside the mother's declared budget — arithmetic, not metering (more below).&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture: decision cores with injected ports
&lt;/h2&gt;

&lt;p&gt;The protocol splits into two kinds of code. &lt;strong&gt;Decision cores&lt;/strong&gt; are pure functions over the registry and schemas — no harness imports, no I/O, no clock. &lt;code&gt;planAndStartSpawn&lt;/code&gt; takes a &lt;code&gt;SpawnPorts&lt;/code&gt; object (role table, config, an &lt;code&gt;identifyMother()&lt;/code&gt; probe, a &lt;code&gt;startChild&lt;/code&gt; spy target) and returns an outcome; &lt;code&gt;acceptChildReport&lt;/code&gt;, &lt;code&gt;sweepQuiescence&lt;/code&gt;, &lt;code&gt;buildSuccessionBrief&lt;/code&gt;, &lt;code&gt;handoverOf&lt;/code&gt; all share the shape. This made the protocol testable with spies before runtime wiring existed, and made check &lt;em&gt;ordering&lt;/em&gt; a tested property.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime wiring&lt;/strong&gt; is a thin host plugin that adapts the cores to real services — &lt;code&gt;ctx.subagents.startContinuable&lt;/code&gt;, &lt;code&gt;defineTool&lt;/code&gt;, the &lt;code&gt;subagent/end&lt;/code&gt; event, file appends — with the clock injected by the wrapper, keeping the cores clockless and quiescence math deterministic in tests.&lt;/p&gt;

&lt;p&gt;One honest wart, documented rather than hidden: the continuable-setup registry is process-global, so the registry and journal are module-level singletons. Multiple mounted instances would double-register child tools and throw; sharing the singletons makes whichever instance wins behaviorally identical, because node ids are global session ids.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approvals: protocol-only, and we mean it
&lt;/h2&gt;

&lt;p&gt;The spec's sharpest non-negotiable: &lt;strong&gt;children can never park on a human approval, and the mother can never approve a descendant's escalation — no code path, not even a hidden one.&lt;/strong&gt; The runtime pins children to &lt;code&gt;approvalPolicy: 'never'&lt;/code&gt; before dispatch; a test greps the plugin sources for &lt;code&gt;approvalPolicy&lt;/code&gt; and &lt;code&gt;user-approval&lt;/code&gt; on every run.&lt;br&gt;
So how does a child that hits a permission wall make progress? It checkpoints, then sends a final report with &lt;code&gt;outcome: 'blocked'&lt;/code&gt; and &lt;code&gt;blockers: ["approval-required: fs write"]&lt;/code&gt;. The human's queue is a &lt;em&gt;view&lt;/em&gt; over blocked finals — rendered in the browser, not a runtime state. The child settles cleanly, its slot frees, and a human decides whether to spawn a successor with the missing grant. Escalation becomes a data structure instead of a hung process.&lt;/p&gt;
&lt;h2&gt;
  
  
  The browser sees the org chart
&lt;/h2&gt;

&lt;p&gt;A second client plugin renders what the mother never sees: the whole tree. It polls two host RPC endpoints every five seconds and shows the full org tree at any depth with live token usage per node where the projection is available — cold children show declared caps only, never faked numbers — checkpoint badges on settled nodes (a predecessor stays &lt;em&gt;browsable&lt;/em&gt; after death), and the blocked queue with a &lt;strong&gt;Handover&lt;/strong&gt; button that copies mission + blockers + checkpoint summary to the clipboard.&lt;/p&gt;

&lt;p&gt;One deliberate data-plane detail: RPC payloads use conditional spreads (&lt;code&gt;...(x !== undefined ? { x } : {})&lt;/code&gt;) because a &lt;code&gt;key: undefined&lt;/code&gt; breaks the runtime's value snapshots.&lt;/p&gt;
&lt;h2&gt;
  
  
  Succession: firing an employee without reading their desk
&lt;/h2&gt;

&lt;p&gt;When a child finishes blocked, fails, or is retired — then what? &lt;code&gt;subsession_succeed { childId, role?, mission?, tokenCap? }&lt;/code&gt; spawns a &lt;strong&gt;successor&lt;/strong&gt;: it inherits the predecessor's brief (with optional overrides), pins &lt;code&gt;continues: &amp;lt;predecessorId&amp;gt;&lt;/code&gt;, and — critically — re-runs the &lt;em&gt;entire&lt;/em&gt; spawn pipeline against the current tree. A stale scope claim can legitimately fail with &lt;code&gt;SCOPE_OVERLAP&lt;/code&gt; against a sibling that moved in since. Succession is not a resurrection; it's a fresh hire with a handover letter.&lt;br&gt;
The handover letter is the O(report) invariant made tangible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;continues: "a9e70fb7-…"
checkpoint: workspaceFile:.dsh/subsessions/a9e70fb7-….journal.jsonl#1
predecessor handover: need permission
predecessor blockers: approval-required: fs write
predecessor open questions: is fs write allowed?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A pointer, a phase, three lines of summary. Not the transcript.&lt;/p&gt;

&lt;p&gt;The gate before succession is a &lt;strong&gt;quiescence sweep&lt;/strong&gt;: a running child whose last sign of life (&lt;code&gt;max(heartbeat, claim-stamp)&lt;/code&gt;) is older than &lt;code&gt;retireTimeoutMs&lt;/code&gt; is presumed dead — settled &lt;code&gt;failed&lt;/code&gt;, descendants orphaned, slot freed. This fixed a real leak: silently-dead children held their slots forever, because nothing else emits a death event. The sweep runs at succession entry; claim-stamps are taken at the spawn gate (silence measured from the real spawn moment), and the sweep is idempotent.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we verified it
&lt;/h2&gt;

&lt;p&gt;Four phases, four gates, one rule kept throughout: &lt;strong&gt;no pass claim without machine evidence&lt;/strong&gt; (junit XML, tsc exit codes, lint counts).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gate&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P1&lt;/td&gt;
&lt;td&gt;Host plugin: schemas, roles, registry, budget, scope, journal, pipelines&lt;/td&gt;
&lt;td&gt;132/132 tests, tsc 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P2&lt;/td&gt;
&lt;td&gt;Client UI: org tree + blocked queue + Handover&lt;/td&gt;
&lt;td&gt;host 141/141, client 5/5, bundle verified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;td&gt;Succession command, quiescence sweep, claim stamps&lt;/td&gt;
&lt;td&gt;host &lt;strong&gt;155/155&lt;/strong&gt; (14 suites), lint 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P4&lt;/td&gt;
&lt;td&gt;Docs only&lt;/td&gt;
&lt;td&gt;package README&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three layers of tests carry the weight: &lt;strong&gt;protocol tests&lt;/strong&gt; over the pure cores (brief/report validation, pinned check order, budget boundaries, scope conflicts, idempotent second finals, orphan cascades — 28 cases, no runtime); &lt;strong&gt;integration tests&lt;/strong&gt; driving the real cores through ports with spies, including the kill-mid-task → checkpoint → respawn roundtrip; and a &lt;strong&gt;driver suite over the real runtime&lt;/strong&gt; — actual &lt;code&gt;Context&lt;/code&gt;, children executed in-process, no model turns. The succession roundtrip asserts the successor's &lt;em&gt;actual seed text&lt;/em&gt; contains the checkpoint ref and handover lines: the property that matters, verified end to end.&lt;/p&gt;

&lt;p&gt;The tests earned their keep: a client bug (a transport failure wiped the UI's last-good snapshot), a tool-filter gap (&lt;code&gt;subsession_succeed&lt;/code&gt; and &lt;code&gt;subsession_checkpoint&lt;/code&gt; were missing from the deny-strip guard), and a clock-ownership drift (&lt;code&gt;claimedAt&lt;/code&gt; was never stamped, so "silence since spawn" was measured from epoch zero). None visible in the passing happy path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related work: we're not the first to want this boundary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Claude Code — &lt;code&gt;context: fork&lt;/code&gt; and agent frontmatter.&lt;/strong&gt; Claude Code 2.1.0 added "running skills and slash commands in a forked sub-agent context" via &lt;code&gt;context: fork&lt;/code&gt; in SKILL.md frontmatter — deliberately left OFF by default. &lt;code&gt;agent: &amp;lt;name&amp;gt;&lt;/code&gt; dispatches a skill to a named subagent, &lt;code&gt;model:&lt;/code&gt; (opus / sonnet / haiku / inherit) is honored in fork mode, &lt;code&gt;allowed-tools:&lt;/code&gt; pre-approves a list, and subagent definitions accept &lt;code&gt;skills: string[]&lt;/code&gt; to preload at startup. The tell that the idea crossed from "interesting" into "maintained": public bug reports — hooks not propagating into forked subagents, output swallowed by the desktop UI, infinite re-invocation loops (fixed in 2.1.145), &lt;code&gt;agent:&lt;/code&gt; silently ignored in 2.1.112. (&lt;a href="https://code.claude.com/docs/en/sub-agents" rel="noopener noreferrer"&gt;sub-agents docs&lt;/a&gt;, &lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview" rel="noopener noreferrer"&gt;agent skills overview&lt;/a&gt;, &lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;skills spec&lt;/a&gt;, &lt;a href="https://github.com/anthropics/claude-code/issues/14661" rel="noopener noreferrer"&gt;issue #14661&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cognition — "Don't Build Multi-Agents" and the read-parallel/write-serial rule.&lt;/strong&gt; Parallel agents make implicit, conflicting decisions; context passing across agents is the unsolved problem. What works in production: multiple agents contribute intelligence but &lt;em&gt;writes stay single-threaded&lt;/em&gt;; parallel-writer swarms still don't see meaningful adoption. Anthropic's cost number: a multi-agent research system burns ~15× the tokens of chat, and token usage alone explained 80% of performance variance on BrowseComp. (&lt;a href="https://cognition.com/blog/multi-agents-working" rel="noopener noreferrer"&gt;Don't Build Multi-Agents&lt;/a&gt;, &lt;a href="https://www.anthropic.com/engineering/multi-agent-research-system" rel="noopener noreferrer"&gt;Anthropic multi-agent research&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MAST — the 14 failure modes.&lt;/strong&gt; 1,600+ annotated traces across 7 multi-agent frameworks found 14 distinct failure modes in 3 categories — bad specification, inter-agent misalignment, failed verification — with inter-annotator kappa of 0.88. ChatDev scores 33.33% correctness on its ProgramDev benchmark, and the headline: multi-agent gains are often minimal against single-agent frameworks or even best-of-N sampling. (&lt;a href="https://arxiv.org/abs/2503.13657" rel="noopener noreferrer"&gt;arXiv:2503.13657&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ReWOO — decoupling reasoning from observations.&lt;/strong&gt; ReWOO's planner emits a plan with placeholders, workers execute the steps, and a solver composes the final answer once — instead of interleaving every tool observation back into the model's reasoning loop. Subsessions shares the instinct (don't feed raw observations upstream) but draws the boundary at the session level: the mother never receives the child's loop, only the settled report. (&lt;a href="https://arxiv.org/abs/2305.18323" rel="noopener noreferrer"&gt;arXiv:2305.18323&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Where we sit: closest to Claude Code's forked-context line — role-typed children returning bounded output — but with the boundary pinned structurally (spawn gates, size gates, protocol-only approvals, succession) rather than by frontmatter convention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we deviated from the spec — on purpose, at the gate
&lt;/h2&gt;

&lt;p&gt;A spec that can't be argued with is a wish list. Every deviation was surfaced in a gate report, not smuggled in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Approval parking → protocol-only.&lt;/strong&gt; The blocked-final queue replaces runtime parking entirely (above).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivery modes: &lt;code&gt;quiet | next-step&lt;/code&gt; only.&lt;/strong&gt; Progress delivers quietly; finals deliver at the next step boundary. No retry buffer — a dead mother's report triggers the orphan cascade instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier→model is plugin config, not eval.&lt;/strong&gt; Presets can't pin models in our runtime; per-task tier selection via evals is future work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Journal = workspace-file JSONL.&lt;/strong&gt; The spec wanted a memory service the fork doesn't have; append-only files with line-numbered pointers get the same properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;verify: ['files']&lt;/code&gt; = existence check.&lt;/strong&gt; A missing claimed file marks the node &lt;code&gt;disputed&lt;/code&gt;; changed-but-unclaimed detection needs snapshot diffs we didn't build.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declared-budget arithmetic.&lt;/strong&gt; No live token metering exists in the runtime for cold children; caps are enforced by arithmetic, live usage is shown only where the projection exists, and we never fake a number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI is polling, not push.&lt;/strong&gt; Five seconds is fine; event push is an optimization, not a design change.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What we'd tell the next implementer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pin the check order and test the order itself.&lt;/strong&gt; Half the subtle bugs in permission-adjacent systems are ordering bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep decision cores clockless and I/O-free.&lt;/strong&gt; Every deterministic test we have is downstream of that one choice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make escalation a data structure.&lt;/strong&gt; A hung child waiting for permission is a bug you can't see; a blocked final report is a row in a queue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never fake telemetry.&lt;/strong&gt; Cold children show declared caps, not invented usage; a dashboard that lies once is a dashboard forever.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;All four phases are landed and gated in the fork: host plugin, client UI, succession + quiescence, docs. The host suite stands at &lt;strong&gt;155/155&lt;/strong&gt; across 14 suites, the client suite at &lt;strong&gt;5/5&lt;/strong&gt;, type checks and lint clean. Gate reports record the evidence and every deviation.&lt;/p&gt;

&lt;p&gt;Which leaves the honest ending. The O(report) invariant is enforced structurally today — every gate, every report contract, every succession letter exists to hold it. And now we have measured what it is worth on real workloads: read the follow-up measurement report, &lt;a href="https://dev.to/sadeghizad/measuring-the-multi-agent-fork-tax-f9j"&gt;Measuring the Multi-Agent Fork Tax&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>engineering</category>
    </item>
    <item>
      <title>Measuring the Multi-Agent Fork Tax</title>
      <dc:creator>Mohammad Fauzel Sadeghizad</dc:creator>
      <pubDate>Fri, 04 Sep 2026 18:46:27 +0000</pubDate>
      <link>https://dev.to/sadeghizad/measuring-the-multi-agent-fork-tax-f9j</link>
      <guid>https://dev.to/sadeghizad/measuring-the-multi-agent-fork-tax-f9j</guid>
      <description>&lt;p&gt;In our previous post, &lt;a href="https://dev.toREPO-URL-TBD"&gt;Giving a Coding Agent an Org Chart&lt;/a&gt;, we described &lt;strong&gt;Subsessions&lt;/strong&gt;: a protocol layer over agent runtimes that enforces role-typed child sessions, versioned briefs, and append-only checkpoint journals.&lt;/p&gt;

&lt;p&gt;The entire architecture rested on one foundational invariant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The mother's context grows by $O(\text{report})$, never by $O(\text{child transcript})$. The human sees the whole org tree; the mother sees only structured reports.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We closed that post with an unresolved question:&lt;br&gt;
&lt;em&gt;The invariant holds mechanically—every gate, every report contract, every succession letter exists to enforce it. What we don't know yet is what it is worth on real workloads: we haven't published the measurement.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post publishes the measurement.&lt;/p&gt;

&lt;p&gt;We pre-registered a formal evaluation rubric (&lt;code&gt;RUBRIC.md&lt;/code&gt;), generated deterministic fixtures across 20 programming tasks, collected 45 full execution runs across two experimental arms, and submitted the entire dataset to an independent adversarial verification audit (&lt;code&gt;results/VERIFICATION.md&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The findings are unambiguous, humbling, and a stark reminder that in software architecture, no abstraction is free.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. The Experiment: Inline vs. Orchestrated
&lt;/h2&gt;

&lt;p&gt;To test whether subsession orchestration outperforms a single agent session, we evaluated two arms under identical conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Inline Arm (Role: &lt;code&gt;worker&lt;/code&gt;)&lt;/strong&gt;: A single autonomous session. The subsession toolset is structurally stripped (&lt;code&gt;canSpawn: false&lt;/code&gt;). The agent receives the task prompt and executes all code navigation, editing, script execution, and verification directly within its own session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Orchestrated Arm (Role: &lt;code&gt;coordinator&lt;/code&gt;)&lt;/strong&gt;: A supervisor session authorized to spawn children (&lt;code&gt;canSpawn: true&lt;/code&gt;, &lt;code&gt;depthCap: 2&lt;/code&gt;). Under pre-registered protocol amendments, the coordinator is required to delegate work to at least two worker subsessions and synthesize their returned reports before delivering the final answer.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Strict Fairness Controls
&lt;/h3&gt;

&lt;p&gt;To ensure we measured the structural cost of orchestration rather than model variance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identical Model&lt;/strong&gt;: Every session across both arms resolved to the deployment default (&lt;code&gt;bai-/glm-5.3-flash&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identical Seed Fixtures&lt;/strong&gt;: All repository files (80 TypeScript files), financial CSVs (360 rows in integer cents), server logs (3,000 lines), and meeting notes (347 KB across 200 sections) were deterministically synthesized from a seeded PRNG (Mulberry32).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mechanical Scoring&lt;/strong&gt;: Outputs were evaluated mechanically by &lt;code&gt;checks/check.mjs&lt;/code&gt; using strict deep-equality against frozen JSON ground truths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interleaved Execution&lt;/strong&gt;: Runs alternated in an A/B/B/A sequence to eliminate time-of-day API throttling biases.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  2. The Headline Result: The Fork Tax
&lt;/h2&gt;

&lt;p&gt;We measured 20 tasks divided across four distinct software engineering classes ($5$ tasks per class). Across the 19 completed pairs, orchestration was strictly more expensive in every single case.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Caveat: One model, one day, $n=5$ per cell, mandatory fan-out ($\ge 2$ workers).&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task Class&lt;/th&gt;
&lt;th&gt;Inline Tokens (med)&lt;/th&gt;
&lt;th&gt;Orch Tokens (med)&lt;/th&gt;
&lt;th&gt;Token Ratio&lt;/th&gt;
&lt;th&gt;Inline Wall (med)&lt;/th&gt;
&lt;th&gt;Orch Wall (med)&lt;/th&gt;
&lt;th&gt;Wall Ratio&lt;/th&gt;
&lt;th&gt;Mother / Inline&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;breadth-read&lt;/strong&gt; (T01–T05)&lt;/td&gt;
&lt;td&gt;76,393&lt;/td&gt;
&lt;td&gt;304,824&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.99×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;204 s&lt;/td&gt;
&lt;td&gt;491 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.41×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.65×&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;single-write&lt;/strong&gt; (T06–T10)&lt;/td&gt;
&lt;td&gt;49,269&lt;/td&gt;
&lt;td&gt;215,631&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;96 s&lt;/td&gt;
&lt;td&gt;745 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.76×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.18×&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;longdoc-transform&lt;/strong&gt; (T11–T15)&lt;/td&gt;
&lt;td&gt;170,631&lt;/td&gt;
&lt;td&gt;592,452&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.47×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;439 s&lt;/td&gt;
&lt;td&gt;1,224 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.79×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.30×&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;multi-step-tool&lt;/strong&gt; (T16–T20)&lt;/td&gt;
&lt;td&gt;104,321&lt;/td&gt;
&lt;td&gt;390,129&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.74×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;185 s&lt;/td&gt;
&lt;td&gt;759 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.10×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.70×&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On accuracy, both arms achieved identical performance: both passed 100% of tasks T01 through T19. (Both arms failed T20 identically due to a disclosed ground-truth collation defect where the prompt asked for lexicographic ordering and the generator sorted directory-first).&lt;/p&gt;

&lt;p&gt;On cost and latency, however, orchestration imposed a severe &lt;strong&gt;fork tax&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token Inflation&lt;/strong&gt;: Orchestrated execution required &lt;strong&gt;$3.47\times$ to $4.38\times$&lt;/strong&gt; more total billed tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wall-Clock Latency&lt;/strong&gt;: Orchestrated execution was &lt;strong&gt;$2.41\times$ to $7.76\times$&lt;/strong&gt; slower. On single-write tasks, dispatching workers, awaiting tool handshakes, and merging reports took $745$ seconds versus $96$ seconds for the single inline agent.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  3. Where Did the Tokens Go?
&lt;/h2&gt;

&lt;p&gt;The most critical finding emerged when we disassembled the token accounting inside the subsession trees.&lt;/p&gt;

&lt;p&gt;A naive assumption is that multi-agent systems burn tokens because multiple workers are exploring parallel paths. The telemetry revealed the exact opposite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Orchestrated Run Token Spend (Median Across 19 Pairs):
├── Mother Session (Supervisor Loop): 55%
└── Worker Subsessions (Task Work):   45%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Over half (55%) of all tokens in an orchestrated run were consumed by the mother session's own loop&lt;/strong&gt;, not by the children doing the work.&lt;/p&gt;

&lt;p&gt;Look at the operational numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Across all 19 completed pairs, the median volume of child reports delivered to the mother was &lt;strong&gt;3,529 bytes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The median token spend of the mother session managing those reports was &lt;strong&gt;213,219 tokens&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The mother spent $\sim 60\times$ more tokens driving her own coordination loop than the total content size of the reports she received.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the central paradox of context engineering: &lt;strong&gt;the $O(\text{report})$ invariant held mechanically on disk, but was economically irrelevant.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The mother's context was indeed protected from child transcripts: she received clean, 2~KB to 7~KB JSON summaries. But the cognitive tax of running a supervisor—formulating structured briefs, specifying filesystem globs, waiting for turns, polling status, reconciling discrepancies, and formatting output—dwarfed the entire cost of the task.&lt;/p&gt;

&lt;p&gt;In 17 of the 19 completed pairs, the mother session's spend &lt;em&gt;alone&lt;/em&gt; exceeded the total token usage of the inline agent doing the entire task from start to finish.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Elusive Crossover Point
&lt;/h2&gt;

&lt;p&gt;In our pre-registered protocol, we hypothesized that as task scale and document size increased, a measurable "crossover point" would emerge where the token savings of context isolation would overtake protocol overhead (Hypothesis 3).&lt;/p&gt;

&lt;p&gt;The data refuted this hypothesis entirely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pairs where orchestration used fewer total tokens:&lt;/strong&gt; &lt;strong&gt;0 / 19&lt;/strong&gt; (0%).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pairs where the mother alone used fewer tokens than inline:&lt;/strong&gt; &lt;strong&gt;2 / 19&lt;/strong&gt; (Task T13 at $0.99\times$, Task T17 at $0.86\times$).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H4 Invariant Bar ($\text{mother tokens} &amp;lt; 0.5\times \text{inline total}$):&lt;/strong&gt; &lt;strong&gt;0 / 19&lt;/strong&gt; (0%).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even on the largest fixture in the benchmark—a 347~KB, 200-section executive meeting document—the inline agent completed the analysis in 170,631 tokens. The orchestrated arm burned 592,452 tokens ($3.47\times$). Why? Because modern LLM context windows (128k+) can digest a 347~KB document in a single gulp. Splitting the document across two workers meant both workers had to read their respective slices, serialize findings, and send them to the coordinator, who then had to read all findings and re-verify them.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Checkpoint Resumption and Deadlock Risk
&lt;/h2&gt;

&lt;p&gt;One promised advantage of subsession architectures is state resilience: if a subagent dies or is terminated mid-flight, a successor can resume from an append-only checkpoint journal without re-running the entire task (Hypothesis 5).&lt;/p&gt;

&lt;p&gt;To measure this, run &lt;code&gt;R38-T19-orch&lt;/code&gt; was deliberately killed mid-task at &lt;strong&gt;18,549 tokens (step 2, 78 seconds)&lt;/strong&gt;. It was then resumed with the frozen recovery prompt: &lt;em&gt;"you were stopped mid-task; recover from your checkpoint and finish; report normally."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The result was an operational disaster:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The resumed leg burned &lt;strong&gt;129,945 additional tokens&lt;/strong&gt; (total: 148,494 tokens).&lt;/li&gt;
&lt;li&gt;The coordinator attempted 5 child spawns. Two were rejected immediately because the model hallucinated unregistered role names (&lt;code&gt;log-analyst-a&lt;/code&gt;, &lt;code&gt;log-analyst-b&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The coordinator then spawned two valid worker subsessions. Both workers subsequently failed and terminated without delivering a final report.&lt;/li&gt;
&lt;li&gt;Crucially, the coordinator runtime possessed no timeout or dead-child detection for asynchronous reports.&lt;/li&gt;
&lt;li&gt;The coordinator emitted its final turn message: &lt;em&gt;"Both workers are running. I'll merge and write the deliverable once their final reports arrive,"&lt;/em&gt; ended its turn, and parked indefinitely.&lt;/li&gt;
&lt;li&gt;The run remained frozen in a deadlock state for &lt;strong&gt;53,046 seconds (~14.7 hours)&lt;/strong&gt; until the experimenter manually force-retired the session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The takeaway for agent harness designers is stark: &lt;strong&gt;without active quiescence monitoring and explicit timeouts on child report arrival, checkpoint resumption does not save tokens—it introduces unbounded deadlocks.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Real-World Mechanism Friction
&lt;/h2&gt;

&lt;p&gt;Because both arms executed against the identical frozen tasks, the benchmark illuminated four failure modes unique to multi-agent architectures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Role Name Hallucination (&lt;code&gt;UNKNOWN_ROLE&lt;/code&gt;)&lt;/strong&gt;: Coordinators repeatedly invented functional role names (&lt;code&gt;doc-summarizer-a&lt;/code&gt;, &lt;code&gt;summarizer&lt;/code&gt;, &lt;code&gt;log-analyst&lt;/code&gt;) instead of adhering to the role table (&lt;code&gt;worker&lt;/code&gt;). Each invalid spawn consumed a full LLM turn and tool round-trip before falling back to valid roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Tree Budget Starvation&lt;/strong&gt;: In our initial configuration, runs were given a shared tree budget of 150,000 tokens. In run &lt;code&gt;R15&lt;/code&gt;, the coordinator spent so many tokens setting up its planning loop that all 6 spawned children were admitted and killed at &lt;strong&gt;0 tokens&lt;/strong&gt;, unable to take their first step. We had to issue a protocol amendment (Amendment #4) raising the budget to 1,000,000 tokens so the cap would not bind asymmetrically on the orchestrated arm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-Verifier False Negatives&lt;/strong&gt;: In at least 8 runs, the runtime's automated verification hooks raced the filesystem writes of child sessions, falsely reporting deliverables as "missing" or "disputed." Coordinators had to burn extra turns reading the disk directly to dismiss the harness's own false alarms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker Unreliability&lt;/strong&gt;: In task T04, a worker claimed it found 53 imports when it had delivered 52. In task T13, workers claimed 103 items where the true count was 100. In both cases, the coordinator caught the discrepancies by re-running the extraction itself from raw source files. The coordinator did add value by catching hallucinations—but it did so by duplicating the worker's effort, strictly increasing total token spend.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  7. The Skeptic's View: Steelmanning the Attack
&lt;/h2&gt;

&lt;p&gt;An adversarial verifier was commissioned to independently audit this benchmark (&lt;code&gt;results/VERIFICATION.md&lt;/code&gt;). What would a skeptic say about these results?&lt;/p&gt;

&lt;p&gt;Here is the honest counter-argument:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This benchmark is an engineered test where multi-agent orchestration was structurally guaranteed to look inefficient. By mandating delegation to $\ge 2$ children on tasks that operate on small repositories and a 347~KB document, the benchmark forced a complex corporate hierarchy onto problems that comfortably fit into a single model turn. Orchestration exists to conquer tasks that exceed context limits; testing it on sub-100k token workloads merely measures the administrative overhead of JSON briefs and prompt handshakes. Furthermore, measuring cumulative billed tokens penalizes the inter-agent communication channels that keep worker contexts clean. This benchmark does not prove orchestration is flawed; it proves that requiring an agent to form a committee to write a 5-paragraph essay is wasteful.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This critique is valid, and we accept it.&lt;/p&gt;

&lt;p&gt;Our benchmark does &lt;strong&gt;not&lt;/strong&gt; prove that multi-agent systems are inherently inferior. It proves something more specific and immediately actionable: &lt;strong&gt;mandatory fan-out on workloads that fit within an LLM's active context window imposes a $3.5\times$ to $4.4\times$ cost multiplier with zero accuracy benefit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When given the choice in pilot run &lt;code&gt;R02b&lt;/code&gt;, a capable coordinator looked at the task, judged it small, and chose to do it entirely inline. Our protocol forced it to delegate. The coordinator's initial instinct was right.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Reproducing the Benchmark
&lt;/h2&gt;

&lt;p&gt;All data, scripts, ground truths, and per-run telemetry are open-source in the public repository under &lt;code&gt;bench/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;bench

&lt;span class="c"&gt;# 1. Verify deterministic fixtures and run self-test&lt;/span&gt;
node generate.mjs &lt;span class="nt"&gt;--verify&lt;/span&gt;
node selftest.mjs
&lt;span class="c"&gt;# Expected: 20/20 PASS, 3/3 deliberate corruptions caught&lt;/span&gt;

&lt;span class="c"&gt;# 2. Recompile CSV and recompute all metrics&lt;/span&gt;
node compile.mjs
node analyze.mjs
node stats.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every number in this article is derived directly from &lt;code&gt;results/results.csv&lt;/code&gt;. Per-run prompt definitions, metrics, and final reports are committed under &lt;code&gt;bench/runs/&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The subsession protocol successfully solves the problem it was designed to solve: child transcripts do not leak into supervisory context. &lt;/p&gt;

&lt;p&gt;However, solving the context isolation problem does not solve the cost problem. Coordination has mass. Writing briefs, inspecting outputs, managing tool permissions, and recovering from child stalls consumes more tokens than the work itself.&lt;/p&gt;

&lt;p&gt;For AI engineers building agent workflows, the architectural rule of thumb is clear:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Default to inline execution.&lt;/strong&gt; If the codebase, document, or working memory fits within the model's context window, keep it in a single session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not force delegation.&lt;/strong&gt; Allow autonomous supervisors to execute tasks inline when they deem them manageable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reserve orchestration for structural walls.&lt;/strong&gt; Deploy subagents only when context saturation degrades reasoning, or when strict security and tool sandboxing mandates an isolated execution boundary.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Until an agent hits a context or permission wall, the cheapest org chart is no org chart at all.&lt;/p&gt;




&lt;h3&gt;
  
  
  Resources &amp;amp; Artifacts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://dev.toREPO-URL-TBD"&gt;REPO-URL-TBD&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical Paper (arXiv)&lt;/strong&gt;: &lt;a href="https://dev.toREPO-URL-TBD"&gt;paper/subsessions-fork-tax.tex&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adversarial Verification Report&lt;/strong&gt;: &lt;a href="https://dev.toREPO-URL-TBD"&gt;&lt;code&gt;bench/results/VERIFICATION.md&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DeepSeek Harness Upstream&lt;/strong&gt;: &lt;a href="https://github.com/deepseek-ai/deepseek-harness" rel="noopener noreferrer"&gt;deepseek-ai/deepseek-harness&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>engineering</category>
    </item>
  </channel>
</rss>
