# Swarm agent (/docs/swarm-agent)



A swarm agent is the shape that pushes the runtime's recursive
contract: one user turn fans out into dozens or hundreds of
subagents, each of which may spawn its own. Kimi K2-style deep
sequential loops, OpenAI Deep Research-style parallel fan-out,
AutoGen / LangGraph supervisor topologies, Claude Code-style
recursive delegation — different topologies, same buyer cohort,
same runtime stress.

The load-bearing pain is the runaway-loop case. A buggy fan-out
or a stuck sequential loop can spend a five-figure budget in one
user turn. This page walks the cost ceiling at the root-turn
boundary, the session-tree audit walk that attributes every
descendant call back to the originating turn, and the
concurrency primitives a swarm host reaches for.

**Related shapes.**
[Research agent](/docs/research-agent) for the canonical
single-anchor / bounded-subagent pattern — the swarm shape
inherits its primitives and pushes them further.
[Coding agent](/docs/coding-agent) if the subagents run code in
sandboxes.
[Multi-tenant SaaS agent](/docs/multi-tenant-saas-agent) if one
runtime serves many customers, each driving their own swarm.

## What you're building [#what-youre-building]

A turn loop whose recursion is bounded by construction, not by
hope:

* Every subagent — including subagents-of-subagents — carries
  the originating user turn's `turnId` and its own
  `subagentDepth`. The whole tree is one query against the
  ledger.
* A per-root-turn cost ceiling aborts the turn when cumulative
  spend crosses the line. The ledger records the cutoff.
* A fan-out cap limits how many subagents one node can spawn at
  once. A recursion-depth cap limits how deep the tree can go.
* Concurrency primitives — `race`, `waitAll`, `waitN`,
  `bounded`, `backpressure` — handle the structural cases a
  swarm host actually hits.

## Cost ceiling at the root-turn boundary [#cost-ceiling-at-the-root-turn-boundary]

The cost ceiling is the load-bearing protection for a swarm.
Today `@pleach/core` ships the structural caps — `maxDepth`,
`maxConcurrent`, `maxPerTurn`, `timeoutMs` — as hard ceilings
the substrate enforces independently of consumer config. A
per-root-turn USD ceiling is on the roadmap (see below); until
it lands, hosts enforce the dollar cap out-of-band against the
audit ledger.

```typescript
import {
  SessionRuntime,
  SUBAGENT_LIMITS,
  AiSdkProvider,
  createSupabaseAdapter,
} from "@pleach/core";

const runtime = new SessionRuntime({
  storage: createSupabaseAdapter({ client: supabase }),
  userId:  "user_123",
  tenantId: "tenant_abc",

  enableSubagentConcurrency: true,
  // SUBAGENT_LIMITS.maxConcurrent is the substrate-enforced
  // ceiling (3); consumer values above the ceiling clamp down.
  maxConcurrentSubagents: SUBAGENT_LIMITS.maxConcurrent,

  orchestratorConfig: {
    provider: anchorProvider,
  },
});

// Out-of-band USD ceiling, polled by the host against the
// audit ledger. `@pleach/compliance/education` ships a
// per-session helper for the single-process case; for swarms
// that span multiple processes, back it with a tenant-scoped
// store and check on each turn boundary.
import { createCostCapPolicy } from "@pleach/compliance/education";

const costCap = createCostCapPolicy({
  ceilingUsd: 25,
  onBreach:   () => runtime.abort(),
});
```

`SUBAGENT_LIMITS` carries the substrate-side hard caps:

| Cap             | Value     | Effect when breached                                              |
| --------------- | --------- | ----------------------------------------------------------------- |
| `maxDepth`      | `3`       | Spawn rejected — fourth nested runtime never starts               |
| `maxConcurrent` | `3`       | New spawns queue until a slot frees                               |
| `maxPerTurn`    | `5`       | Sixth spawn in a turn is rejected                                 |
| `timeoutMs`     | `120_000` | Subagent emits `subagent.failed` with `terminalStatus: "timeout"` |

The recursion is bounded structurally, not by per-subagent
prompts. A subagent that doesn't know about the cap can't escape
it.

## What today ships [#what-today-ships]

Today, `@pleach/core` ships:

* Recursive `SessionRuntime` sessions — every subagent is itself
  a `SessionRuntime`, with the same primitives the root has.
* `AuditableCall` typed audit-ledger rows — every spawn writes
  a row that ties the child session back to the parent turn.
* `parent_turn_id` and `subagent_depth` columns on the audit
  ledger — the tree walk is one recursive CTE.
* `SUBAGENT_LIMITS` for depth, parallel fanout, and total
  subagent count.

