Skip to main content

Why Role-Based Subagents Slow Down Coding Agents: Subagent Folding + Progressive Skill Disclosure (2.66x Faster)

Updated 9 min readMarkdown

πŸ’‘ AI Labo Benchmark Series β€” Experiment E05 (Multi-Agent vs. Folded Loop)

This post is part of our empirical benchmark series testing AI coding agent harness patterns inside network-isolated Proxmox VMs against a hidden 20-case grading suite.


Metadata & Experiment Identity

  • Experiment ID: E05 (Backlog Candidate C002)
  • Run ID: e05-vm209-20261028-01
  • Sandbox Environment: Proxmox Isolated VM VM209 (ai-e05-209, 0 NICs, virtio-serial QGA relay, systemd UID separation)
  • Model: gemini-3.8-flash (thinkingLevel: LOW)
  • Pattern Under Test: Anthropic Engineering ("Building agents: When to fold subagents into your main agent loop", Diane Sarkis) β€” Role-Based Subagent Swarm vs. Single Folded Loop + Progressive Skill Disclosure

1. Executive Summary (TL;DR)

When developers try to scale an AI coding agent, a tempting pattern is to mirror a human org chart: split the workflow into Role-Based Subagents (Architect βž” Core Implementer βž” Ledger Implementer βž” QA Fixer) and pass natural-language handoff summaries down the chain.

On tightly coupled codebases, this creates three severe bottlenecks:

  1. The "Telephone Game" Effect (Handoff Context Loss): When an Architect's 1,400-character plan is compressed or summarized for downstream workers, subtle edge-case invariants (like formatting zero discounts as -0 instead of 0) get dropped.
  2. Downstream Rework Loops: Implementers guess at missing details, causing integration failures that force QA Fixer retries.
  3. Static Skill Preloading Bloat: Because the router doesn't know which domain rules each subagent will need, all company skill docs (SOAP/XML, Kubernetes, GDPR, UI tokens, SaaS billing) get stuffed into subagent system prompts upfront.

To test Anthropic's Subagent Folding + Progressive Skill Disclosure architecture, we benchmarked a 3-module SaaS usage-billing pipeline (normalizer.py, billing.py, ledger.py) inside isolated VM VM209:

  • Mode A (RoleSubagentSwarmRunner): Splits the task across 4 role-based subagents with 3 handoffs and preloads all 5 internal company skill documents into the prompt.
  • Mode B (FoldedSkillLoopRunner): Folds planning, coding, and verification into one main agent loop with zero handoffs. The initial prompt shows only a 5-line Skill Catalog Index; the agent dynamically calls load_skill("saas_billing_spec") on Turn 1 and patches all 3 files in one coherent pass on Turn 2.

Key Result

Mode A suffered a classic Telephone Game bug: handoff truncation dropped the DISCOUNT: -0 formatting invariant, causing ledger.py to fail QA and trigger an extra rework turn (5 LLM calls, 36.36s). Mode B completed with zero handoffs and zero rework in 2 calls (13.68s)β€”running 2.66x faster (-62.4% time) while cutting input tokens by -67.0% (14,815 βž” 4,889), output tokens by -39.9% (2,397 βž” 1,440), and API cost by -54.9% ($0.0201 βž” $0.0091).

Metric Mode A: Role-Based Subagents (RoleSubagentSwarm) Mode B: Folded Loop + Skill Disclosure (FoldedSkillLoop) Delta / Improvement
Hidden Grading Suite Score (20 Cases) 20 / 20 (100% after rework) 20 / 20 (100% 1st-pass) Zero rework needed
Subagent Handoffs 3 handoffs (with summary loss) 0 handoffs (single shared context) Eliminated Telephone Game loss
QA Failure Rework Retries (failed_check_retries) 1 retry (DISCOUNT: -0 bug) 0 retries -100% rework
LLM Calls (model_calls) 5 calls 2 calls -60.0% fewer calls
Total File Edits (file_edits) 4 edits (ledger.py edited twice) 3 edits (1 per file) -25.0% fewer edits
Turn 1 Input Tokens 4,095 tokens (5 skills preloaded) 1,220 tokens (5-line index only) -70.2% initial prompt bloat
Cumulative Input Tokens (promptTokenCount) 14,815 tokens 4,889 tokens -67.0% reduction (~3x leaner)
Cumulative Output Tokens (candidatesTokenCount) 2,397 tokens 1,440 tokens -39.9% (no handoff prose or rework)
Elapsed Execution Time (elapsed_seconds) 36.36 sec 13.68 sec -62.4% (2.66x faster)
Estimated API Cost (estimated_micro_usd) $0.0201 (20,101 micro-USD) $0.0091 (9,067 micro-USD) -54.9% cost reduction

2. Architecture Comparison: Role Handoffs vs. Folded Skill Loop

