Skip to main content

Overview

Every zombie you deploy eventually needs to call an external service: Slack, GitHub, AgentMail, OpenAI. Those services want an API key. You do not want your agent — running untrusted model-generated reasoning inside a sandbox — to ever hold that key in memory. The workspace vault is the answer. Secrets live in a dedicated, encrypted vault scoped to the workspace. Each secret is addressed by a bare key name (for example, agentmail_api_key). Your zombie’s TRIGGER.md declares which key names it needs; at event time the credential firewall fetches the value, makes the outbound call, and returns only the response. The raw value never crosses the sandbox boundary.

Adding a credential

zombiectl credential add <name> --value=<value> stores a secret in the current workspace’s vault. The name is what you reference from TRIGGER.md.
zombiectl credential add agentmail_api_key --value=$AGENTMAIL_KEY
✓ Credential 'agentmail_api_key' stored in vault.
The command POSTs to /v1/workspaces/{workspace_id}/credentials with a JSON body { "name": "...", "value": "..." }. The value is encrypted at rest; only the credential firewall can decrypt it when servicing a skill call. Exit codes:
  • 0 — stored.
  • 1 — no workspace selected, or API error.
  • 2 — missing <name> or --value.

Listing credentials

zombiectl credential list returns the names and creation timestamps of every credential in the current workspace. Values are never returned. This is by design — once stored, a secret is only ever used by the firewall.
zombiectl credential list
  agentmail_api_key  2026-04-15T10:22:31Z
  github_token       2026-04-16T14:55:12Z
  slack_bot_token    2026-04-17T09:03:44Z
Pass --json for machine-readable output.

Referencing credentials from TRIGGER.md

A zombie declares the credentials it needs as a list of bare key names in its TRIGGER.md frontmatter. Nothing else — no URI scheme, no path, no secret-manager-specific prefix. The names are looked up verbatim against the workspace vault.
---
name: lead-collector
trigger:
  type: webhook
  source: agentmail
  event: message.received
credentials:
  - agentmail_api_key
---
At event delivery time the credential firewall fetches each named secret from the vault and substitutes it into the outbound HTTP request made by the matching skill. The agent never sees the resolved value. If a zombie references a credential that is not present in the vault when zombiectl up is called, deployment fails with a clear error listing the missing names.

Rotation

Rotating a credential is a single command — no redeploy is needed. The next event handled by any zombie using that credential picks up the new value.
zombiectl credential add agentmail_api_key --value=$NEW_AGENTMAIL_KEY
Adding a name that already exists overwrites the stored value.

Deletion

To remove a credential, use Mission Control (the web dashboard) or the API directly. A CLI delete subcommand is on the roadmap.
zombiectl credential delete is planned for a future release. Today, use the dashboard at app.usezombie.com or call DELETE /v1/workspaces/{workspace_id}/credentials/{name} directly.

What the agent can and cannot see

ThingCan the agent see it?
The credential’s name (agentmail_api_key)Yes. It is needed to call the right skill.
The credential’s value (the raw secret)No. The firewall injects and strips it outside the sandbox.
The response body from the external serviceYes. The agent needs the data to reason about what to do next.
Any headers the external service setYes, unless they carry sensitive tokens — the firewall redacts known-sensitive header names.
This is the core security guarantee. If the agent is compromised — model-prompt injection, jailbreak, whatever — your keys are not. The agent never had them.