# Postgres POSTGRES_USER= POSTGRES_PASSWORD= POSTGRES_DB=molecule DATABASE_URL=postgres://USER:PASS@postgres:5432/molecule?sslmode=disable # Redis REDIS_URL=redis://redis:6379 # Platform PORT=8080 # ---- Admin credential — REQUIRED to close issue #684 (AdminAuth bearer bypass) ---- # When ADMIN_TOKEN is set, only this value is accepted on /admin/* and /approvals/* routes. # Without it, any valid workspace bearer token can call admin endpoints (backward compat # fallback, still vulnerable). Set this in every environment, rotate when compromised. # Generate: openssl rand -base64 32 # Store in fly secrets / deployment env — NEVER commit the actual value here. ADMIN_TOKEN= SECRETS_ENCRYPTION_KEY= # 32-byte key (raw or base64). Leave empty for plaintext (dev only). CONFIGS_DIR= # Path to workspace-configs-templates/ (auto-discovered if empty) PLUGINS_DIR= # Path to plugins/ directory (default: /plugins in container) # PLATFORM_URL=http://host.docker.internal:8080 # URL agent containers use to reach the platform; injected into workspace env. Default derives from PORT. # MOLECULE_URL=http://localhost:8080 # Canonical MCP-client URL (mirrors PLATFORM_URL inside containers). Read by the MCP server (mcp-server/) and Molecule MCP tooling. # WORKSPACE_DIR= # Optional global host path bind-mounted to /workspace in every container. Per-workspace workspace_dir column overrides this; if neither is set each workspace gets an isolated Docker named volume. # MOLECULE_ENV=development # Environment label (development/staging/production). Used for log tagging and conditional behaviour. # MOLECULE_ENABLE_TEST_TOKENS= # Set to 1 to expose GET /admin/workspaces/:id/test-token (mints a fresh bearer token for E2E scripts). The route is auto-enabled when MOLECULE_ENV != production; this flag is the explicit override. Leave unset/0 in prod — the route 404s unless enabled. # MOLECULE_ORG_ID= # SaaS only: org UUID set by control plane on tenant machines. When set, workspace provisioning auto-routes through the control plane API instead of Docker. # CP_PROVISION_URL= # Override control plane URL for workspace provisioning (default: https://api.moleculesai.app). Only needed for testing against a non-production control plane. # CORS / rate limiting # CORS_ORIGINS=http://localhost:3000,http://localhost:3001 # Comma-separated allowed origins for the HTTP API. # RATE_LIMIT=600 # Requests/minute per client (default 600). # Activity retention # ACTIVITY_RETENTION_DAYS=7 # Days to keep rows in activity_logs before pruning. # ACTIVITY_CLEANUP_INTERVAL_HOURS=6 # How often the background pruner runs. # Container/runtime detection # MOLECULE_IN_DOCKER= # Set when running the platform inside Docker (accepts 1/0, true/false). Triggers A2A proxy to rewrite 127.0.0.1: agent URLs to Docker bridge hostnames. Auto-detected via /.dockerenv; only set if detection fails or to force off. # Observability (Awareness) # AWARENESS_URL= # If set, injected into workspace containers along with a deterministic AWARENESS_NAMESPACE derived from workspace ID. Enables the cross-session memory MCP server. # GitHub # GITHUB_REPO=owner/repo # Target repo for agent initial_prompt clone (e.g. Molecule-AI/molecule-monorepo). Read inside workspace containers. # GITHUB_TOKEN= # Personal access token / installation token used by agents that clone private repos. Register as a global secret via POST /admin/secrets for propagation to workspace env. Token is used in-URL during clone and then scrubbed from .git/config via `git remote set-url`. # Webhooks # GITHUB_WEBHOOK_SECRET= # HMAC secret used to verify incoming GitHub webhook payloads at /webhooks/github. # CLI clients # MOLECLI_URL=http://localhost:8080 # URL the molecli TUI uses to reach the platform. # Plugin install safeguards (POST /workspaces/:id/plugins) # All three bound the cost of a single install so a slow/malicious # source can't tie up a handler. Defaults are sane for typical use. PLUGIN_INSTALL_BODY_MAX_BYTES=65536 # max request body size (default: 64 KiB) PLUGIN_INSTALL_FETCH_TIMEOUT=5m # duration string; whole fetch+copy deadline PLUGIN_INSTALL_MAX_DIR_BYTES=104857600 # max staged-tree size (default: 100 MiB) # ---- Plugin supply chain hardening (issue #768, PR #775) ---- # Set to 'true' to allow unpinned plugin refs (no #tag/#sha). Local dev only. # When unset or 'false' (default), installing a plugin from a source without # an explicit ref is rejected — prevents supply chain attacks via floating HEAD. # NEVER set in production. Pending: PR #775 must merge before this takes effect. PLUGIN_ALLOW_UNPINNED= # Phase 30.7 — remote-agent liveness threshold. Workspaces with # runtime='external' are marked offline if their last_heartbeat_at is # older than this many seconds. Slightly larger than the 60s Redis TTL # so transient WAN hiccups don't flap online/offline. Set to 0 to use # the built-in default (90s). REMOTE_LIVENESS_STALE_AFTER=90 # ---- Workspace hibernation (issue #724, PR #724) ---- # Workspaces with no active tasks hibernate after this many minutes. # Leave empty to disable. Per-workspace override via the hibernation_idle_minutes # column (set via PATCH /workspaces/:id or org.yaml). This env var sets the # platform-wide default applied to workspaces that have no per-workspace setting. # Note: the global-default behaviour (reading this env var) is pending — currently # only the per-workspace DB column is active. Setting this has no effect until that # code lands. HIBERNATION_IDLE_MINUTES=60 # Canvas NEXT_PUBLIC_PLATFORM_URL=http://localhost:8080 NEXT_PUBLIC_WS_URL=ws://localhost:8080/ws # Workspace Runtime ANTHROPIC_API_KEY= OPENROUTER_API_KEY= # OpenRouter API key (openrouter.ai). Use with model: openrouter:anthropic/claude-3.5-haiku. Also acts as the fallback key for the hermes runtime when HERMES_API_KEY is unset. HERMES_API_KEY= # Nous Research Portal API key (inference-prod.nousresearch.com). Used by the hermes runtime; falls back to OPENROUTER_API_KEY if unset. GROQ_API_KEY= # Groq API key (console.groq.com). Use with model: groq:llama-3.3-70b-versatile CEREBRAS_API_KEY= # Cerebras API key (cloud.cerebras.ai). Use with model: cerebras:llama3.1-8b GOOGLE_API_KEY= # Google AI API key (aistudio.google.com). Use with model: google_genai:gemini-2.5-flash MAX_TOKENS=2048 # Max output tokens for OpenRouter requests (default: 2048) LANGGRAPH_RECURSION_LIMIT=500 # LangGraph/DeepAgents max ReAct steps per turn (lib default: 25; raised to 500 — PM fan-out to 6+ reports + synthesis routinely exceeds 100) MODEL_PROVIDER=anthropic:claude-opus-4-7 # Format: provider:model. Providers: anthropic, openai, openrouter, groq, cerebras, google_genai, ollama # ---- Workspace tier resource limits (issue #14) ---- # Per-tier memory/CPU caps applied to each workspace Docker container. # CPU_SHARES follows the Docker convention: 1024 shares == 1 CPU. # Any value <=0 or malformed falls back to the compiled default shown. # Tier 1 is sandboxed (tmpfs, readonly) and is not resource-capped here. TIER2_MEMORY_MB=512 # Standard tier memory cap (default 512 MiB) TIER2_CPU_SHARES=1024 # Standard tier CPU (default 1024 = 1 CPU) TIER3_MEMORY_MB=2048 # Privileged tier memory cap (default 2048 MiB; previously uncapped) TIER3_CPU_SHARES=2048 # Privileged tier CPU (default 2048 = 2 CPU; previously uncapped) TIER4_MEMORY_MB=4096 # Full-host tier memory cap (default 4096 MiB; previously uncapped) TIER4_CPU_SHARES=4096 # Full-host tier CPU (default 4096 = 4 CPU; previously uncapped) # Social Channels (optional — configure per-workspace via API or Canvas) TELEGRAM_BOT_TOKEN= # Telegram Bot API token (talk to @BotFather). Used as default for new Telegram channels. DISCORD_WEBHOOK_URL= # Discord Incoming Webhook URL (Server → Channel → Integrations → Webhooks). Used by Community Manager workspace. # CI/CD Slack notifications (issue #624) # Add SLACK_CI_WEBHOOK_URL as a GitHub Actions secret (repo Settings → Secrets → Actions). # When set, CI failures in platform-build, canvas-build, python-lint, shellcheck, # and e2e-api workflows post an alert to the configured #ci-alerts Slack channel. # Obtain: Slack App → Incoming Webhooks → Add to channel → copy URL. # Leave unset to disable (jobs skip silently — no build failure). SLACK_CI_WEBHOOK_URL= # https://hooks.slack.com/services/... # Langfuse (optional observability) LANGFUSE_HOST=http://langfuse-web:3000 LANGFUSE_PUBLIC_KEY= LANGFUSE_SECRET_KEY= # ---- EU AI Act Annex III compliance — molecule-audit-ledger (#594) ---- # Secret salt for PBKDF2 key derivation (HMAC-SHA256 chain verification). # When set, GET /workspaces/:id/audit derives the HMAC key and verifies the # chain inline, returning "chain_valid": true/false in the response. # When unset, "chain_valid": null — use the CLI to verify: # python -m molecule_audit.verify --agent-id # Must match AUDIT_LEDGER_SALT set in each workspace container. # AUDIT_LEDGER_SALT= # 32+ random bytes (base64 or arbitrary string) # ---- Operator identity (for org-templates/reno-stars/, see OPERATOR_NOTES.md) ---- # These are NOT consumed by the platform itself — they're documented here so # operators of the reno-stars template (and any future operator-personalised # template) know what to set as global_secrets. The platform injects every # global_secret into every workspace container as an env var; the agent # system-prompts reference them via ${VAR_NAME}. OPERATOR_EMAIL= # e.g. you@example.com OPERATOR_PHONE= # e.g. 555-123-4567 (display only, not used for SMS) OPERATOR_TELEGRAM_ID= # numeric Telegram user ID (for bot DMs) GADS_MCC_ID= # Google Ads MCC (manager) account ID, format 123-456-7890 GADS_CUSTOMER_ID= # Google Ads child customer ID, format 987-654-3210 GCP_PROJECT_ID= # Google Cloud project ID (e.g. my-website-123456) GSC_SERVICE_ACCOUNT= # Search Console reporter service account email