AgentKit
DocsKitsCLI ReferenceDesktop App
BetaYou are reading docs for the beta channel (3.0.0-beta.15). Features may change before the next stable release.Switch to stable →

Guides

Using the secrets vault

Store API keys and tokens in the AgentKit secrets vault, let agents use them by reference, answer approvals, and audit every release.

ak secrets keeps small named values, such as API keys, tokens, and certificates, in the OS keychain or an age-encrypted vault file. Coding agents use a value through a ${secret:NAME} reference instead of an unmanaged .env file or a shell export. This guide explains how the commands fit together; each command's page has the full flags, defaults, and exit codes. The Desktop app has its own Secrets page.

A grant trusts the agent with the value

The vault organizes and audits access. It does not seal a value away from an agent you granted it to. Read Limits before you grant a secret.

Commands

TaskCommand
Store or replace a valueak secrets set, ak secrets rotate
See what is stored (never the value)ak secrets list, ak secrets get
Remove a valueak secrets delete
Move a .env file into the vaultak secrets import-env
Let an agent read a secretak secrets grant
Answer requests agents left waitingak secrets approve
See or remove grantsak secrets grants, ak secrets revoke
Check or re-pin an agent's binaryak secrets trust
Read the access ledgerak secrets audit
Inventory the vaultak secrets export
Manage the file backend's vault and recovery keysak secrets recovery

Values are read from --value=- (stdin), --value-file, or a non-echoing prompt, never from a literal flag value that would land in shell history. ak secrets get prints [redacted] unless you pass --reveal in a terminal.

Choose a backend

BackendUse it whenAgents can resolve
Keychain (default)The host has a working OS keychain: macOS Keychain, Windows Credential Manager, or a Secret Service on LinuxYes
FileThe host has no usable keychainNo: the vault passphrase is read only from a terminal, so an agent resolve fails (exit 7)
MemoryTests and demos; nothing persistsProcess-local only

The backend comes from --backend, then AGENTKIT_SECRETS_BACKEND, then backend in the secrets section of $AGENTKIT_HOME/config.yaml, and otherwise the keychain. A host config that selects the file backend therefore makes every agent resolve fail, even though no flag says so. Use the keychain on any host where agents need secrets; the file backend suits a vault only you read from a terminal.

The OS keychain may ask you to allow access the first time ak reads an item, or after an upgrade changes the binary. That prompt is the keychain's own access control.

Set up the file backend

ak secrets recovery init --label <label>                 # create the vault and one recovery key
ak secrets recovery add <age-public-key> --label <label>  # enroll another recovery key
ak secrets recovery list

recovery init shows the recovery private key once and stores it nowhere. Keep it where the host cannot reach it: if you lose the passphrase and every recovery key, nobody can open the vault. If you forget the passphrase, run a vault-reading command with --unlock-with-recovery in a terminal, paste the recovery key, and choose a new passphrase.

The host remembers the newest vault version it has seen. If the vault on disk is older (restored from a backup or synced over by a stale copy), commands that open it fail. Find out why first; to keep the older vault anyway, run ak secrets recovery accept-rollback. Writes made after that older copy are lost.

Let agents use a secret

An agent writes a reference into a tool call:

curl -H "Authorization: Bearer ${secret:NAME}" <url>

The core Kit's secrets-inject PreToolUse Hook substitutes the value in memory just before the tool runs. In Claude Code it scans only the Bash and PowerShell commands and the WebFetch URL. For each reference it runs ak secrets resolve, which identifies the calling agent by walking the process tree and hashing the agent's binary; the caller is never taken from a flag. Any failure blocks the tool call rather than passing the literal reference on.

When ak run starts a Codex or Grok agent, ${secret:NAME} references in the environment it passes to that agent are resolved the same way, and the run stops if a value cannot be released.

A resolve succeeds only when a grant matches four fields: the secret, the project, the agent's binary fingerprint, and the purpose. An empty purpose is a literal value, not a wildcard, and a block outranks any allow on the same scope. Get an agent's fingerprint from ak secrets trust <adapter> --json or from a waiting request.

ak secrets grant --allow-host <host> restricts an allow to WebFetch URLs aimed at the listed hosts. A restricted grant refuses any release whose destination the Hook cannot check, including every Bash or PowerShell reference. The restriction applies to the Hook's own substitution path only; see ak secrets grant for the exact matching rules.

Answer approvals

When no grant covers a resolve, it does not prompt. It fails closed (exit 8) and leaves a request for you. Answer it with ak secrets approve in your own terminal, or in the approval inbox on the Desktop Secrets page:

