- 12 stepsevery tool call passes, in a fixed order
- 22,600lines in the tools module, with its schema validator, tool kinds and built-ins
- 0commits by the coding agent straight to the main repository; the gatekeeper opens the merge
I make the safe path the only path, and I take flexibility away where flexibility would let an action skip a check.
One frozen path for every tool call
Agent Swarm runs agents that act on real systems. If every tool does its own validation, permission checks and logging, each new tool is a new place for a mistake, and nobody can audit a fleet of them. I decided there would be exactly one path for an action and that the path would be frozen. Every tool call, of every kind, goes through one Rust harness in a fixed order, and a tool marked as needing approval pauses the agent loop until approval arrives.
1 schema validation, strict mode and peer-call depth · 2 normalisation · 3 redaction before the pre-call hook · 4 authorisation · 5 rate limit · 6 resource quota · 7 timeout · 8 retry policy · 9 the tool's execute body · 10 sanitisation, size cap and credential scrub · 11 batched audit rows to PostgreSQL · 12 observation
Credential scrubbing and size caps run in the shared output step, so a careless tool body has a backstop. Agents call MCP methods directly, outside the tool kinds, which avoids wrapping one governance layer inside another.
The reasoning is in Tools are the platform.
A configurable pipeline is more flexible; a fixed one is something I can trust, because there is one way an action happens.
Tool kinds that carry their own guards
Most tools are YAML declarations, and each executable kind carries the guard its inputs need. A WASM extension kind is declared and the harness rejects it, because I would rather leave a kind unrunnable than ship it half-built with part of the pipeline bypassed. The test discipline is on the Agent tool qualification testing page.
A container for every persona
Agent Swarm also has to start agents somewhere they can do limited harm. Its persona launcher turns a declared persona into a Docker container. An agent cannot call what it was not granted and never holds a credential it does not need, and sensitive operations go to a gatekeeper agent that checks who is asking and applies its own policy, which adds separation of duties to narrow tokens.
A coding agent on a local open-weight model edited code on its own branch, ran the tests, pushed, and asked the gatekeeper agent to open the merge request: A coding agent that never holds the keys.