Capability Routing
An agent that hits the edge of its sandbox shouldn't hand the job back to you. MUR derives a dispatch index — who can run what — from the permissions the kernel actually enforces, so a blocked command finds an agent that can run it.
mur agent who # every agent, and what it can do
mur agent who --can cargo # who holds `cargo`, and where work can be delegated
mur agent who --skill rust # who has a matching skill
mur agent who --can git --as pm # evaluate dispatch permissions as another agent
Why the front-door agent holds no keys
Your concierge is the agent with the widest reach: unrestricted network, several writable repositories, always running — and it reads whatever you paste into it, including text from the web. That combination is exactly the one that shouldn't also be able to execute arbitrary code. cargo and npm run build scripts; a build script is arbitrary code.
So the concierge doesn't get those keys. A narrow specialist does — one repository, restricted egress, a short list of binaries. When the concierge needs a build, it delegates.
What the index is made of
Nothing here is declared in a separate list that someone has to maintain. A new agent appears the moment its profile exists, and it can never claim an ability the kernel would refuse.
| Layer | Comes from | Used to |
|---|---|---|
| Hard | entitlements — the binaries, paths, and network the sandbox enforces | Filter. Not in the allowlist means it physically cannot run |
| Soft | role, installed skills, model | Rank and explain. A label can be stale; it never decides |
| Authorization | fleet_run in ~/.mur/config.yaml | Decide what may be delegated to. Never inferred |
The three stay separate on purpose. A description can be out of date; a kernel allowlist cannot.
Reading the output
$ mur agent who --can cargo
Agents that explicitly hold `cargo`:
qa [running]
exec cargo, cargo-nextest, rustc, git
writes /repos/app, /repos/tools
net Restricted
rustsmith [running]
role Engineer
exec git, cargo, rustc
writes /repos/app
net Restricted
Dispatch routes for 'mur' (fleet_run), best first:
ready:
builder via rustsmith budget $1.00
blocked (capable, but not usable right now):
develop-rust via rustsmith, qa — not authorized for this agent
authorize: add "develop-rust" to fleet_run.fleets in ~/.mur/config.yaml
ready routes are ordered least-privileged first. Among the agents that can do the job, MUR prefers the one carrying the least unrelated power — otherwise every task drifts toward whichever agent can do everything, undoing the containment you set up elsewhere.
blocked routes are shown to you, not to the agent. A capable fleet you haven't authorized is a grant path when you read it and a target list when a compromised agent reads it. The agent only ever sees routes it may already use; the authorize line is for the human.
If an agent shows PROFILE EDITED SINCE START, its live permissions are not what its profile now says — restart it before relying on the row.
What an agent sees when it's blocked
The sandbox is compiled when an agent starts and enforced by the kernel, so there is no approval prompt for a denied binary — the exec simply fails. Instead of an opaque error, the agent gets the route:
[sandbox] `cargo` is not in agent 'mur''s spawn allowlist, so the kernel refused
to exec it. This is decided when the agent starts — there is no approval prompt
for it. DELEGATE it instead of asking the user: fleet_run(fleet="builder",
goal=<this exact command, with absolute paths>). Best first: "builder" (via
rustsmith).
To grant it here instead, the user runs: `mur agent perm allow-spawn mur cargo`
and restarts the agent.
The delegation then runs as a normal fleet job, so it inherits the guards that come with one: a budget ceiling, the mur fleet stop kill-switch, fail-closed approval, and a signed channel record of what ran.
Authorizing a route
Discovery is automatic; authorization is deliberate. A fleet becomes a valid delegation target only when you say so, in a file no agent can write:
# ~/.mur/config.yaml
fleet_run:
agents: [mur] # who may delegate
fleets: [builder, deep-research] # where they may delegate to
A fleet also needs a positive loop.budget_usd — an agent-triggered run without a spending ceiling is refused. Both lists are empty by default: nothing is delegable until you choose it.
Granting a binary directly
Sometimes the right answer is to widen the agent rather than route around it:
mur agent perm allow-spawn <agent> <binary>
mur agent restart <agent> # the sandbox is sealed at startup
Weigh it against what that agent already reaches. A binary that runs project-supplied code — cargo, npm, make — turns into arbitrary execution with that agent's full network and filesystem access.
See also
- Agent CLI — chatting with an agent, and approving its tool calls
- Capabilities — installing bundled MCP servers, skills, and program requirements