You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow a principal holding a grant to delegate a strictly narrower version of it to another principal (e.g., an orchestrator delegating to a sub-agent), producing a child token whose constraints are provably a subset of the parent's, with the full delegation chain recorded and revocable as a unit.
Why this matters
Multi-agent systems are the dominant emerging pattern (orchestrator → specialist sub-agents, A2A-style delegation), and "how do I scope what my sub-agent can do?" currently has no good answer at the tool-call layer. Monotonic attenuation is the classic strength of the capability model — supporting it makes the kernel's security model genuinely distinctive, and it composes directly with the federation work that already exists.
child constraints must be equal-or-narrower on every axis (TTL ≤ parent remaining TTL, rows/fields ⊆ parent, scope ⊆ parent, same capability_id);
any widening attempt raises a typed error with a stable reason.
Token payload records parent_token_id and delegation_depth; configurable max_delegation_depth (default small, e.g. 2).
Policy hook: DefaultPolicyEngine may deny delegation per capability/safety class (e.g., DESTRUCTIVE not delegable by default).
Revocation cascades: revoking a parent invalidates all descendants.
ActionTrace for a delegated invocation records the delegation chain (token ids only, no payloads).
Docs: a "delegation" section in docs/capabilities.md + runnable offline example with an orchestrator and a sub-agent principal.
Implementation notes
Token model and HMAC signing: src/weaver_kernel/tokens.py (CapabilityToken, HMACTokenProvider). Child tokens are signed normally; verification additionally walks parentage for revocation (requires revocation store lookups by token id — composes with the persistence work).
Constraint-narrowing comparison should reuse the grant-constraint logic already enforced on handle expansion (handles.py, HandleConstraintViolation) rather than inventing a second subset checker.
Invariant I-06 (tokens bind principal + capability + constraints; no reuse across principals) is the heart of this feature: the child token is bound to the child principal — delegation mints a new binding, never shares the parent token.
Policy placement: delegation checks in policy.py must run after sensitivity checks (rule-order trap in AGENTS.md).
Tests: narrowing enforced per axis; widening rejected (type + message asserted); cascade revocation; depth limit; delegated invocation produces a trace with the chain.
Acceptance criteria
delegate() mints child tokens that are verifiably narrower on every constraint axis.
Any widening attempt fails with a typed error and stable denial reason.
Parent revocation invalidates all descendant tokens.
Delegated invocations are traceable end-to-end via kernel.explain() (chain of token ids).
Offline example + docs section added; CHANGELOG updated.
No weakening of I-06; existing token tests still pass.
Out of scope
Cross-kernel delegation (tokens remain kernel-scoped per the federation design; cross-kernel trust stays manifest-based).
Capability composition (combining two capabilities into one grant).
Macaroon-style offline attenuation without kernel involvement — worth a design note, not this issue.
References
Capability-systems literature on attenuation (e.g., macaroons, object-capability model) as neutral background.
Summary
Allow a principal holding a grant to delegate a strictly narrower version of it to another principal (e.g., an orchestrator delegating to a sub-agent), producing a child token whose constraints are provably a subset of the parent's, with the full delegation chain recorded and revocable as a unit.
Why this matters
Multi-agent systems are the dominant emerging pattern (orchestrator → specialist sub-agents, A2A-style delegation), and "how do I scope what my sub-agent can do?" currently has no good answer at the tool-call layer. Monotonic attenuation is the classic strength of the capability model — supporting it makes the kernel's security model genuinely distinctive, and it composes directly with the federation work that already exists.
Proposed scope
Kernel.delegate(parent_token, child_principal, constraints=...) -> CapabilityToken:parent_token_idanddelegation_depth; configurablemax_delegation_depth(default small, e.g. 2).DefaultPolicyEnginemay deny delegation per capability/safety class (e.g., DESTRUCTIVE not delegable by default).ActionTracefor a delegated invocation records the delegation chain (token ids only, no payloads).docs/capabilities.md+ runnable offline example with an orchestrator and a sub-agent principal.Implementation notes
src/weaver_kernel/tokens.py(CapabilityToken,HMACTokenProvider). Child tokens are signed normally; verification additionally walks parentage for revocation (requires revocation store lookups by token id — composes with the persistence work).handles.py,HandleConstraintViolation) rather than inventing a second subset checker.policy.pymust run after sensitivity checks (rule-order trap in AGENTS.md).Acceptance criteria
delegate()mints child tokens that are verifiably narrower on every constraint axis.kernel.explain()(chain of token ids).Out of scope
References
federation.pyfor the cross-kernel boundary this issue deliberately respects.Priority: P1 · Effort: L · Impact: High