Agent SwarmAgent Swarm
Reference

Environment Variables

Complete reference for all Agent Swarm environment variables — server configuration, API keys, MCP base URL, Slack tokens, GitHub credentials, and integration settings for self-hosted deployments

Complete reference for all environment variables used by Agent Swarm.

Server Variables

VariableDefaultDescription
PORT3013Port for MCP HTTP server
API_KEYAPI key for server authentication (required)
MCP_BASE_URLhttps://api.example-swarm.devInternal/worker-facing API base — the URL workers, the UI, and the setup command use to reach the API server. In split deploys this may be an internal/cluster address.
PUBLIC_MCP_BASE_URLFalls back to MCP_BASE_URLPublic, browser/externally-reachable API origin used for OAuth redirect URIs and webhook URLs. Defaults to MCP_BASE_URL when unset; set it in split deploys where MCP_BASE_URL is an internal/cluster address that external providers (Linear, Jira, GitHub) can't reach.
SWARM_URLlocalhostBase domain for service discovery
APP_URLDashboard URL for Slack message links. DASHBOARD_URL is a deprecated alias of APP_URL.
ENVEnvironment mode (development adds prefix to Slack agent names)
DATABASE_PATH./agent-swarm-db.sqliteSQLite database file path
SQLITE_VEC_EXTENSION_PATHPath to vec0.so native extension for sqlite-vec vector search. Set automatically in the Docker image (/app/extensions/vec0.so). Only needed for non-Docker deployments.
SCRIPT_RUNTIME_DIRDirectory holding the pre-built script-runtime bundles (eval-harness.bundle.js, stdlib.bundle.js, swarm-sdk.bundle.js, zod.bundle.js). Set automatically in the Docker image (/app/scripts-runtime). Required by the scripts runtime when running as a compiled binary, since the harness subprocess cannot read the binary's /$bunfs/ virtual filesystem.
TS_LIB_DIRDirectory holding the TypeScript lib.*.d.ts files used by script typecheck. Set automatically in the Docker image (/app/typescript-lib). Required in compiled-binary mode so the TypeScript compiler can resolve the default lib.
SECRETS_ENCRYPTION_KEYAuto-generated on first bootMaster key for encrypting swarm_config secret rows at rest. Accepts base64 (43-char, e.g. openssl rand -base64 32) or 64-char hex (e.g. openssl rand -hex 32). Decodes to exactly 32 bytes. Reserved: cannot be stored in the DB config store. See Encryption Key.
SECRETS_ENCRYPTION_KEY_FILEAlternative to SECRETS_ENCRYPTION_KEY: absolute path to a file whose contents are the base64- or hex-encoded key. Useful with Docker secrets or k8s Secret volume mounts.
SCHEDULER_INTERVAL_MS10000Polling interval for scheduled tasks (ms)
OPENAI_API_KEYFallback key for memory embeddings (used when EMBEDDING_API_KEY is unset).
EMBEDDING_API_KEYAPI key for the embedding provider. Takes precedence over OPENAI_API_KEY.
EMBEDDING_API_BASE_URLOptional custom OpenAI-compatible base URL (e.g. Azure OpenAI, Together, vLLM, Ollama). Leave unset to hit api.openai.com.
EMBEDDING_MODELtext-embedding-3-smallEmbedding model slug sent to the provider.
EMBEDDING_DIMENSIONS512Vector dimensions requested from the model. Must match what the model supports.
MEMORY_RECENCY_HALF_LIFE_DAYS14Days until memory recency decay reaches 0.5
MEMORY_ACCESS_BOOST_MAX1.5Maximum access boost multiplier for reranking
MEMORY_ACCESS_RECENCY_HOURS48Hours within which access counts for full boost
MEMORY_CANDIDATE_MULTIPLIER3Candidate set size relative to requested limit
OPENROUTER_API_KEYRequired for the Stop-hook session summarizer + LLM memory rater (calls go through the Vercel AI SDK against OpenRouter). When unset, both session-summary indexing and the llm rater are no-ops
MEMORY_RATER_LLM_MODELgoogle/gemini-3-flash-previewOpenRouter model slug used by the Stop-hook summarizer + LLM rater. Override with any OpenRouter slug (e.g. anthropic/claude-haiku-4.5)
MEMORY_LLM_RATER_ENABLEDfalseWhen true, the same summarizer call also produces structured `useful: true
CAPABILITIESAll enabledComma-separated feature flags
HEARTBEAT_INTERVAL_MS90000Heartbeat sweep interval (ms)
HEARTBEAT_DISABLEfalseSet to true to disable the heartbeat module
HEARTBEAT_STALL_THRESHOLD_MIN30Minutes before an in-progress task is considered stalled
HEARTBEAT_STALE_CLEANUP_MIN30Minutes before stale resources (sessions, reviewing tasks) are cleaned up
HEARTBEAT_MAX_AUTO_ASSIGN5Max pool tasks to auto-assign per sweep

Encryption key resolution (see Encryption Key for the full guide):

  1. SECRETS_ENCRYPTION_KEY env var
  2. SECRETS_ENCRYPTION_KEY_FILE env var (path to a file containing the key)
  3. <data-dir>/.encryption-key on the API's data volume
  4. Auto-generated on first boot only when the DB does not yet contain encrypted secret rows

Losing the key while keeping the database means losing every encrypted secret with no recovery path. Back up the key alongside every database backup.

Docker Worker Variables

Harness Provider

VariableRequiredDefaultDescription
HARNESS_PROVIDERNoclaudeAI provider: claude (Claude Code), codex, opencode, pi (pi-mono), devin (Devin), or claude-managed (Anthropic Managed Agents). See Harness Configuration

Credentials

Which credentials you need depends on your selected harness provider:

Claude Code (HARNESS_PROVIDER=claude, default):

VariableRequiredDefaultDescription
CLAUDE_CODE_OAUTH_TOKENYes*OAuth token for Claude CLI. Supports comma-separated values for multi-credential load balancing
ANTHROPIC_API_KEYAlt*Alternative to CLAUDE_CODE_OAUTH_TOKEN. Also supports comma-separated values
SWARM_USE_CLAUDE_BRIDGENofalseReloadable boolean (true/1 enables, false/0/unset disables). When enabled, the Claude adapter routes through the installed claude-bridge binary from pinned package @desplega.ai/claude-bridge@0.1.5, a Desplega-owned claude -p drop-in that drives interactive Claude Code through tmux. Requires Bun, claude, and tmux on PATH. See Claude Bridge.
CLAUDE_BINARYNoclaudeLow-level argv prefix for the Claude CLI. Accepts a single binary name (claude), an absolute path, or a whitespace-separated command string. Legacy bridge commands remain supported only as a deprecated compatibility path; prefer SWARM_USE_CLAUDE_BRIDGE=true. Reloadable via swarm_config (precedence: repo > agent > global > env > claude) so you can flip a worker via set-config CLAUDE_BINARY=... without a container restart.
ENABLE_PROMPT_CACHING_1HNo1Enables Anthropic's 1-hour prompt cache for every Claude Code session spawned by the worker. Default-on since v1.69.1; set to 0 (env or swarm_config) to opt out. Injected by ClaudeAdapter into the spawned claude process env.

* One of CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY is required.

pi-mono (HARNESS_PROVIDER=pi):

VariableRequiredDefaultDescription
ANTHROPIC_API_KEYOne of*Anthropic API key for Claude models via pi-mono
OPENROUTER_API_KEYOne of*OpenRouter API key for multi-provider model access

* At least one credential source is required (API key or ~/.pi/agent/auth.json). Do not pass CLAUDE_CODE_OAUTH_TOKEN when using pi-mono — it will override the configured provider. See Harness Configuration for details.

Codex (HARNESS_PROVIDER=codex):

VariableRequiredDefaultDescription
OPENAI_API_KEYOptionalStandard OpenAI API key for Codex
API_KEYYesSwarm API key used to fetch codex_oauth from the config store
MCP_BASE_URLYeshttp://host.docker.internal:3013Swarm API URL reachable by the worker

Codex can also authenticate through ~/.codex/auth.json, including ChatGPT OAuth restored from the swarm config store. See Provider Auth: Codex OAuth.

opencode (HARNESS_PROVIDER=opencode):

VariableRequiredDefaultDescription
OPENROUTER_API_KEYOne of*OpenRouter API key (primary — unlocks 100+ models at openrouter.ai)
ANTHROPIC_API_KEYOne of*Anthropic API key for Claude models
OPENAI_API_KEYOne of*OpenAI API key for GPT models
OPENCODE_BINARYNoopencodePath to the opencode CLI binary (if not in $PATH)
MODEL_OVERRIDENoopenrouter/qwen/qwen3-coder-flashModel string passed to opencode. Use provider/model-id format (e.g. anthropic/claude-sonnet-4-6, openai/gpt-4o)

* At least one of OPENROUTER_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, or ~/.local/share/opencode/auth.json is required.

Devin (HARNESS_PROVIDER=devin):

VariableRequiredDefaultDescription
DEVIN_API_KEYYesDevin API key (prefix: cog_*)
DEVIN_ORG_IDYesDevin organization ID (prefix: org-*)
DEVIN_POLL_INTERVAL_MSNo15000Polling interval for Devin session events (ms)
DEVIN_ACU_COST_USDNo2.25USD per ACU for cost tracking
DEVIN_API_BASE_URLNohttps://api.devin.aiDevin API base URL (override for testing)
DEVIN_MAX_ACU_LIMITNoPer-session ACU cap (sent to Devin API + UI budget bar)
MAX_SKILL_CHARSNo100000Max chars for inlined SKILL.md content

Starter env file: .env.docker-devin.example at the repo root.

Claude Managed Agents (HARNESS_PROVIDER=claude-managed):

VariableRequiredDefaultDescription
ANTHROPIC_API_KEYYesAnthropic API key (used by both the setup CLI and the runtime adapter)
MANAGED_AGENT_IDYesAnthropic Agent ID. Written by claude-managed-setup
MANAGED_ENVIRONMENT_IDYesAnthropic Environment ID. Written by claude-managed-setup
MCP_BASE_URLYesMust be HTTPS-public so Anthropic's sandbox can reach /mcp. Worker fails fast at boot otherwise
MANAGED_AGENT_MODELNoclaude-sonnet-4-6Default model on sessions.create; per-task task.model overrides
MANAGED_GITHUB_VAULT_IDNoAnthropic vault ID holding a GitHub PAT, for repo-bound tasks (recommended for prod)
MANAGED_GITHUB_TOKENNoLiteral GitHub PAT injected as authorization_token on github_repository resources (dev-only fallback)

Run the one-time bunx @desplega.ai/agent-swarm claude-managed-setup from your laptop to bootstrap the Anthropic-side Agent + Environment and persist IDs into swarm_config. See Harness Configuration § Claude Managed Agents.

General Worker Settings

VariableRequiredDefaultDescription
API_KEYYesAPI key for MCP server
AGENT_IDNoAuto-generatedAgent UUID. Keep stable for task resume
AGENT_ROLENoworkerRole: worker or lead
AGENT_NAMENoAuto-generatedDisplay name for the agent
MCP_BASE_URLNohttp://host.docker.internal:3013MCP server URL
SESSION_IDNoAuto-generatedLog folder name
YOLONofalseContinue on errors
SYSTEM_PROMPTNoCustom system prompt text
SYSTEM_PROMPT_FILENoPath to system prompt file
CONTEXT_MODE_DISABLEDNofalseSet to true to disable the default context-mode MCP wiring for local Claude Code, Codex, and opencode workers. Leaves the worker running but hides/skips the ctx_* tools.
STARTUP_SCRIPT_STRICTNotrueExit on startup script failure
SHUTDOWN_TIMEOUTNo30000Grace period (ms) before pausing tasks
MAX_CONCURRENT_TASKSNo1Maximum parallel tasks per worker
SWARM_URLNolocalhostBase domain for service URLs
LEAD_PORTNo3020Host port for lead service. Example variable used in docker-compose.example.yml — adjust to your setup. In isolated network namespaces all services can share the same port.
WORKER1_PORTNo3021Host port for worker-1 service. Example — see LEAD_PORT.
WORKER2_PORTNo3022Host port for worker-2 service. Example — see LEAD_PORT.
PM2_HOMENo/workspace/.pm2PM2 state directory
TEMPLATE_IDNoTemplate for initial profile on first boot (e.g., official/coder)
TEMPLATE_REGISTRY_URLNohttps://templates.agent-swarm.devURL of the templates registry

Git Configuration

VariableDefaultDescription
GITHUB_TOKENGitHub token for git operations
GITHUB_EMAILworker-agent@desplega.aiGit commit email
GITHUB_NAMEWorker AgentGit commit name

Slack Integration

VariableDescription
SLACK_BOT_TOKENBot User OAuth Token (xoxb-...)
SLACK_APP_TOKENApp-Level Token for Socket Mode (xapp-...)
SLACK_SIGNING_SECRETSigning Secret (optional for Socket Mode)
SLACK_DISABLESet to true to disable Slack
SLACK_ALLOWED_EMAIL_DOMAINSComma-separated email domains
SLACK_ALLOWED_USER_IDSComma-separated user IDs to always allow
ADDITIVE_SLACKSet to true to enable non-mention thread message buffering and batching
ADDITIVE_SLACK_BUFFER_MSDebounce window for thread buffer in ms (default: 10000)
SLACK_THREAD_FOLLOWUP_REQUIRE_MENTIONSet to true to require @mention for thread follow-up routing (default: false)

GitHub Integration

VariableDescription
GITHUB_WEBHOOK_SECRETWebhook secret for GitHub App
GITHUB_BOT_NAMEBot name for @mentions (default: agent-swarm-bot)
GITHUB_BOT_ALIASESComma-separated additional @mention aliases (e.g. heysidekick,sidekick)
GITHUB_EVENT_LABELSComma-separated labels that trigger agent action on PR/issue label events (default: swarm-review)
GITHUB_APP_IDGitHub App ID (for bot reactions)
GITHUB_APP_PRIVATE_KEYGitHub App private key (base64-encoded)
GITHUB_DISABLESet to true to disable GitHub

GitLab Integration

VariableDescription
GITLAB_TOKENGitLab PAT or Group Access Token for API calls
GITLAB_URLGitLab instance URL (default: https://gitlab.com)
GITLAB_WEBHOOK_SECRETShared secret for webhook verification
GITLAB_BOT_NAMEBot username for @mention detection (default: agent-swarm-bot)
GITLAB_EMAILGit commit email for GitLab repos
GITLAB_NAMEGit commit name for GitLab repos
GITLAB_DISABLESet to true to disable GitLab integration

AgentMail Integration

VariableDescription
AGENTMAIL_DISABLESet to true to skip AgentMail integration
AGENTMAIL_WEBHOOK_SECRETSvix signing secret for webhook verification
AGENTMAIL_INBOX_DOMAIN_FILTERComma-separated domains to allow for incoming inbox webhooks (e.g., yourdomain.com,example.com). Unmatched inbox domains are silently dropped
AGENTMAIL_SENDER_DOMAIN_FILTERComma-separated sender domains to allow (e.g., gmail.com,company.com). Unmatched sender domains are silently dropped

Kapso / WhatsApp Integration

VariableDescription
KAPSO_API_KEYKapso API key used for outbound sends and optional webhook registration (X-API-Key)
KAPSO_PHONE_NUMBER_IDDefault WhatsApp Business phone-number ID the swarm sends from
KAPSO_WEBHOOK_HMAC_SECRETShared secret used to verify Kapso's X-Webhook-Signature header on inbound webhooks
KAPSO_API_BASE_URLOptional Kapso API base URL override (default: https://api.kapso.ai)

Setup Steps

  1. Set the values above in your .env or integrations dashboard.
  2. Have the lead call register-kapso-number to point the number at /api/integrations/kapso/webhook and store the routing mapping.
  3. Use send-whatsapp-message / reply-whatsapp-message for the common text path, or the kapso-whatsapp skill for templates, media, and reactions.

Sentry Integration

VariableDescription
SENTRY_AUTH_TOKENSentry Organization Auth Token
SENTRY_ORGSentry organization slug

Linear Integration

VariableDescription
LINEAR_DISABLESet to true to disable Linear integration
LINEAR_CLIENT_IDOAuth app client ID (create at Linear > Settings > API > Applications)
LINEAR_CLIENT_SECRETOAuth app client secret (shown once on creation)
LINEAR_REDIRECT_URIOAuth callback URL (e.g., http://localhost:3013/api/trackers/linear/callback)
LINEAR_SIGNING_SECRETWebhook signing secret from Linear app settings
LINEAR_ALLOWED_STATESCSV of WorkflowState.type values that trigger task creation. Default: unstarted,started,completed,canceled (i.e. skip Backlog & Triage). Set to empty to lock down everything but the label override. See Linear integration → State gate.
LINEAR_SWARM_READY_LABELLabel name (case-insensitive) that bypasses the state gate. Default: swarm-ready.

Setup Steps

  1. Create an OAuth app at Linear > Settings > API > Applications
  2. Set Actor to "Application"
  3. Set Callback URL to your /api/trackers/linear/callback endpoint
  4. Enable "Agent session events" in webhook settings
  5. Set Webhook URL to your /api/trackers/linear/webhook endpoint
  6. Copy Client ID, Client Secret, and Webhook Signing Secret
  7. Start the server, then visit /api/trackers/linear/authorize to complete OAuth

With portless: set LINEAR_REDIRECT_URI=https://api.swarm.localhost:1355/api/trackers/linear/callback

Portless (Local Development)

Portless replaces port-based URLs with friendly domain names for local development.

VariableWith PortlessDescription
MCP_BASE_URLhttps://api.swarm.localhost:1355API server URL
APP_URLhttps://ui.swarm.localhost:1355Dashboard URL

Install: bun add -g portless. Enable HTTPS: portless trust && portless proxy start --https.

Cloud Personalization & Adaptive Home

Identity envs that brand the swarm and gate cloud-only UX. All are read on every GET /status call (cheap — env reads + one SQL aggregate, no upstream calls). See the Personalization & Status guide for the full story.

VariableDefaultDescription
SWARM_CLOUDfalseWhen true, marks the deployment as cloud-hosted. Surfaces Docs/Support/Billing items in the user-menu, suppresses the self-host marketing footer, and is sent as metadata.is_cloud (always present) on every anonymized telemetry event
SWARM_ORG_NAMESwarmSidebar header name. Also sent as metadata.organization_name on every anonymized telemetry event when set
SWARM_ORG_IDnoneStable org/tenant identifier exposed on /status as identity.org_id and sent as metadata.organization_id on every anonymized telemetry event when set. Set by the orchestrator on cloud deployments
SWARM_ORG_LOGO_URLbundled /logo.pngSidebar logo URL (any HTTPS URL). Falls back to the bundled logo if it fails to load
SWARM_BRAND_COLORnoneTints the org name in the sidebar header (any CSS color, e.g. #a855f7)
SWARM_MARKETING_URLnoneSelf-host marketing footer link target. Suppressed when SWARM_CLOUD=true or SWARM_HIDE_CLOUD_PROMO=true
SWARM_HIDE_CLOUD_PROMOfalseForce-hide the marketing footer regardless of SWARM_CLOUD
SWARM_VERIFY_TTL_MS3600000 (1h)How long a successful "Test connection" click keeps the harness milestone in verified state. In-memory; lost on API restart

Agent Filesystem (agent-fs)

VariableDescription
AGENT_FS_API_URLAgent-fs API URL. When set as a global swarm config, enables agent-fs integration with persistent shared filesystem
AGENT_FS_API_KEYPer-agent API key, auto-generated on first boot via agent-fs registration. Stored as agent-scoped secret
AGENT_FS_SHARED_ORG_IDShared org ID for the swarm's agent-fs organization. Auto-created by the lead on first boot
AGENT_FS_DEFAULT_ORG_IDDefault agent-fs org ID used to auto-resolve agent-fs attachment rows on store-progress when orgId is missing. Scope precedence: agent > global
AGENT_FS_DEFAULT_DRIVE_IDDefault agent-fs drive ID used to auto-resolve agent-fs attachment rows on store-progress when driveId is missing. Scope precedence: agent > global

These are managed as swarm config values (via set-config with scope: "global"), not environment variables in .env files. The entrypoint registers agents with agent-fs on first boot and stores API keys as agent-scoped secrets. The runner propagates AGENT_FS_SHARED_ORG_ID to worker processes automatically. The two AGENT_FS_DEFAULT_* keys let the server fill in attachment IDs server-side so the renderer can emit full live-host URLs — per-row IDs always win, and missing config + missing row IDs still falls back to the agent-fs:<path> form.

x402 Payments

Environment variables for the x402 payment module, enabling agents to make USDC micropayments on x402-gated APIs.

Common

VariableDefaultDescription
X402_SIGNER_TYPEAuto-detectedSigner backend: "openfort" or "viem". Auto-detects based on which credentials are set
X402_MAX_AUTO_APPROVE1.00Maximum USD amount to auto-approve per request
X402_DAILY_LIMIT10.00Daily spending limit in USD
X402_NETWORKeip155:84532CAIP-2 network ID. eip155:84532 = Base Sepolia (testnet), eip155:8453 = Base mainnet

Openfort Signer

VariableRequiredDescription
OPENFORT_API_KEYYesOpenfort API key (sk_test_ or sk_live_ prefixed)
OPENFORT_WALLET_SECRETYesP-256 ECDSA key for wallet authentication (base64 encoded)
OPENFORT_WALLET_ADDRESSNoReuse existing wallet address instead of creating a new one

Viem Signer

VariableRequiredDescription
EVM_PRIVATE_KEYYesWallet private key (0x-prefixed hex). Use a burner wallet with minimal funds

Multi-Credential Support

To distribute load across multiple Claude subscriptions, provide multiple credentials as comma-separated values:

# Multiple OAuth tokens — one is randomly selected per session
CLAUDE_CODE_OAUTH_TOKEN=token1,token2,token3

# Also works with API keys
ANTHROPIC_API_KEY=sk-key1,sk-key2

When a session is spawned, the runner splits the credential value by commas and randomly selects one. Each session gets a single credential, distributing load across subscriptions. A log line indicates which credential index was selected (never the credential itself). Single values (no commas) work unchanged — fully backward compatible.

Telemetry

VariableDefaultDescription
ANONYMIZED_TELEMETRYtrue (enabled)Set to false to disable anonymized telemetry. See Telemetry for details
DESPLEGA_TELEMETRY_ENVproductionExplicit telemetry environment tag. Set to development or test for intentional non-production telemetry.

OpenTelemetry

OpenTelemetry traces are disabled unless OTEL_EXPORTER_OTLP_ENDPOINT is set. See Observability with OpenTelemetry for SigNoz setup, emitted spans, and query examples.

VariableDefaultDescription
OTEL_EXPORTER_OTLP_ENDPOINTnoneOTLP HTTP traces endpoint. For SigNoz Cloud, use your region's base ingest URL (e.g. https://ingest.eu2.signoz.cloud) — the SDK appends /v1/traces.
OTEL_EXPORTER_OTLP_HEADERSnoneOTLP exporter headers, for example signoz-ingestion-key=<key>. Treated as sensitive by the secret scrubber
OTEL_EXPORTER_OTLP_PROTOCOLSDK defaultExport protocol. Use http/protobuf for SigNoz Cloud
OTEL_SERVICE_NAMEagent-swarm-api or agent-swarm-worker outside local composeOpenTelemetry service.name. Set to agent-swarm everywhere to keep one service and split by agentswarm.service.role
OTEL_RESOURCE_ATTRIBUTESderived from NODE_ENVComma-separated resource attributes such as deployment.environment=local,env=local,service.namespace=agent-swarm
OTEL_TRACE_POLLOFFWhen set to 1/true, emits trace spans for the worker poll loop (worker.poll) and the /api/poll HTTP endpoint. Skip by default to reduce span volume.

Business-Use Instrumentation

Optional integration with @desplega.ai/business-use for tracking system invariants across the distributed API + worker architecture.

VariableDescription
BUSINESS_USE_API_KEYAPI key from uvx business-use-core@latest init
BUSINESS_USE_URLBU backend URL (default: http://localhost:13370)

SDK enters no-op mode if the API key is missing — safe to omit in environments without a BU backend.

Secrets Encryption

swarm_config rows with isSecret=1 are encrypted at rest using AES-256-GCM (v1.67.0+). The server resolves the encryption key on boot in this order:

  1. SECRETS_ENCRYPTION_KEY env var (base64-encoded 32 bytes)
  2. SECRETS_ENCRYPTION_KEY_FILE pointing at a file containing the base64 key
  3. <data-dir>/.encryption-key file on disk
  4. Auto-generated on first boot (only when the DB has no existing encrypted rows)

Generate a key with:

openssl rand -base64 32 > ./encryption_key
chmod 600 ./encryption_key

Back up and preserve the encryption key alongside your SQLite database. Losing the key means losing all encrypted secrets (API tokens, OAuth creds, etc.) with no recovery path. Do not switch between key sources unless the underlying base64 value is identical.

Reserved keys: API_KEY and SECRETS_ENCRYPTION_KEY are rejected by the swarm_config API (case-insensitive) and must remain environment-only.

Upgrading from plaintext: Legacy secrets are auto-migrated on first boot. If SECRETS_ENCRYPTION_KEY was not set beforehand, a one-time plaintext backup is created at <db-path>.backup.secrets-YYYY-MM-DD.env. Delete this file after verifying your key is backed up.

Priority

When both CLI flags and environment variables are set:

  • CLI flags take precedence over environment variables
  • Inline text (SYSTEM_PROMPT) takes precedence over file (SYSTEM_PROMPT_FILE)

On this page