Delegation Scope Design Guide
API keys are a god-mode pattern. They mean unlimited access, no attribution, and no expiry — once leaked, the only fix is rotation. That model worked when the only thing holding the key was a server you owned. It does not work when the holder is an AI agent operating on a human's behalf.
HUMΛN replaces API keys with delegation tokens: a signed cryptographic contract that says "this human (or org) grants this agent these specific scopes for this specific window, with these specific constraints." The MCP surface enforces them on every call.
What a delegation actually is
A token has five fields:
| Field | Meaning |
|---|---|
from |
The principal granting authority (DID — passport or org). |
to |
The principal receiving authority (the agent's DID). |
scope |
The set of capabilities granted, as a list of scope strings. |
constraints |
Optional bounds — rate limits, IP ranges, time windows, value caps. |
expires_at |
A hard expiry; tokens never live forever. |
The token is signed with the granter's passport key, so the verifier doesn't need to call HUMΛN to check authenticity — they verify the signature and check the revocation registry.
The MCP scope vocabulary
These are the scopes you'll actually use day-to-day:
| Scope | Grants | Doesn't grant |
|---|---|---|
kb:read:public |
Read 58 Public-classified docs + Canon | Org-internal docs |
kb:read:internal |
Read Internal-classified docs (HUMΛN devs) | FoundersOnly |
companion:chat |
Multi-turn human.ask + human.companion.chat, and Companion preferences (/v1/companion/preferences + observe/pending/ack) |
KB ingest, arbitrary execution without other scopes |
human_api:agents:invoke |
POST /v1/agents/call — the human.call MCP tool (hosted Worker + API use the same scope string) |
Does not replace per-capability scopes or the risk gate |
humanos:read / humanos:write |
Intent / HumanOS REST routes (what /v1/intent actually checks; MCP human.intent needs humanos:write) |
Whatever the route policy does not cover |
(no call:propose / call:execute scopes) |
human.call uses a mode field (propose vs execute), not separate delegation strings |
See below |
human_api:passports:read |
Read passport data | Mutate passports |
human_api:passports:write |
Mutate passports | Cross-tenant |
org:settings:read |
Read org-level settings | Modify |
org:settings:write |
Modify org-level settings | Org admin operations |
cloud:admin:* |
Internal HUMΛN team — admin surfaces | Anything outside HUMΛN org |
There are more (event emit, marketplace, signals) — see the AI corpus article delegation-scope-vocabulary.md for the canonical list.
Principle of least privilege
Start with the smallest grant that lets your agent do something useful:
# A read-only Cursor companion
human delegation mint \
--to did:agent:my-cursor \
--scope "kb:read:public companion:chat" \
--expires-in 30d
Now your agent can answer questions and search the KB. It cannot do anything destructive. If it needs more, expand the scope — don't reach for a wildcard.
human.call is mode-aware (not two scopes)
The most consequential knob is human.call’s mode, not a pair of delegation scopes named call:propose / call:execute (those strings are not minted today).
mode: "propose"— surface a plan or dry-run outcome; your UI can still require an explicit approval step before a laterexecute.mode: "execute"— perform the action; the API risk gate still enforcesrequires_approvalon irreversible work, and plan tier may block cheap tiers from execute paths on the hosted Worker.
For autonomous workflows (cron jobs, daily summaries), execute on reversible operations may be appropriate when policy allows. For interactive tools (Cursor, Claude Code), default to propose first and let the human confirm before execute.
Constraints: the underrated lever
Constraints let you say "yes, but only..." A few useful ones:
{
"rate_limit": "60/min",
"value_cap_usd": 100,
"allowed_capabilities": ["calendar.events.create", "kb:search"],
"ip_allowlist": ["10.0.0.0/8"]
}
The agent gets the right of way and the speed limit.
Revoking without breaking everything
The Console's Settings → MCP Access page lists every active session. Revoke one and:
- The KV cache in the MCP Worker drops the session immediately.
- The API marks the session row revoked.
- Subsequent calls return
401withrevoked_atin the problem details. - Other agents (other rows) keep working.
Revocation is per-session, not per-key. You don't have to rotate one delegation to fix another.
Org-level vs user-level delegation
Most agents act for a specific user. But some — workflows, scheduled jobs, the org's automation runtime — act for the org. Their delegation has from: did:org:... instead of from: did:passport:.... The grant pattern is identical; the audit trail is different (provenance shows which org admin minted it, on whose behalf).
When in doubt: user-level. Org-level should be rare and should always have an admin's name attached in provenance.
Common mistakes
- Granting
*"just for testing." Never lands as "just for testing." Mint scoped tokens even in dev. - Forgetting
expires_at. A token without expiry is an API key with extra steps. - Mixing the same delegation across multiple integrations. Hard to revoke one without breaking the others. One agent → one delegation.
- Using
cloud:admin:*outside HUMΛN team. This surface is internal-only and gated; if you're not a HUMΛN dev, you'll get403.
Tooling
human delegation mint— create one (CLI).human delegation list— see what you've issued.human delegation revoke <id>— kill it.- Console → Settings → Delegations — same surface, click-friendly.
- Console → Settings → MCP Access — sessions specifically tied to MCP integrations.
Next
- Doc 4 — KB Access Control Explainer (what each classification means, who sees what).
- AI corpus:
/ai/articles/delegation-scope-vocabulary.md.