Skip to main content
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

  1. clawup init generates a clawup.yaml with ${env:VAR} references in the secrets section, plus a .env.example file
  2. You copy .env.example to .env and fill in values
  3. 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:
  1. process.env — Shell environment variables (highest priority)
  2. .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 KeyEnv VariableRequiredDescription
anthropicApiKeyANTHROPIC_API_KEYYesAnthropic API key or OAuth token
tailscaleAuthKeyTAILSCALE_AUTH_KEYYesReusable Tailscale auth key
tailnetDnsNameTAILNET_DNS_NAMEYesYour tailnet DNS name (e.g., tail12345.ts.net)
tailscaleApiKeyTAILSCALE_API_KEYNoTailscale API key for device management
hcloudTokenHCLOUD_TOKENHetzner onlyHetzner Cloud API token
braveApiKeyBRAVE_API_KEYIf using brave-search depBrave Search API key

Per-Agent Secrets

Per-agent secrets are scoped by role. The env var name follows the pattern <ROLE>_<SECRET_SUFFIX>:
Secret KeyEnv Variable PatternTriggered By
slackBotToken<ROLE>_SLACK_BOT_TOKENslack plugin
slackAppToken<ROLE>_SLACK_APP_TOKENslack plugin
linearApiKey<ROLE>_LINEAR_API_KEYopenclaw-linear plugin
linearWebhookSecret<ROLE>_LINEAR_WEBHOOK_SECRETopenclaw-linear plugin
linearUserUuid<ROLE>_LINEAR_USER_UUIDopenclaw-linear plugin (optional, auto-fetched)
githubToken<ROLE>_GITHUB_TOKENgh 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:
SecretValidation
anthropicApiKeyMust start with sk-ant-
tailscaleAuthKeyMust start with tskey-auth-
tailnetDnsNameMust end with .ts.net
slackBotTokenMust start with xoxb-
slackAppTokenMust start with xapp-
linearApiKeyMust start with lin_api_
githubTokenMust 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.