Use Cases
Delegating credentials to sub-agents
When your agent spawns a worker — a VM, a sub-process, a CI runner — it can share a subset of its permissions without exposing its own identity.
When to delegate
Multi-agent workflows
Parent agent orchestrates, sub-agents execute specific API calls.
Ephemeral VMs
Spin up a worker VM that needs GitHub access for 2 hours, then auto-expires.
CI / CD pipelines
Give your pipeline scoped API access without storing long-lived secrets.
Sandboxed execution
Run untrusted code with minimal permissions — it can't escalate beyond its delegate scope.
Create a scoped delegate
A scoped delegate gets a fixed subset of the parent's approved scopes. No dynamic expansion — what you give is what it gets.
terminal
$ keychains delegates add pr_a1b2c3 --scopes "github::repo" --ttl 3600> Delegate created: del_x7y8z9> Mode: scoped> Scopes: github::repo> Expires in: 1 hour> Ship KEYCHAINS_DELEGATE_ID and KEYCHAINS_DELEGATE_KEY to the remote systemCreate a wildcard delegate
A wildcard delegate starts with zero scopes and accumulates them as the user approves. The parent's scopes act as a hard ceiling.
terminal
$ keychains delegates add pr_a1b2c3 --wildcard --ttl 7200> Delegate created: del_w1c2a3> Mode: wildcard> Scopes: (none — approved on demand)> Parent ceiling: github::repo, google::gmail.readonlyNote: The wildcard delegate can only request scopes the parent has already approved. Requesting a scope outside the parent's set returns a hard
scope_refused error — no approval URL.The two-tier scope check
When a wildcard delegate requests a scope, two checks happen:
Tier 1 — Parent Ceiling
Is the scope in the parent's
approvedScopes? If no: hard refuse. No approval URL.Tier 2 — Delegate Approval
Scope is in parent but not the delegate? Ask user — returns 403 with approval URL.
Using delegates from code
remote-worker.ts
import { mintDelegateToken, proxyFetch } from '@keychains.dev/machine-sdk';// On the remote system — env vars shipped from parentconst { token } = await mintDelegateToken(process.env.KEYCHAINS_DELEGATE_ID,process.env.KEYCHAINS_DELEGATE_KEY);const res = await proxyFetch('https://api.github.com/user/repos', { token });Warning: Delegate private keys are secrets. Always use short TTLs and revoke delegates as soon as the task completes.
Revoking a delegate
Revoke from the CLI, SDK, or dashboard. Takes effect immediately.
terminal
$ keychains delegates rm del_x7y8z9> Delegate del_x7y8z9 revokedTip: Revoking the parent permission automatically revokes all its delegates via cascade revocation.
Delegation mode matrix
| Parent | Delegate | Behavior |
|---|---|---|
| scoped | scoped | Fixed subset. No expansion. |
| scoped | wildcard | Accumulates up to parent's fixed set. |
| wildcard | scoped | Fixed subset of parent's dynamic pool. |
| wildcard | wildcard | Dynamic accumulation. Parent is hard ceiling. |