Delegated authority
Bounded, time-limited, revocable grants that can never exceed their parent — the one invariant the whole model rests on.
A delegation is a grant of authority from one principal to another, narrowed and bounded. A human delegates to an agent. An agent delegates to a sub-agent. The sub-agent delegates to a worker. Each hop is recorded, each is constrained, and each can be revoked.
The whole thing rests on one rule.
A child can never exceed its parent
Not "should not". Cannot. A delegation that asks for a capability the parent does
not hold, an amount above the parent's ceiling, an expiry past the parent's
expiry, or a scope wider than the parent's scope is refused with
DELEGATION_ESCALATION.
It is refused rather than silently clamped, because silent clamping means the caller believes it has authority it does not have, and finds out at the worst possible moment. An explicit failure at grant time is strictly better than a surprise at use time.
#What a delegation carries
| What it bounds | |
|---|---|
| Capabilities | A subset of the parent's. Never an addition. |
| Amount ceiling | Minor units. At most the parent's ceiling. |
| Scope | Organization, workspace, environment, agent or tool. Never broader than the parent's. |
| Expiry | At or before the parent's expiry. |
| Depth | How many further hops are permitted. |
| Constraints | Extra conditions: destinations, resources, time windows. |
bashcurl -X POST https://veefore.example.com/v1/delegations \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-H 'Idempotency-Key: delegate-refunds-to-worker' \
-d '{
"from_agent_id": "agt_supervisor",
"to_agent_id": "agt_worker",
"capabilities": ["refund.create"],
"max_amount": 50000,
"currency": "INR",
"expires_at": "2026-10-10T00:00:00.000Z",
"max_depth": 0
}'
max_depth: 0 means the worker cannot delegate onward. That is usually what you
want at the leaf: a worker that can sub-delegate is a worker whose authority you
no longer fully know.
#Check before you grant
httpPOST /v1/delegations/simulate
Tells you whether a delegation would be permitted, and if not, which bound it
violates. Cheaper than discovering it from a 403, and it is what the console
calls as you fill in the form.
#Resolution at request time
Stage 6 of the pipeline resolves the chain:
- Walk from the acting agent up to the root grant.
- Check every hop is still valid — not revoked, not expired, issuer still operational.
- Intersect the constraints of every hop. The effective authority is the narrowest value at each dimension, not the nearest.
- Compare the request against the result.
Point 3 is the one that catches people. If the root grants a ₹100,000 ceiling and an intermediate hop narrowed it to ₹50,000, the leaf's ceiling is ₹50,000 — even if the leaf's own grant says ₹100,000. Narrowing anywhere in the chain narrows everything below it, permanently, for as long as that hop exists.
Described in text
The root grants ₹1,000,000, a supervisor narrows it to ₹100,000, and a team
agent narrows it again to ₹50,000. The worker's own grant says ₹100,000 and its
effective ceiling is still ₹50,000. This is the usual cause of "the delegation
says 100000 but we get AUTHORITY_EXCEEDED at 60000".
bashcurl -s https://veefore.example.com/v1/agents/agt_worker/authority \
-H "Authorization: Bearer $VEEFORE_API_KEY"
returns the resolved effective authority — what the agent can actually do right now, after every intersection. When an agent is refused and nobody can work out why, this is the first thing to read.
#Refusals
| Code | Cause |
|---|---|
DELEGATION_ESCALATION |
The grant asked for more than the parent holds. Refused at creation. |
DELEGATION_INVALID |
The chain does not resolve: a hop was revoked, or an issuer is no longer operational. |
DELEGATION_EXPIRED |
A hop's expiry has passed. |
AUTHORITY_EXCEEDED |
The chain resolved and the request is outside it. |
AUTHORITY_EXCEEDED is the common one in normal operation, and the error
details carry the capability, the ceiling and what was requested, so the agent
can report something useful instead of "forbidden".
#Narrowing and revoking
Reducing a delegation is allowed and takes effect immediately:
httpPATCH /v1/delegations/{delegationId}
Widening is refused — same invariant, same error. To grant more, create a new delegation whose parent actually holds that authority.
Revocation cascades:
bashcurl -X POST https://veefore.example.com/v1/delegations/del_01ABC/revoke \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{ "reason": "Supervisor agent decommissioned" }'
Everything derived from that grant dies with it, at every depth, immediately. No grace period and no draining. A cascade that waits is a cascade that does not work when you need it.
#Seeing the shape of it
httpGET /v1/delegations/graph
Nodes and edges for the whole delegation graph. The console renders it on the Delegations page, and it is the fastest way to answer "what can this agent actually reach, and through whom" — a question that is hard to answer from a list of rows and obvious from a graph.
#Depth is bounded on purpose
An unbounded chain is a reasoning problem and a performance problem. Every hop is another set of constraints to intersect and another record to check for revocation. More importantly, a human reviewing authority four hops deep cannot realistically tell you what the leaf can do.
Set max_depth to the smallest number that works. Most useful topologies are
two or three deep.
#Policy fields
| Field | Use |
|---|---|
authority.max_amount |
The resolved ceiling |
authority.capabilities |
The resolved capability set |
authority.depth |
Depth backing the authority |
delegation.depth |
Depth of the delegation used |
delegation.chain_length |
Number of hops |
delegation.valid |
Whether resolution succeeded |
A useful rule: require approval whenever an agent acts near the top of its ceiling.
json{
"id": "rule-near-ceiling",
"name": "Approval near the authority ceiling",
"priority": 700,
"enabled": true,
"when": {
"kind": "group",
"id": "g-near-ceiling",
"operator": "and",
"children": [
{ "kind": "condition", "id": "c-amount", "field": "amount", "operator": "gt", "value": 40000 },
{
"kind": "condition",
"id": "c-ceiling",
"field": "authority.max_amount",
"operator": "lte",
"value": 50000
}
]
},
"then": {
"decision": "REQUIRE_APPROVAL",
"reason": "Request is close to the delegated ceiling.",
"approval": { "routingMode": "SINGLE", "requiredApprovals": 1, "ttlSeconds": 900 }
}
}
Another: refuse deep chains for anything dangerous.
json{
"id": "rule-deep-chain-dangerous",
"name": "Dangerous tools need direct authority",
"priority": 850,
"enabled": true,
"when": {
"kind": "group",
"id": "g-deep-dangerous",
"operator": "and",
"children": [
{
"kind": "condition",
"id": "c-dangerous",
"field": "tool.dangerous",
"operator": "is_true"
},
{
"kind": "condition",
"id": "c-chain",
"field": "delegation.chain_length",
"operator": "gt",
"value": 2
}
]
},
"then": { "decision": "BLOCK", "reason": "Dangerous tools require direct authority." }
}