Expand description
Capability scoping — the granted MCP subset, interpreted as a Rule-of-Two trust budget.
agentd has no policy engine; a subagent’s authority is the subset of MCP servers/tools its parent grants. Two invariants this module encodes:
- Monotonic narrowing. A child’s scope is the intersection with its parent’s — a child can never widen beyond what its parent holds. Because narrowing only ever shrinks, a check made over the root grant bounds every descendant, which is what lets the trifecta gate run once at startup rather than at every spawn.
- Rule of Two. Servers and tools are tagged
untrusted_input/sensitive/egress; granting one agent all three legs of the lethal trifecta is refused unless the operator overrides it (security.allow_trifecta).
Everything here is pure logic with no I/O; callers apply it. Config
validation folds the whole root grant, so startup and --validate-config
can never reach different verdicts, and the subagent.run tool folds the
child’s requested server subset before minting the child.
Structs§
- Tool
Scope - A subagent’s tool scope: which MCP servers it may reach, and (optionally) which tools within them. Both must pass for a call to be allowed.
- Trifecta
- The three legs of the “lethal trifecta”. An agent holding all three — it reads untrusted content, can touch sensitive data, and can send data out — is the dangerous combination: one injected instruction in the content it reads is enough to make it fetch a secret and forward it.
Enums§
- Rule
OfTwo - The verdict on a grant.
Ok≤ 2 legs; all 3 legs →Refuse(orWarnwith--allow-trifecta). - Scope
- A whitelist over names: everything, or an explicit set.
BTreeSetfor deterministic ordering (stable logs/serialization). - Trifecta
Tag - One leg of the lethal trifecta — an operator-declared risk capability a tool carries. Tags come from the operator’s own config and nowhere else: never from a tool description, a model’s claim about itself, or anything an MCP server advertises, because a server able to tag itself could simply declare itself harmless and buy back the leg it was meant to be charged.
- Trifecta
Verdict - The verdict on a grant’s trifecta exposure. A refusal is never a crash — each caller turns it into an outcome its layer can act on:
Functions§
- check_
trifecta - Pure Rule-of-Two check. Folds the tags of a granted tool set (
ORacross legs) and judges the accumulated budget: - evaluate
- Evaluate a grant’s trifecta exposure. The Rule of Two is satisfied at ≤2
legs; 3 legs violates it — refused unless
allow_trifectadowngrades the refusal to a loud warning.