AnswerEffect
DenyRefuses this request and stores nothing; the next resolve asks again
Allow onceReleases the secret exactly once
Allow for a whileAn allow that expires on its own: 24 hours by default in the CLI (--ttl changes it); 15 minutes, 1 hour (default), or 8 hours in Desktop
Always allow (allow until revoked)An allow with no expiry

An agent that keeps asking without a grant is rate-limited per fingerprint and then held in a cool-down (exit 9). A job under a standing grant never reaches the limit.

grant and approve refuse to run (exit 6) when an agent sits above them in the process tree, and Desktop refuses an answer when an agent started the app. This stops an agent from approving its own request in the obvious way; it is a speed bump, not a boundary.

Revoke

ak secrets revoke <ref> --agent sha256:<hash>   # one scope, allow or block
ak secrets revoke --agent sha256:<hash> --all   # every grant that binary holds

Revoking stops future reads. It does not recall a value the agent already read, so rotate the secret after a panic revoke.

After a release

A released value reaches the tool's process and arguments, and the runtime may record the executed call, value included, in its session transcript. AgentKit keeps only a hash and a length of each released value, in release manifests under $AGENTKIT_HOME/diagnostics/manifests/. Two commands use them to remove released values later:

  • ak diagnostics export removes them from a support bundle when it can read the manifests.
  • ak sessions redact finds them in registered Claude Code session files. It is a dry run unless you pass --apply --yes, and it backs up before rewriting.

Rotate

Each secret has a rotation window: 90 days by default, or the value you pass with ak secrets set <ref> --rotate-ttl <days>d. ak secrets list flags secrets past their window. Replace a value with ak secrets rotate <ref>; it fails if the ref does not exist, so a typo does not create a new secret.

Audit releases

Every resolve with an identifiable caller writes one row to the secrets_audit ledger, for a release and a refusal alike, before any value is returned. A row records the ref, project, fingerprint, label, purpose, decision, source, session, error code, and context, never a value. For a WebFetch reference, the destination host is added to the context. A Desktop reveal requires a reason, recorded the same way.

Read the ledger with ak secrets audit or on the Desktop Audit log page. The ledger is kept until you change its retention with ak data retention --class secrets_audit.

While Desktop is open, each release also shows an in-app notice with a Revoke this agent's grants button, and raises an OS notification titled Secret released while the window is unattended. Neither carries the value; see the Secrets page.

Export

ak secrets export --json                               # inventory on stdout, no values
ak secrets export --out ./inventory.json               # the same, as a file only you can read
ak secrets export --include-values --out ./values.age  # confirms, then writes an age-encrypted file

The default export contains no values. --include-values needs an interactive terminal and an --out path ending in .age; values never go to stdout. It asks you to confirm and to choose a passphrase, and nothing on the host keeps that passphrase, so losing it loses the export. Decrypt with the stock age CLI, for example age --decrypt values.age | jq ., and treat any decrypted file like the secrets it contains.

Move from .env

ak secrets import-env <path>           # skips keys that already exist
ak secrets import-env <path> --force   # overwrites them instead

The command reports only counts, never values, and reads at most 1 MiB. Then grant the agents that need each key, change the commands to use ${secret:NAME}, and remove the .env file.

Cloud sync

The vault lives on one host. An opt-in, end-to-end encrypted sync between your devices, teammates, and CI is in development as ak-vault. It is not available yet: the sync service stays switched off until its protocol passes an independent security review.

The design keeps the local vault as the source of truth:

  • Each device encrypts values before upload, so the sync server stores and relays only ciphertext and cannot read a secret.
  • Membership changes are signed by the vault owner and hash-chained, so the server cannot add a reader or hide a removal.
  • Concurrent edits are kept as conflicts to resolve, never silently overwritten, and a deleted secret cannot be brought back by a stale device.
  • A device keeps its own grants: a synced policy can only narrow what an agent may read, never widen it.

The protocol and its threat model are public.

Limits

These are deliberate boundaries of this version:

  • A grant trusts the agent's model with the plaintext. A prompt-injected agent can send a granted value to any host that --allow-host does not exclude. An unrestricted grant relies on the runtime's permission prompt, and AGENTKIT_SECRETS_INJECT_AUTO_ALLOW=1 removes that prompt.
  • No wall after injection. Once a value is in a child process, its environment, or a transcript, AgentKit cannot contain it. Redaction and rotation are the remedies.
  • Self-approval refusal is a speed bump. An agent running as your user can detach from the process tree or edit the grants file directly.
  • Keychain access control is the OS's. Any process running as your user that the keychain lets in can read an item.
  • Memory attackers. Anyone who can read the memory of ak, the Hook, or the tool process can read the value while it is in use.
  • Static windows. Grant and rotation windows are fixed durations.