# ============================================================ # Discoclaw — Quick Start Configuration # ============================================================ # Copy this file to .env and fill in the REQUIRED values. # Primary guided setup: run `discoclaw init` (global install). # From source: run `pnpm setup` for guided interactive configuration. # For all ~90 options, see .env.example.full # ============================================================ # ---------------------------------------------------------- # REQUIRED — the bot won't start without these # ---------------------------------------------------------- # Your Discord bot token (from https://discord.com/developers/applications) # Important: Enable Message Content Intent in Developer Portal # (Bot → Privileged Gateway Intents) or the bot receives empty messages. DISCORD_TOKEN= # Comma-separated Discord user IDs allowed to talk to the bot. # Empty = nobody can use it (fail-closed). DISCORD_ALLOW_USER_IDS= # User ID to @mention on new task creation. `discoclaw init` / `pnpm setup` # default this to the first DISCORD_ALLOW_USER_IDS entry for fresh installs. #DISCOCLAW_TASKS_MENTION_USER= # ---------------------------------------------------------- # AUTO-DETECTED — written by the bot on first connect; only override if needed # ---------------------------------------------------------- # Tasks forum channel ID. Auto-created by the bot on first guild connect and # persisted to system-scaffold.json. Only set this to override the auto-created channel. #DISCOCLAW_TASKS_FORUM= # Automations (cron) forum channel ID. Auto-created by the bot on first guild # connect and persisted to system-scaffold.json. Only set this to override the auto-created channel. #DISCOCLAW_CRON_FORUM= # Default model for cron job execution: fast | capable | deep (or concrete model names). # Defaults to capable (resolves to Sonnet on Claude Code) — avoids using Opus on routine cron work. # Override at runtime via `!models set cron-exec `. #DISCOCLAW_CRON_EXEC_MODEL=capable # ---------------------------------------------------------- # CORE — most users will want to review these # ---------------------------------------------------------- # Guild (server) ID — used for task sync and system channel bootstrap. # Collected as a required field by `discoclaw init`. DISCORD_GUILD_ID= # Optional custom service name for multi-instance installs. # Written automatically by `discoclaw install-daemon --service-name `. # `discoclaw dashboard`, `!restart`, and other service actions use this to target the correct unit. # Leave unset to use the default service name: discoclaw #DISCOCLAW_SERVICE_NAME=discoclaw # Disable the local operator dashboard HTTP server inside the main discoclaw process. # It is enabled by default and binds to 127.0.0.1. To allow access from a Tailscale # phone/browser without SSH tunneling, set DISCOCLAW_DASHBOARD_TRUSTED_HOSTS to your # tailnet IP or MagicDNS name. #DISCOCLAW_DASHBOARD_ENABLED=0 # Dashboard port (default: 9401). Multi-instance setups on the same machine must use distinct ports. #DISCOCLAW_DASHBOARD_PORT=9401 # Comma-separated Host header allowlist for non-loopback dashboard access. # When set, the dashboard binds to 0.0.0.0 but still rejects all Host headers except # loopback names plus the entries listed here. # Example: phone.tailnet.ts.net,100.64.0.12 #DISCOCLAW_DASHBOARD_TRUSTED_HOSTS= # Canvas Activities are experimental and disabled by default. Set to 1 to enable. # Fresh installs and upgraded installs stay off until you uncomment this with =1, restart the bot, # then complete the Discord Activity setup in the Developer Portal and expose the endpoint over public HTTPS. #DISCOCLAW_CANVAS_ENABLED=1 # Canvas server port (default: 9402). Multi-instance setups on the same machine must use distinct ports. #DISCOCLAW_CANVAS_PORT=9402 # Trusted export bridge for saving files from canvas artifacts into workspace/exports/canvas. # Set this to 0 if you want read-only canvas behavior. #DISCOCLAW_CANVAS_WRITE_BRIDGE_ENABLED=1 # Optional. Enables full Discord OAuth2 user verification for Activities. # When unset, uses bot-verified pre-authorization (sufficient for personal/small-team bots). #DISCORD_ACTIVITY_CLIENT_SECRET= # Optional explicit Discord application ID override. When unset, discoclaw falls back to the logged-in bot application's ID. #DISCORD_CLIENT_ID= # Where the Claude CLI runs (its working directory). # Default: ./workspace (or $DISCOCLAW_DATA_DIR/workspace if DATA_DIR is set) #WORKSPACE_CWD= # Primary startup runtime adapter: claude-cli | gemini-api | codex-cli | openai | openrouter # Startup-only / restart-required boundary: # - PRIMARY_RUNTIME sets the default adapter the instance boots with. # - `!models set chat ` can live-switch the main runtime in memory, but chat runtime swaps do not persist. # - Persistent model-role defaults live in data/models.json. # - Persistent runtime-only overlays live in data/runtime-overrides.json (`voiceRuntime`, `fastRuntime`). # - `!models reset` writes startup-default model strings back into models.json and clears fast/voice runtime overlays; # it does not rewrite PRIMARY_RUNTIME in .env. # Supported runtime-path notes: # - `claude-api` is voice-only and is not a valid PRIMARY_RUNTIME. # - `gemini-api` requires GEMINI_API_KEY. # - `claude-cli` requires a working Claude CLI. Legacy alias `claude` is still accepted. # Proof/readiness boundary notes: # - codex-cli/openai: source-checkout `pnpm preflight*` and npm/global `discoclaw doctor` stay config-only; use the install-mode-specific proof gates. # - openrouter: OPENROUTER_API_KEY is config-only until `!status` or the startup credential report shows `openrouter-key: ok`. #PRIMARY_RUNTIME=claude-cli # If PRIMARY_RUNTIME=codex-cli and you want full-access mode (no approvals/sandbox): #CODEX_DANGEROUSLY_BYPASS_APPROVALS_AND_SANDBOX=1 # Readiness note: `codex-cli` on PATH plus CODEX_* config is not full readiness proof. # Source checkouts still need the separate Codex session-auth gate; npm/global installs still use the same-shell manual Codex check. # Optional: isolate Codex state/sessions from ~/.codex (helps avoid stale rollout DB issues): #CODEX_HOME=/absolute/path/to/.codex-home-discoclaw # Runtime launcher state hardening for CLI providers. # When enabled, launcher state/path errors (e.g. Codex rollout-path corruption) trigger # one automatic retry with CODEX_HOME set to a clean stable home. # Set to 0 to disable this behavior. #DISCOCLAW_CLI_LAUNCHER_STATE_HARDENING=1 # Optional stable home override used by the hardening retry above. # Default: /.codex-home-discoclaw #DISCOCLAW_CODEX_STABLE_HOME=/absolute/path/to/.codex-home-discoclaw # Disable Codex session persistence/resume (workaround for session DB issues): #CODEX_DISABLE_SESSIONS=1 # Emit Codex item lifecycle debug events in stream preview (item.started/item.completed + item.type): #DISCOCLAW_CODEX_ITEM_TYPE_DEBUG=1 # Log each Discord preview line decision (allowed/suppressed + rendered line) to journald: #DISCOCLAW_DEBUG_STREAM_PREVIEW_LINES=1 # Enable long-run completion recovery for Discord replies. # After the threshold delay, the bot posts a deferred "Still running..." check-in. # It also persists bounded recovery state so successful long/tool-heavy runs can still # get a final completion update after restart if the main reply edit/send was interrupted. #DISCOCLAW_COMPLETION_NOTIFY=1 # Delay (ms) before a run is treated as long-running for the watchdog path. Default: 30000. #DISCOCLAW_COMPLETION_NOTIFY_THRESHOLD_MS=30000 # Discord action auto-follow-up stall timeout (ms). Controls when pending follow-up turns are treated as stalled. #DISCOCLAW_ACTION_FOLLOWUP_TIMEOUT_MS=30000 # [DEPRECATED] Model-role configuration now lives in data/models.json (managed via !models commands). # RUNTIME_MODEL is only a startup/default seed for the `chat` role when models.json is missing # or when `!models reset` restores startup defaults. It does not persist chat runtime swaps. # Model tier: fast | capable | deep (provider-agnostic). # Concrete model names (e.g. opus, sonnet, gpt-4o) are still accepted as passthrough. #RUNTIME_MODEL=capable # [DEPRECATED] Plan execution has its own startup default now. When models.json is missing # or reset, DISCOCLAW_PLAN_RUN_MODEL seeds the dedicated `plan-run` role independently. # New deployments should use `!models set plan-run ` instead. #DISCOCLAW_PLAN_RUN_MODEL=capable # Output format for the Claude CLI. stream-json gives smoother streaming. #CLAUDE_OUTPUT_FORMAT=stream-json # Allow Claude to run without permission prompts. This is what makes # headless/Discord operation possible — the Discord allowlist above # is the security boundary instead. #CLAUDE_DANGEROUSLY_SKIP_PERMISSIONS=1 # Gemini API adapter # - PRIMARY_RUNTIME=gemini-api uses the Gemini API directly. #GEMINI_API_KEY= # Default model for Gemini API requests when a role follows the adapter default. #GEMINI_MODEL=gemini-2.5-pro # --- OpenAI-compatible HTTP adapter --- # Readiness note: `OPENAI_API_KEY` presence only satisfies config checks. # Source checkouts need separate `OPENAI_SMOKE_TEST_TIERS=... pnpm test` evidence; npm/global installs need a live `openai-key: ok` check. #OPENAI_API_KEY= # Default OpenAI model when a role follows the adapter default. #OPENAI_MODEL=gpt-4o # Enable tool use (function calling) for OpenAI-compat and OpenRouter adapters. #OPENAI_COMPAT_TOOLS_ENABLED=0 # --- OpenRouter adapter --- # Readiness note: `OPENROUTER_API_KEY` presence only satisfies config checks. # Start discoclaw and confirm `!status` (or the startup credential report) shows `openrouter-key: ok` # before claiming the shipped runtime sees this path. #OPENROUTER_API_KEY= #OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 # Default OpenRouter model when a role follows the adapter default. #OPENROUTER_MODEL=anthropic/claude-sonnet-4.6 # OpenRouter now ships built-in tier defaults for `fast`, `capable`, and `deep`. # Use DISCOCLAW_TIER_OPENROUTER_ only when you want instance-specific overrides. # Optional OpenRouter-only provider routing preferences (JSON string). #OPENROUTER_PROVIDER_PREFERENCES='{"order":["anthropic"],"allow_fallbacks":false}' # Log level: trace | debug | info | warn | error | fatal #LOG_LEVEL=info # Override the default platform-detected restart command used by !restart and # !update apply. Useful for custom setups (e.g. Docker, non-standard service # managers, or running under a different user). If unset, the command is # auto-selected: systemctl --user on Linux, launchctl on macOS. #DC_RESTART_CMD= # ---------------------------------------------------------- # Voice — configure via `pnpm setup` or `discoclaw init` # ---------------------------------------------------------- # Run `pnpm setup` or `discoclaw init` to enable voice interactively, # or set these vars manually to enable Gemini Live voice chat. #DISCOCLAW_VOICE_ENABLED=0 # Gemini Live requires GEMINI_API_KEY. # Gemini Live session rotation threshold (ms). The provider proactively reconnects # before Gemini's ~15 min session limit to minimize audio gap. Default: 780000 (13 min). #DISCOCLAW_GEMINI_SESSION_ROTATION_MS=780000 # Text channel used for voice prompt context and actions (e.g. posting action results, # reading pinned notes). Required for full voice functionality when voice is enabled. #DISCOCLAW_VOICE_HOME_CHANNEL= # e.g. "voice" # Text channel for posting voice transcripts. Optional — auto-discovered via bootstrap # (the bot creates a "voice-log" text channel and stores its ID in system-scaffold.json). # Only set this to override the auto-discovered channel. #DISCOCLAW_VOICE_LOG_CHANNEL= #GEMINI_API_KEY= # Optional voice-only Anthropic runtime for voice responses. # `claude-api` is not a valid PRIMARY_RUNTIME and does not persist in models.json. # Use `!models set voice claude-api` to persist the voice runtime path in runtime-overrides.json. #ANTHROPIC_API_KEY= # ---------------------------------------------------------- # Secret management via Discord DM # ---------------------------------------------------------- # Use !secret in a DM to the bot to add or update .env entries without # restarting or editing files directly. Values are never echoed back. # !secret set KEY=value — add/update an entry # !secret unset KEY — remove an entry # !secret list — list key names (values hidden) # The bot must be restarted (!restart) after changes take effect. # ---------------------------------------------------------- # Token cost optimization (automatic, no config needed) # ---------------------------------------------------------- # Prompt assembly is structured so the static preamble (root policy, tracked # defaults, tracked tools, workspace context) produces byte-identical output # across turns. Anthropic's automatic prefix caching matches the longest # identical prefix and charges ~90% less for cached tokens — no explicit # cache_control parameters or adapter changes required. # # On follow-up turns within an active Discord session, dynamic sections are # trimmed automatically: channel context is excluded from the preamble prefix, # and conversation history is replaced by a compact action-result summary. # Combined, this targets ~12-15k token savings per follow-up turn. # # Cache hit telemetry is logged at LOG_LEVEL=info (search for # "anthropic-cache-telemetry" in journal output). Set LOG_LEVEL=debug for # full prompt section breakdowns. # ---------------------------------------------------------- # Continuation capsule staleness # ---------------------------------------------------------- # Maximum age (ms) of a continuation capsule before it is skipped at injection time. # Prevents stale context from prior conversations bleeding into unrelated sessions. # Capsules with an idle/awaiting currentFocus are always skipped regardless of age. # Default: 7200000 (2 hours). Set to 0 to disable TTL expiry (idle detection still applies). #DISCOCLAW_CAPSULE_TTL_MS=7200000 # ---------------------------------------------------------- # For all ~90 options (subsystems, actions, memory, identity, # observability, advanced/debug), see .env.example.full # ----------------------------------------------------------