{"slug": "an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions", "title": "An Agent That Can Spawn Agents Is a Fork Bomb With Good Intentions", "summary": "A developer warns that giving AI agents the ability to spawn sub-agents without limits creates a recursive fork bomb pattern, leading to runaway costs and resource exhaustion. The post, written by the creator of agentproto, argues that spawning must be a metered privilege with depth and breadth caps, not an unbounded capability. The fix is privilege-gated spawning where child agents cannot exceed their parent's permissions.", "body_md": "Disclosure up front: I build\n\n[agentproto], one of the\n\ntools in this market. The primitives in the back half are real and the fields\n\nare checkable; the problem in the front half is everyone's. Corrections\n\nwelcome — file an issue.\n\nHere's the multi-agent dream, and it's a good one: you hand one capable agent a\n\nbig task, and instead of grinding through it alone, it spins up a little team —\n\none sub-agent to research, two to implement in parallel, one to review — waits for\n\nthem all, and hands you the merged result. An orchestrator that manages\n\norchestrators. It works, and it's genuinely powerful.\n\nNow read that sentence again with an engineer's paranoia. *An orchestrator that\nmanages orchestrators.* If an agent can spawn agents, then the agents it spawns\n\nYou already know this shape. It's the oldest prank in the Unix book:\n\n```\n:(){ :|:& };:   # a function that calls two copies of itself, forever\n```\n\nThat's a fork bomb. It does nothing malicious — each copy just politely starts\n\ntwo more, until the process table is full and the machine is on its knees. A\n\ncoding agent with an unbounded spawn tool is the same structure with a language\n\nmodel in the middle and your API bill underneath.\n\nThe one idea, if you remember nothing else:\n\nSpawning isn't a feature you turn on. It's a privilege you grant — and a\n\nprivilege with no depth, no breadth, and no ceiling is a fork bomb with good\n\nintentions.\n\nWhen you give an agent a `spawn_sub_agent`\n\ntool, you're not just adding a\n\ncapability. You're granting it the right to grant *itself* the same capability,\n\nrecursively, as many times as its reasoning talks it into. Most setups make that\n\ngrant implicitly and totally: if the tool is in the toolset, spawning is\n\nunlimited — any depth, any number of children, and each child just as privileged\n\nas the parent.\n\nTwo things make that expensive fast, and neither is hypothetical. First, cost.\n\nAnthropic's own guidance on sub-agents is that you isolate exploration in them\n\nprecisely because **each one can burn ten thousand tokens to hand back a\nfive-line summary** — cheap when it's one, a bonfire when a confused parent\n\nThe receipt that should slow you down.The sharpest orchestration writers\n\nconverge on one rule:the number of agents a job spawns is the **output* of\n\nthe orchestration decision, not the input.* You don't pick a multi-agent\n\nworkflow because you can — you pick it because the work's shape demands it. An\n\nagent that spawns because spawning is available has skipped the only decision\n\nthat mattered.\n\nSo the problem isn't multi-agent orchestration. It's *ungoverned* spawning —\n\nhanding an LLM a recursive, self-replicating capability and trusting its judgment\n\nto not run it off a cliff. The fix isn't \"don't spawn.\" It's \"make spawning a\n\nmetered privilege.\"\n\nPlace yourself honestly before you build. Four postures, each with a ceiling.\n\n**Unbounded.** Any agent holding the spawn tool spawns freely — any depth, any\n\ncount. Powerful, and one confused reasoning loop from a runaway tree and a bill\n\nwith a comma you didn't expect. *Ceiling: the first agent that decides the answer\nto \"this is hard\" is \"spawn more agents.\"*\n\n**Concurrency-capped by hand.** You cap how many agents run at once, in your own\n\nharness code, watching a dashboard. Better — but it's your attention doing the\n\ncapping, and it doesn't stop *depth*, just width at one instant. *Ceiling: you,\nwatching.*\n\n**Worktree-isolated only.** You give each parallel agent its own git worktree so\n\nthey don't stomp each other's files — the near-universal isolation trick, and a\n\ngood one. But a worktree isolates the *filesystem*, not the *right to spawn*. A\n\ntidily-isolated agent can still fork-bomb. *Ceiling: clean files, unbounded tree.*\n\n**Privilege-gated.** Spawning is a role, capped by depth and breadth, and a child\n\ncan never grant itself more than the parent had. *This is the one that can't run\naway, and it's the one you can declare instead of police.*\n\nWhere are you?If your honest answer is\"any agent with the tool can spawnyou don't have orchestration — you have a fork bomb that\n\nas much as it wants,\"\n\nhasn't gone off yet. The rest of this is four bounds that make sure it never\n\ndoes.\n\nThe first bound is the bluntest: most agents in a tree should be *leaves* that\n\nphysically cannot delegate. In agentproto that's a spawn-time role.\n\n```\n// this child does the work and CANNOT spawn — the spawn tools are removed\nagent_start({\n  adapter: \"claude-code\",\n  role: \"executor\",        // leaf: agent_start / agent_prompt are stripped\n  cwd: \"/abs/host/path\",\n  prompt: \"Implement the retry cap in src/payments/retry.ts. Do not delegate.\"\n})\n```\n\nAn `executor`\n\nis a leaf by construction: the `agent_start`\n\nand `agent_prompt`\n\ntools are **stripped from its toolset**, and asking it to become an orchestrator\n\nis simply ignored — no amount of clever prompting gives it back the ability to\n\nspawn, because the capability isn't in the room. A `supervisor`\n\nmay delegate.\n\nThat single distinction turns \"every agent is a potential parent\" into \"spawning\n\nis a named privilege that most of the tree doesn't hold.\"\n\nThis is the same lesson the OWASP Agentic Top 10 files under **least agency**:\n\ngive an agent only the autonomy its task needs. A worker implementing a function\n\ndoesn't need the right to raise an army. Take it away, and a whole class of\n\nrunaway trees becomes unrepresentable.\n\nLeaves can't spawn, but supervisors can, and a chain of supervisors is still a\n\nrecursion. So the second bound caps how *deep* the tree can go, and makes the cap\n\none-directional.\n\n```\nagent_start({\n  role: \"supervisor\",\n  orchestrator: { maxDepth: 3, maxChildren: 8 },   // this subtree, bounded\n  // …\n})\n```\n\n`maxDepth`\n\ndefaults to **3** and has a **hard ceiling of 8** — a spawn that would\n\nexceed it is rejected outright, not queued. The load-bearing detail is the\n\ndirection: **a recursive spawn can only lower the inherited cap, never raise\nit.** A parent at depth 3 can hand a child a budget of 2; that child cannot hand\n\nDepth stops the tree going infinitely *down*; breadth stops any one node\n\nexploding *sideways*. `maxChildren`\n\ndefaults to **8** concurrently-alive\n\nsub-agents per parent and, like depth, a recursive spawn can only lower the\n\ninherited quota — never raise it.\n\nThat's the direct antidote to the `:|:`\n\nin the fork bomb — the part where one\n\nprocess becomes two becomes four. Cap the branching factor and the geometric\n\nexplosion can't start. Combined with depth, your worst case is now a *known*\n\nnumber of agents (`maxChildren ^ maxDepth`\n\n, and shrinking as it descends), not an\n\nopen-ended one. You can look at a spawn config and say exactly how bad a confused\n\nrun gets. That sentence is impossible in the unbounded world.\n\nCost gets its own hard stop.Independently of the tree shape, each session\n\ntakes`maxCostUsd`\n\n— a cumulative dollar ceiling; the session is stopped at the\n\nnext turn-end once it's exceeded. Depth and breadth bound thecount; this\n\nbounds thespenddirectly, so even a legal-sized tree of expensive turns has a\n\nnumber it can't cross.\n\nThe last bound is the subtle one, and it's what makes the other three trustworthy:\n\na child can never end up *more* powerful than the parent that made it. The daemon\n\nenforces a privilege lattice — a spawn made through an orchestrator may only\n\ncreate a role at or below the caller's own level, never something more privileged,\n\nand an explicit `tools`\n\nallowlist can only ever *narrow* the toolset, never widen\n\nit. **A child can never grant itself scope its parent didn't have.**\n\nAnd the parent's view is boxed, too. The daemon mints a **per-child scope-token**,\n\ninjects a scoped sub-gateway into that child's session, and **revokes the token\nwhen the session exits**. A parent's\n\n`session_tree`\n\nshows only Four bounds, one property: you can hand an agent the genuinely powerful ability to\n\nbuild and run a team, and still be able to state — before it runs — the maximum\n\ndepth, the maximum breadth, the maximum spend, and the ceiling on privilege. The\n\ncapability stays; the fork bomb becomes unrepresentable.\n\nReal infrastructure, real sharp corners. Four I hit live:\n\n`turn-end`\n\nis a transient event, so the wait\ntimes out on a child that already succeeded. Teach the parent the fallback: if\nthe wait times out, read the child's output to confirm, or take an event cursor\n`session_tree`\n\n), or you'll leak\nrunning agents.`cwd`\n\nmust be a real host pathAnd the fair comparison. Vendors do ship sub-agents — Claude Code's Agent Teams\n\nwill run a team for you, and inside one vendor's stack it's smooth and needs none\n\nof this wiring. Two things a built-in team doesn't give you: the spawn tree stays\n\ninside that vendor (your cheap open-model executors aren't invited), and the\n\ngovernance is theirs, not a set of depth/breadth/role/cost bounds you declare and\n\nown. If you live entirely in one vendor and never want a mixed fleet, take the\n\nbuilt-in — it's less work. If you want to spawn across vendors *and* sleep at\n\nnight, the bounds have to be yours.\n\nThe instinct to stop agents from spawning is the wrong lesson — spawning a team\n\nis exactly the leverage that makes agents worth orchestrating. The right lesson is\n\nthat a self-replicating capability handed to a probabilistic reasoner needs the\n\nsame thing every other powerful capability needs: limits it can't rewrite.\n\nSo grant the privilege deliberately. Make most agents leaves that can't delegate.\n\nCap the depth so the recursion has a floor. Cap the breadth so no node fans into a\n\nswarm. Cap the spend and the privilege so a child is always smaller than its\n\nparent. Do that and \"an agent that spawns agents\" stops being a fork bomb and\n\nstarts being what you actually wanted: a team with a foreman, and a foreman who\n\ncan't accidentally hire the whole city.\n\nLet the agent build its team. Just make sure the tree has a floor, the branches\n\nhave a limit, and the whole thing dies when the job's done.\n\nIf your orchestrator bounds spawning a cleaner way — or you've found a runaway\n\ntree these four bounds wouldn't have caught — tell me where. I'll fix the piece.\n\n*Written by the maintainer of agentproto (Apache-2.0,\nsource) — a local, cross-vendor daemon for\nrunning and governing coding agents. Same contract as our\n/compare page: dated facts, named strengths,\ncorrections by issue. Got something wrong?\nFile an issue.*\n\n*Building agentproto in the open — follow @theagentproto and @agentik_ai on X.*", "url": "https://wpnews.pro/news/an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions", "canonical_source": "https://dev.to/agentiknet/an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions-2kjh", "published_at": "2026-07-14 01:36:46+00:00", "updated_at": "2026-07-14 01:56:59.171824+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-infrastructure", "ai-tools", "developer-tools"], "entities": ["agentproto", "Anthropic", "Unix"], "alternates": {"html": "https://wpnews.pro/news/an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions", "markdown": "https://wpnews.pro/news/an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions.md", "text": "https://wpnews.pro/news/an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions.txt", "jsonld": "https://wpnews.pro/news/an-agent-that-can-spawn-agents-is-a-fork-bomb-with-good-intentions.jsonld"}}