Delegate authority
Give a sub-agent a bounded slice of what the parent holds, and nothing more.
A supervisor agent fans work out to workers. Each worker should be able to do its piece and nothing else. That is a delegation.
#Create one
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-3' \
-d '{
"from_agent_id": "agt_supervisor",
"to_agent_id": "agt_worker_3",
"capabilities": ["refund.create"],
"max_amount": 50000,
"currency": "INR",
"expires_at": "2026-10-10T00:00:00.000Z",
"max_depth": 0,
"reason": "Batch refund processing for the 2026-10 damage claims queue"
}'
from_agent_idstringrequiredThe parent. Must itself hold everything being delegated.
to_agent_idstringrequiredThe child.
capabilitiesstring[]requiredA subset of the parent's. Never an addition.
max_amountnumberoptionalMinor units. At most the parent's ceiling.
expires_atISO-8601requiredAt or before the parent's expiry. Set it to when the work ends.
max_depthnumberoptionalFurther hops permitted.
0means the child cannot sub-delegate.reasonstringoptionalRecorded in the audit trail. Worth filling in — in three months this is the only thing that explains why the grant exists.
#Check first
bashcurl -X POST https://veefore.example.com/v1/delegations/simulate \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{
"from_agent_id": "agt_supervisor",
"to_agent_id": "agt_worker_3",
"capabilities": ["refund.create", "payout.initiate"],
"max_amount": 200000
}'
Tells you whether it would be permitted and which bound it violates. Cheaper
than discovering it from a 403, and it is what the console calls as you fill
in the form.
A child can never exceed its parent
Asking for a capability the parent does not hold, an amount above its ceiling,
or an expiry past its expiry is refused with DELEGATION_ESCALATION —
refused, not silently clamped.
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.
#See what a worker can actually do
bashcurl -s https://veefore.example.com/v1/agents/agt_worker_3/authority \
-H "Authorization: Bearer $VEEFORE_API_KEY"
Returns the resolved effective authority after intersecting every hop.
Narrowing anywhere narrows everything below
If the root grants ₹100,000 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. The effective value at each dimension is the narrowest in the chain, not the nearest.
This is the usual cause of "the delegation says 100000 but we get
AUTHORITY_EXCEEDED at 60000". Read the resolved authority, not the individual
grant.
#Handle it in the agent
A delegation is not something the child agent passes as a parameter. It is resolved server-side from the agent's identity, at stage 6 of every pipeline run. The worker just acts:
tsconst worker = protect(workerAgent, { name: 'refund-worker-3' });
try {
await worker.act({
tool: 'refund_customer',
capability: 'refund.create',
amount: 60_000,
currency: 'INR',
parameters: { orderId: 'ord_8812' },
});
} catch (error) {
if (error instanceof VeeforeBlockedError) {
// AUTHORITY_EXCEEDED arrives here. The details carry the ceiling and the
// requested amount, so the worker can report something useful.
return { status: 'over_ceiling', reason: error.message };
}
throw error;
}
The error details include the capability, the ceiling and what was requested,
so a worker can report "requested 60000, ceiling is 50000" rather than
"forbidden".
#Shape the topology
Depth 0 at the leaf. A worker that can sub-delegate is a worker whose
authority you no longer fully know. Set max_depth: 0 unless you have a
specific reason.
Short expiries. A delegation for a batch job should expire when the batch does. An open-ended grant is a standing permission with extra steps.
One delegation per purpose. Two delegations with clear reasons beat one broad grant that covers both, because revoking one does not affect the other.
Narrow the ceiling to the work. If the batch's largest claim is ₹400, do not grant ₹50,000 because it was a round number.
#Revoke
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": "Batch complete" }'
Cascades to everything derived from the grant, 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.
Narrowing is also allowed and takes effect immediately:
httpPATCH /v1/delegations/{delegationId}
Widening is refused. To grant more, create a new delegation from a parent that actually holds that authority.
#See the graph
bashcurl -s https://veefore.example.com/v1/delegations/graph \
-H "Authorization: Bearer $VEEFORE_API_KEY"
Nodes and edges for the whole graph. The console renders it on the Delegations page, and it is the fastest way to answer "what can this agent reach, and through whom" — a question that is hard from a list and obvious from a graph.
#Policy on delegation shape
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." }
}
Available fields: authority.max_amount, authority.capabilities,
authority.depth, delegation.depth, delegation.chain_length,
delegation.valid.