Skip to content
MCP Five

The CrewProject #432 / 51

Seatbelts, and why five

Recursion multiplies per-loop limits. The best of the five is an absence, not a counter.

Project #3 had seatbelts and they were all correct. Every one of them was scoped to one loop.

Recursion multiplies per-loop limits instead of adding them.

An orchestrator allowed ten iterations, that hires three workers allowed ten each, has quietly authorised forty API calls against conversations that keep growing. Nobody wrote that number down. It is the product of two limits that each looked reasonable alone.

The five

SeatbeltKind of limitFromWhat it catches that the others don't
MAX_ITERATIONS = 10per agent#2One agent spinning. Kept at ten on purpose โ€” raising it would have hidden the effect being measured.
MAX_CONCURRENT = 3ratenewThree-wide is a bill times three, not times sixty. The model may ask for more; they queue.
MAX_SPAWNS = 8quantitynewAn orchestrator that wants one agent per jar, hiring sixty of them three at a time, politely, within the concurrency cap.
MAX_TREE_TOKENSmoneynewThe only check that sees the whole bill. Shared by reference; workers spend from the boss's wallet.
no spawn_agent for workersstructuralnewInfinite recursion.

Five, because they catch five genuinely different failures. Note that the second and third look similar and are not: MAX_CONCURRENT bounds how many run at once, MAX_SPAWNS bounds how many run at all. An orchestrator can respect a concurrency cap perfectly while hiring sixty workers in sequence.

The one worth stealing

That last row.

There is no depth counter in this codebase. A sub-agent is started with delegate: false, so spawn_agent is not in its tool list at all.

ts
runAgentLoop({
  messages: [{ role: "user", content: briefing(task) }],
  toolbox: context.toolbox,
  gate: true,
  delegate: false,          // โ† cooks don't hire cooks
  budget: context.budget,
})

It cannot recurse for the same reason you cannot dial a phone number that was never printed.

Prefer a design where the bad thing is unreachable over a check that catches it.

What it costs

Honesty about the tradeoff, because this design is not free.

Two levels is a deliberate structural choice, not a limitation you can lift by changing a constant. Three levels needs a real depth counter, and at that point everything above gets harder: the counter has to survive pauses, the budget has to be attributed further down the tree, and the approval card has to explain a path rather than a parent.

So the design is honest about what it is: a two-level tree, enforced by construction, with the escape hatch clearly signposted as a bigger piece of work rather than a config change.

One wallet, shared by reference

MAX_TREE_TOKENS deserves its own note, because it is the only seatbelt that is not per-agent.

It is a single TreeBudget object passed down into every worker by reference, so that the sentence "the whole run stops at 600,000 tokens" is true rather than approximately true.