+-------------------------------------------------------------------------+
| Proxmox Isolated VM209 (0 NICs, virtio-serial QGA, systemd UID split)   |
|  Target Task: 3-Module SaaS Usage Billing Pipeline                      |
|               (normalizer.py βž” billing.py βž” ledger.py)                  |
|                                                                         |
|  +-------------------------------------------------------------------+  |
|  | Mode A: RoleSubagentSwarmRunner (4 Roles + 5 Preloaded Skills)    |  |
|  |  - Turn 1 [Architect]:   Writes 1,437-char plan βž” truncated (220c)|  |
|  |  - Turn 2 [Impl Core]:   Patches normalizer.py & billing.py       |  |
|  |  - Turn 3 [Impl Ledger]: Patches ledger.py (misses `-0` rule!)    |  |
|  |  - Turn 4 [QA Fixer]:    run_tests βž” FAILS (`zero_discount_-0`)   |  |
|  |  - Turn 5 [QA Fixer]:    Re-patches ledger.py βž” PASS & SUBMIT     |  |
|  |  --> 5 calls | 14,815 in | 2,397 out | 36.36s                     |  |
|  +-------------------------------------------------------------------+  |
|                                                                         |
|  +-------------------------------------------------------------------+  |
|  | Mode B: FoldedSkillLoopRunner (Single Loop + Progressive Skills)  |  |
|  |  - Turn 1: Sees 5-line Skill Index βž” calls `load_skill` for only  |  |
|  |            `saas_billing_spec` (1,220 in / 21 out)                |  |
|  |  - Turn 2: Patches all 3 modules coherently in one context        |  |
|  |            + passes verifier on 1st try βž” AUTO_SUBMIT (3,669 in)  |  |
|  |  --> 2 calls | 4,889 in  | 1,440 out | 13.68s (2.66x faster!)     |  |
|  +-------------------------------------------------------------------+  |
+-------------------------------------------------------------------------+

3. Code-Level Postmortem: Catching the "Telephone Game" Bug in the Act

Inspecting actions.json and execution-traces.json from VM209 shows exactly how role-based handoffs break coupled invariants:

  1. On Turn 1 (seq 0), role_1_architect read all files and all 5 preloaded skill docs (4,095 input tokens) and authored a detailed 1,437-character handoff_plan. However, the router's summary budget (220 chars) truncated the tail of the noteβ€”cutting off the ledger.py formatting clause requiring DISCOUNT: -0 when the discount is zero.
  2. On Turn 3 (seq 2), role_3_implementer_ledger received only the truncated handoff summary and guessed a "reasonable" Python conditional:
# ❌ Mode A β€” Turn 3 (`role_3_implementer_ledger`): Guessed from truncated handoff!
out.append(f"DISCOUNT: -{disc}" if disc > 0 else f"DISCOUNT: {disc}")
  1. On Turn 4 (seq 3), role_4_qa_fixer ran integration tests (3,293 input tokens) and immediately hit {"error": "zero_discount_must_format_as_-0", "passed": false}, forcing Turn 5 (seq 4, 4,213 input tokens) to re-emit ledger.py from scratch.

In Mode B (FoldedSkillLoop), the single agent loaded saas_billing_spec directly into its working context (1,220 tokens on Turn 1) without loading the 4 irrelevant enterprise skills (SOAP/XML, K8s Helm, GDPR logging, React UI tokens), and wrote f"DISCOUNT: -{disc}" accurately on the very first pass.

Turn-by-Turn Token Breakdown (usage.json)

Mode Seq Role / Action Input Tokens Output Tokens Cost (micro-USD) What Happened
Mode A 0 role_1_architect: handoff_plan 4,095 412 4,617 5 skills preloaded; 1,437-char plan truncated
Mode A 1 role_2_implementer_core: patch_core 1,992 1,228 6,099 Implements normalizer.py & billing.py
Mode A 2 role_3_implementer_ledger: patch_ledger 1,222 402 2,424 Handoff loss: writes DISCOUNT: 0 bug
Mode A 3 role_4_qa_fixer: run_tests (FAIL) 3,293 8 2,500 Catches zero_discount_must_format_as_-0
Mode A 4 role_4_qa_fixer: fix_and_submit (PASS) 4,213 347 4,461 Re-patches ledger.py to recover
Mode A Sum β€” 5 calls (3 handoffs, 1 rework) 14,815 2,397 20,101 Extra output spent on prose + duplicate patch
Mode B 5 folded_turn_1: load_skill("saas_billing_spec") 1,220 21 994 Loads only the 1 relevant skill from 5-line index
Mode B 6 folded_turn_2: patch_pipeline βž” AUTO_SUBMIT 3,669 1,419 8,073 Patches all 3 modules in 1 shot; 0 rework
Mode B Sum β€” 2 calls (0 handoffs, 0 rework) 4,889 1,440 9,067 2.66x faster, -54.9% cheaper

4. All 20 Hidden Grading Suite Results (labjudge05)

Stage Test Case IDs Invariants Verified Mode A (Role Swarm) Mode B (Folded Loop)
Stage 1 (normalizer.py) normalizer_01 to normalizer_06 Trim/uppercase tenant_id & metric, allow only API_CALLS/STORAGE_GB, reject units <= 0 & bool/float, non-mutation 6 / 6 PASS 6 / 6 PASS
Stage 2 (billing.py) billing_01 to billing_08 First-seen order, rate conflict check, 9999 vs 10000 PRO/ENTERPRISE tier discount before credit_note, floor // 10, credit cap 8 / 8 PASS 8 / 8 PASS
Stage 3 & E2E (ledger.py) e2e_01 to e2e_06 DISCOUNT: -0 signed zero, aggregated units, free-tier ledger, floor tax E2E, line order, error propagation 6 / 6 PASS (fixed on Turn 5) 6 / 6 PASS (1st try)
Total 20 Hidden Cases β€” 20 / 20 (100%) 20 / 20 (100%)

5. Practical Takeaway: When to Split (E04) vs. When to Fold (E05)

Combining E04 (Loops vs. Graphs) and E05 (Subagent Folding) gives a crisp architectural rule for multi-agent design:

  • Split by Module + Deterministic Verifier (E04): Only isolate steps into separate contexts when each step produces a code artifact verified by a deterministic test suite and has a fixed interface contract.
  • Fold Sequential Roles (E05): Never split Architect βž” Coder βž” Reviewer across separate subagents connected by natural-language summaries on coupled files. Keep them in one folded loop, and replace bloated system prompts with Progressive Skill Disclosure (a 5-to-10 line index + on-demand load_skill).

πŸ”— Continue Reading the Series

No comments yet. Be the first to comment.

More from this blog