Clawup uses a .env file to manage secrets outside of your manifest. The clawup.yaml manifest declares which env vars to read using ${env:VAR_NAME} syntax — making the YAML self-documenting while keeping actual values out of version control.
How It Works
clawup init generates a clawup.yaml with ${env:VAR} references in the secrets section, plus a .env.example file
- You copy
.env.example to .env and fill in values
clawup deploy loads .env, validates all secrets are present, and configures Pulumi automatically before deploying
# clawup.yaml — secrets section (auto-generated)
secrets:
anthropicApiKey: "${env:ANTHROPIC_API_KEY}"
tailscaleAuthKey: "${env:TAILSCALE_AUTH_KEY}"
tailnetDnsName: "${env:TAILNET_DNS_NAME}"
tailscaleApiKey: "${env:TAILSCALE_API_KEY}"
agents:
- name: agent-pm
role: pm
secrets:
slackBotToken: "${env:PM_SLACK_BOT_TOKEN}"
slackAppToken: "${env:PM_SLACK_APP_TOKEN}"
# .env — actual values (git-ignored)
ANTHROPIC_API_KEY=sk-ant-api03-xxxxx
TAILSCALE_AUTH_KEY=tskey-auth-xxxxx
TAILNET_DNS_NAME=tail12345.ts.net
TAILSCALE_API_KEY=tskey-api-xxxxx
PM_SLACK_BOT_TOKEN=xoxb-xxxxx
PM_SLACK_APP_TOKEN=xapp-xxxxx
The .env file is automatically added to .gitignore by clawup init. Actual secret values are stored encrypted in Pulumi config — the .env file is a convenience for populating secrets non-interactively.
Resolution Order
When resolving ${env:VAR} references, values are checked in this order:
process.env — Shell environment variables (highest priority)
.env file — Loaded from the project root (or path specified by --env-file)
This matches standard dotenv behavior — shell variables always take precedence.
Global Secrets
These are shared across all agents and always included in the manifest:
| Secret Key | Env Variable | Required | Description |
|---|
anthropicApiKey | ANTHROPIC_API_KEY | Yes | Anthropic API key or OAuth token |
tailscaleAuthKey | TAILSCALE_AUTH_KEY | Yes | Reusable Tailscale auth key |
tailnetDnsName | TAILNET_DNS_NAME | Yes | Your tailnet DNS name (e.g., tail12345.ts.net) |
tailscaleApiKey | TAILSCALE_API_KEY | No | Tailscale API key for device management |
hcloudToken | HCLOUD_TOKEN | Hetzner only | Hetzner Cloud API token |
braveApiKey | BRAVE_API_KEY | If using brave-search dep | Brave Search API key |
Per-Agent Secrets
Per-agent secrets are scoped by role. The env var name follows the pattern <ROLE>_<SECRET_SUFFIX>:
| Secret Key | Env Variable Pattern | Triggered By |
|---|
slackBotToken | <ROLE>_SLACK_BOT_TOKEN | slack plugin |
slackAppToken | <ROLE>_SLACK_APP_TOKEN | slack plugin |
linearApiKey | <ROLE>_LINEAR_API_KEY | openclaw-linear plugin |
linearWebhookSecret | <ROLE>_LINEAR_WEBHOOK_SECRET | openclaw-linear plugin |
linearUserUuid | <ROLE>_LINEAR_USER_UUID | openclaw-linear plugin (optional, auto-fetched) |
githubToken | <ROLE>_GITHUB_TOKEN | gh dep |
For example, if the PM agent (role pm) has the Slack plugin, the expected env vars are PM_SLACK_BOT_TOKEN and PM_SLACK_APP_TOKEN.
Linear User UUID
The linearUserUuid is auto-fetched by clawup deploy using the Linear API. You can also set it manually in .env to bypass the API call:
PM_LINEAR_USER_UUID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
Identity requiredSecrets
Identities can declare additional secrets beyond what plugins and deps imply using the requiredSecrets field in identity.yaml:
# identity.yaml
plugins:
- slack # implicitly → slackBotToken, slackAppToken
deps:
- gh # implicitly → githubToken
# Additional secrets not covered by plugins/deps
requiredSecrets:
- notionApiKey
- customWebhookSecret
The camelCase key is converted to SCREAMING_SNAKE_CASE and prefixed with the agent’s role. For example, notionApiKey on a pm agent becomes PM_NOTION_API_KEY.
This is additive — secrets implied by plugins/deps are always included. requiredSecrets adds extras on top. If a key in requiredSecrets is already implied by a plugin/dep, it won’t be duplicated.
.env.example
The .env.example file is generated automatically by clawup init (and regenerated by clawup deploy). It lists all required env var names with empty values, organized by scope:
# Clawup Secrets — copy to .env and fill in values
# See clawup.yaml 'secrets' section for which keys map where
# ── Required ─────────────────────────────────
ANTHROPIC_API_KEY=
TAILSCALE_AUTH_KEY=
TAILNET_DNS_NAME=
TAILSCALE_API_KEY=
# ── Agent: Juno (pm) ──────────────────────
PM_SLACK_BOT_TOKEN=
PM_SLACK_APP_TOKEN=
PM_NOTION_API_KEY=
# PM_LINEAR_USER_UUID= # auto-fetched if PM_LINEAR_API_KEY is set
Using --env-file
By default, clawup deploy looks for .env in the project root. Override with:
clawup deploy --env-file /path/to/my/.env
Validation
Clawup validates well-known secret formats during deployment:
| Secret | Validation |
|---|
anthropicApiKey | Must start with sk-ant- |
tailscaleAuthKey | Must start with tskey-auth- |
tailnetDnsName | Must end with .ts.net |
slackBotToken | Must start with xoxb- |
slackAppToken | Must start with xapp- |
linearApiKey | Must start with lin_api_ |
githubToken | Must start with ghp_ or github_pat_ |
If a value from .env fails validation, a warning is shown but the value is still used.
Managing Secrets Post-Deploy
After initial deployment, manage secrets without re-deploying:
# Set or rotate a secret
clawup secrets set braveApiKey BSA_xxx
clawup secrets set slackBotToken xoxb-xxx --agent pm
# List configured secrets (values redacted)
clawup secrets list
Under the hood, this updates the encrypted Pulumi config. Run clawup redeploy to apply changes to running agents.