Let an agent use secrets it can never read.
BetaIf an agent runs the CLI on your login, it has everything you have: it can reveal values, allow new hosts and consent to its own spends. An agent token (ta_…) is a separate credential for the agent. It can use secrets through the broker, inside a scope and a daily budget you set, and nothing more.
Spend, request, list. Nothing else.
| An agent token can | It can never |
|---|---|
| Spend a secret through the broker (secrets spend, migrate, deploy-worker) | Reveal or pull a value, or resolve one into a process |
| Ask a person for a value (secrets request), unless minted with --no-request | Grant consent, including to itself |
| List projects, environments and keys its patterns reach | Allow a destination or change its rules |
| Read its own requests and its own spend ledger | Create presigned calls, service tokens or other agent tokens |
| Sign with an SSH key through the SSH agent, each signature approved by the person who made the token | Read the SSH private key |
Each API route opts in to agent tokens by name, and a test fails the build if one is added without review. Everywhere else a ta_ bearer is rejected as if it were no login at all.
Mint one and consent
An owner or admin mints the token, from the CLI or Secrets → Agents in the console. The token is shown once. Consent is still per secret and host: the agent spends as agent:<name>, and only a person can create that grant.
# Scope it to what the job needs. * is a whole part; DO_* is a prefix.
tilldev secrets agents create deploy-bot \
--refs 'infra/prod/DO_*,infra/prod/CF_API_TOKEN' \
--budget 50 --expires 7 --quiet > deploy-bot.token
# Consent, once, for each secret and host the agent may use.
tilldev secrets broker allow secretref://infra/prod/DO_TOKEN api.digitalocean.com --methods GET,POST,DELETE
tilldev secrets broker grant create secretref://infra/prod/DO_TOKEN \
--agent agent:deploy-bot --host api.digitalocean.com --scope ttl --ttl-minutes 1440| Pattern | Reaches |
|---|---|
infra/prod/DO_TOKEN | Exactly that secret. |
infra/*/DO_TOKEN | DO_TOKEN in every environment of infra. |
infra/prod/STRIPE_* | Keys starting STRIPE_ in infra/prod. |
*/*/* | Everything the creator can reach. Avoid it. |
A wildcard matches within one part and never crosses a /, so infra/prod/* does not reach infra-old/prod/….
Use it
# Where the agent runs. The CLI and the Node broker SDK use it ahead of any login.
export TILLDEV_AGENT_TOKEN="$(cat deploy-bot.token)"
tilldev secrets agents whoami # scope, spends left today, expiry
tilldev secrets spend GET https://api.digitalocean.com/v2/account \
--bearer secretref://infra/prod/DO_TOKEN
# Needs a value nobody stored yet? Ask a person for it.
tilldev secrets request CF_API_TOKEN --env prod --note "Workers deploy, one account"import { createBroker, secretref } from '@tillstack/secrets-node'
// Reads TILLDEV_AGENT_TOKEN. No agentKey: the token names the agent.
const broker = createBroker()
const res = await broker.fetch('https://api.digitalocean.com/v2/droplets', {
headers: { authorization: `Bearer ${secretref('infra', 'prod', 'DO_TOKEN')}` },
})Budget, expiry and whose access it carries
- Daily budget. Each spent reference, and each SSH signature, counts one against the token's daily limit (default 100, up to 10,000). It resets at 00:00 UTC. Over the limit the broker refuses with
budget_exhausted. - Scope. A reference outside the patterns is refused with
out_of_scopebefore anything is decrypted. - Expiry. 1 hour to 90 days, default 30 days.
- Live role. The token acts with its creator's current role. If they leave the workspace or lose access to a secret, the token loses it too.
tilldev secrets agents ls
tilldev secrets broker spends --agent agent:deploy-bot # every use, spent or refused
tilldev secrets agents revoke deploy-bot # immediateagent.create and agent.revoke. Requests the agent makes are logged with actor type agent and the person it acts for.