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

> 💡 **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.
> * 🚀 **[View All 41 Benchmark Results & Master Ranking](https://tappers.hashnode.dev/ai-agent-harness-patterns-benchmark)**
> * 🛡️ **[Read How Our Proxmox & systemd Anti-Cheating Sandbox Works](https://tappers.hashnode.dev/air-gapped-proxmox-systemd-agent-sandbox)**

---

## 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

```text
+-------------------------------------------------------------------------+
| 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:

```python
# ❌ Mode A — Turn 3 (`role_3_implementer_ledger`): Guessed from truncated handoff!
out.append(f"DISCOUNT: -{disc}" if disc > 0 else f"DISCOUNT: {disc}")
```

3. **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
* 🚀 **Master Benchmark Hub (All 41 Patterns Ranked):** [I Benchmarked 41 AI Agent Harness Patterns in Isolated VMs: How to Cut Tokens by 90% Without Losing Accuracy](https://tappers.hashnode.dev/ai-agent-harness-patterns-benchmark)
* 🛡️ **Methodology & Sandbox Architecture:** [How to Benchmark AI Agents Without Eval Cheating or API Key Leaks: Designing a Proxmox & systemd Sandbox](https://tappers.hashnode.dev/air-gapped-proxmox-systemd-agent-sandbox)
* 🕸️ **Previous (`E04`):** [Single Loops vs. Directed Graphs for AI Coding Agents: Cutting Input Tokens by 74.4% Without Losing Accuracy](https://tappers.hashnode.dev/e04-loops-vs-graphs)
* 🧪 **Next (`E06`):** [Why AI Agents Write Weak Tests for Their Own Code: Single-Agent TDD vs. Two-Agent Blind TDD (0% vs. 100% Mutant Kill Rate)](https://tappers.hashnode.dev/e06-blind-tdd-worktrees)