For the canonical anchor → bounded subagent fan-out pattern, see
[Research agent](/docs/research-agent).

## Roadmap [#roadmap]

The deeper swarm surface lands incrementally:

* **Per-root-turn cost ceiling.** `maxCostUsdPerTurn` is on the
  roadmap as a first-class limit. Until it lands, hosts enforce
  the ceiling out-of-band — a polling read against
  `harness_auditable_calls` filtered by `parent_turn_id`, with
  the host calling `runtime.abort()` when the cumulative spend
  crosses the budget. `@pleach/compliance/education` ships a
  `createCostCapPolicy({ ceilingUsd, onBreach })` helper for the
  per-session shape (single-process / in-memory by default;
  swap in a tenant-DB backing store for multi-process) — it does
  not yet aggregate by `parent_turn_id` but is sufficient when
  the swarm root is a 1:1 session.
* **Concurrency primitives.** A `@pleach/core/spawn` subpath
  with `race`, `waitAll`, `waitN`, `bounded`, and
  `backpressure` primitives that absorb the topology a swarm
  host already wrote in user space. Until it lands, hosts
  compose the same shapes with `Promise.all`, `Promise.race`,
  and a host-side semaphore.
* **Session-tree audit walker.** A `@pleach/replay` helper that
  walks the recursive CTE shown below into a structured object
  and serializes it for offline review. The SQL is the same;
  the helper saves the join glue.
* **Deterministic spawn-order replay.** A `spawnIndex` on
  `SpawnTreeState` that normalizes parallel-spawn ordering
  for byte-identical replay across the tree.
* **Per-subagent cost ceilings.** A nested cap that lets one
  branch of the tree have its own budget without blocking the
  rest. Lands after the root-turn ceiling is in soak.

No dates. Track the upstream package READMEs and CHANGELOG for
landing notices.

## The session-tree audit walk [#the-session-tree-audit-walk]

Every subagent's audit rows carry `parent_turn_id` and
`subagent_depth`. The whole tree — sequential loops, parallel
fan-out, recursive delegation — reads as one recursive CTE.

```sql
with recursive tree as (
  select turn_id, parent_turn_id, subagent_depth,
         tool_name, model_id, input_tokens, output_tokens
  from harness_auditable_calls
  where turn_id = $1
  union all
  select c.turn_id, c.parent_turn_id, c.subagent_depth,
         c.tool_name, c.model_id, c.input_tokens, c.output_tokens
  from harness_auditable_calls c
  join tree t on c.parent_turn_id = t.turn_id
)
select
  subagent_depth,
  count(*)                                  as calls,
  sum(input_tokens + output_tokens)         as tokens
from tree
group by subagent_depth
order by subagent_depth;
```

The query reads the whole investigation top-down: depth 0 is the
anchor turn; depth N is the deepest spawn. A regulator asking
"what did the agent do for user turn T" gets the full tree in
one read.

## Topology-neutral primitives [#topology-neutral-primitives]

The runtime doesn't have a topology opinion. The same
primitives — recursive sessions, the ledger tree, the cost
ceiling, the spawn record — absorb four different shapes:

| Topology             | What the host writes               | What the runtime stamps          |
| -------------------- | ---------------------------------- | -------------------------------- |
| Deep sequential loop | a long tool-loop in one subagent   | `subagent_depth = 1`, many rows  |
| Parallel fan-out     | N subagents spawned at the anchor  | `subagent_depth = 1`, N siblings |
| Supervisor / worker  | supervisor spawns workers per task | `subagent_depth = 1` or 2, tree  |
| Recursive delegation | subagent spawns its own subagent   | `subagent_depth = N`, deep tree  |

A swarm host picks the topology; the runtime makes the audit
walk identical across all four.

## Where to go next [#where-to-go-next]

<Cards>
  <Card title="Subagents" href="/docs/subagents" description="The spawn surface, the SpawnTreeState shape, and SUBAGENT_LIMITS." />

  <Card title="Research agent" href="/docs/research-agent" description="The canonical anchor → bounded subagent fan-out pattern that the swarm shape extends." />

  <Card title="Audit ledger" href="/docs/audit-ledger" description="The harness_auditable_calls schema and the parent_turn_id column the tree walk reads from." />

  <Card title="Channels" href="/docs/channels" description="Per-subagent stream isolation so the UI can render the tree without rebuilding it." />

  <Card title="Coding agent" href="/docs/coding-agent" description="The swarm shape when the subagents run code in sandboxes." />

  <Card title="Multi-tenant SaaS agent" href="/docs/multi-tenant-saas-agent" description="Per-tenant runtime construction when each tenant drives its own swarm." />
</Cards>
