# ============================================================ # Discoclaw — Complete Environment Reference # ============================================================ # This is the full reference for all ~90 env vars. # For quick start, see .env.example (only the essentials). # Primary guided setup: run `discoclaw init` (global install). # From source: run `pnpm setup` for guided interactive configuration. # ============================================================ # ---------------------------------------------------------- # REQUIRED — the bot won't start without these # ---------------------------------------------------------- # Your Discord bot token (from https://discord.com/developers/applications) # Important: You must also enable Message Content Intent in the Discord Developer Portal # (Bot page → Privileged Gateway Intents). Without it, the bot silently 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= # ---------------------------------------------------------- # 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= # ---------------------------------------------------------- # CORE — most users will want to review these # ---------------------------------------------------------- # Where the Claude CLI runs (its working directory). # Default: ./workspace (or $DISCOCLAW_DATA_DIR/workspace if DATA_DIR is set) #WORKSPACE_CWD= # Primary runtime adapter for bot messages, crons, summaries, and plan execution. # Valid values: claude | gemini | codex | openai | openrouter # - openai requires OPENAI_API_KEY # - openrouter uses the existing OPENROUTER_API_KEY env-key path, but key presence is config-only # until `!status` (or the startup credential report) shows `openrouter-key: ok` # - claude requires a working Claude CLI # - gemini requires the Gemini CLI (GEMINI_BIN) # Readiness boundary for codex/openai: # - source checkout: `pnpm preflight*` proves config/bootstrap only; see docs/audit/codex-blank-machine-readiness.md # - npm/global install: `discoclaw doctor` / `!doctor` stay config-only; see docs/audit/codex-npm-managed-path.md #PRIMARY_RUNTIME=claude # --- Primary models --- # [DEPRECATED] Model configuration has moved to models.json (managed via !models commands). # RUNTIME_MODEL is still read as a fallback when models.json is missing, but new deployments # should use `!models set chat ` instead. See docs for migration details. # 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 # --- Fast-tier default --- # [DEPRECATED] Model configuration has moved to models.json (managed via !models commands). # DISCOCLAW_FAST_MODEL is still read as a fallback when models.json is missing, but new # deployments should use `!models set fast ` instead. # Sets the default model for all "small" tasks (summary, cron, cron auto-tag, task auto-tag). # Valid tiers: fast | capable | deep. Individual overrides (DISCOCLAW_SUMMARY_MODEL, etc.) still win when set. #DISCOCLAW_FAST_MODEL=fast # [DEPRECATED] Fast-tier runtime selection has moved to models.json (managed via !models commands). # Use `!models set fast /` to route fast-tier through a different runtime — # the provider prefix auto-selects the runtime adapter. DISCOCLAW_FAST_RUNTIME is still read # as a fallback when models.json has no fast-tier entry, but new deployments should migrate. # Valid values: claude | gemini | codex | openai | openrouter # If this points at OpenAI, `OPENAI_API_KEY` presence is still config-only. # Source checkouts need separate smoke evidence; npm/global installs need runtime-visible `openai-key: ok`. #DISCOCLAW_FAST_RUNTIME= # --- Tier model overrides --- # Override the concrete model resolved for any runtime × tier combination. # Format: DISCOCLAW_TIER__= # Unset = use the built-in default shown in the comments. # Concrete model names (e.g. sonnet, gpt-4o-mini) are passed through unchanged. # # Claude Code adapter (default: fast=haiku, capable=sonnet): #DISCOCLAW_TIER_CLAUDE_CODE_FAST=haiku #DISCOCLAW_TIER_CLAUDE_CODE_CAPABLE=sonnet #DISCOCLAW_TIER_CLAUDE_CODE_DEEP=claude-opus-4-6 # # Gemini CLI adapter (default: fast=gemini-2.5-flash, capable=gemini-2.5-pro): #DISCOCLAW_TIER_GEMINI_FAST=gemini-2.5-flash #DISCOCLAW_TIER_GEMINI_CAPABLE=gemini-2.5-pro #DISCOCLAW_TIER_GEMINI_DEEP=gemini-2.5-pro # # OpenAI-compatible adapter (default: adapter-default for both tiers): #DISCOCLAW_TIER_OPENAI_FAST=gpt-4o-mini #DISCOCLAW_TIER_OPENAI_CAPABLE=gpt-4o #DISCOCLAW_TIER_OPENAI_DEEP= # # OpenRouter adapter (default: fast=openai/gpt-5-mini, capable=anthropic/claude-sonnet-4.6, deep=anthropic/claude-opus-4.6): # These are optional overrides only; leave unset to use the shipped built-in tier map. #DISCOCLAW_TIER_OPENROUTER_FAST=openai/gpt-5-mini #DISCOCLAW_TIER_OPENROUTER_CAPABLE=anthropic/claude-sonnet-4.6 #DISCOCLAW_TIER_OPENROUTER_DEEP=anthropic/claude-opus-4.6 # # Codex CLI adapter (default: adapter-default for both tiers): #DISCOCLAW_TIER_CODEX_FAST= #DISCOCLAW_TIER_CODEX_CAPABLE= #DISCOCLAW_TIER_CODEX_DEEP= # # Tool-tier map — override which tool tier a model resolves to. # Comma-separated model=tier pairs. Tiers: basic, standard, full. # Format: haiku=basic,sonnet=standard,opus=full # Unset = built-in pattern matching (haiku/flash→basic, sonnet→standard, opus/unknown→full). #DISCOCLAW_TOOL_TIER_MAP= # 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 adapter --- # When GEMINI_API_KEY is set, the REST API adapter is used (zero startup overhead). # When unset, falls back to the Gemini CLI binary (requires `gemini` in PATH). #GEMINI_API_KEY= # Path to the Gemini CLI binary (default: gemini). Only used when GEMINI_API_KEY is unset. #GEMINI_BIN=gemini # Default model for the Gemini adapter. #GEMINI_MODEL=gemini-2.5-pro # Log level: trace | debug | info | warn | error | fatal #LOG_LEVEL=info # ============================================================ # CORE SUBSYSTEMS — enabled by default, configure as needed # ============================================================ # ---------------------------------------------------------- # Cron — forum-based scheduled tasks (enabled by default) # ---------------------------------------------------------- # Forum channel ID is auto-created on first connect (see AUTO-DETECTED above). # Model tier for cron execution: fast | capable | deep (concrete names accepted as passthrough). #DISCOCLAW_CRON_MODEL=fast # Default model tier for cron job execution (fast | capable | deep, concrete names accepted as passthrough). # Defaults to capable (resolves to Sonnet on Claude Code) — avoids using Opus on routine cron work. # Per-job overrides and AI-classified model still win when set. Override at runtime via # `!models set cron-exec `. #DISCOCLAW_CRON_EXEC_MODEL=capable # Enable cron Discord actions (CRUD via Discord action blocks). #DISCOCLAW_DISCORD_ACTIONS_CRONS=1 # Persistent stats directory (run counts, last run time, status). #DISCOCLAW_CRON_STATS_DIR= # AI auto-tagging for cron purpose + model tier. #DISCOCLAW_CRON_AUTO_TAG=1 #DISCOCLAW_CRON_AUTO_TAG_MODEL=fast # Runtime tag-map file (seeded from scripts/cron/cron-tag-map.json on first boot). #DISCOCLAW_CRON_TAG_MAP= # Default timezone for cron schedules that don't specify one (IANA format, e.g. America/New_York). # Falls back to the system timezone if unset or invalid. #DEFAULT_TIMEZONE= # Set to 0 to disable cron entirely. #DISCOCLAW_CRON_ENABLED=1 # ---------------------------------------------------------- # Tasks — task tracking (enabled by default) # ---------------------------------------------------------- # Forum channel ID is auto-created on first connect (see AUTO-DETECTED above). # Guild ID — used for task sync bootstrap and system channel bootstrap. # Also used for System channel bootstrap when the bot is in multiple servers. DISCORD_GUILD_ID= # Runtime tag-map file (seeded from scripts/tasks/tag-map.json on first boot). #DISCOCLAW_TASKS_TAG_MAP= # Skip Phase 5 (thread reconciliation) during task sync. Useful for shared-forum deployments # where multiple instances share the same forum and you don't want cross-instance archival. #DISCOCLAW_TASKS_SYNC_SKIP_PHASE5=0 # Enable/disable retries after sync failures. #DISCOCLAW_TASKS_SYNC_FAILURE_RETRY_ENABLED=1 # Delay before failure retries (ms). #DISCOCLAW_TASKS_SYNC_FAILURE_RETRY_DELAY_MS=30000 # Delay before deferred-close retries (ms). #DISCOCLAW_TASKS_SYNC_DEFERRED_RETRY_DELAY_MS=30000 # 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= # When 1 and MENTION_USER set, open task starters keep @mention for sidebar visibility; removed on close. #DISCOCLAW_TASKS_SIDEBAR=0 #DISCOCLAW_TASKS_AUTO_TAG=1 #DISCOCLAW_TASKS_AUTO_TAG_MODEL=fast # Set to 0 to disable tasks entirely. #DISCOCLAW_TASKS_ENABLED=1 # Prefix for generated task IDs (e.g. ws-001). #DISCOCLAW_TASKS_PREFIX=ws # ---------------------------------------------------------- # Discord actions — let Claude manage your server (enabled by default) # ---------------------------------------------------------- # Master switch — must be 1 for any action category to work (default: 1). # Enabling it unlocks the defer command below (and all other action categories). #DISCOCLAW_DISCORD_ACTIONS=1 # Per-category flags (only active when master switch is 1): #DISCOCLAW_DISCORD_ACTIONS_CHANNELS=1 #DISCOCLAW_DISCORD_ACTIONS_MESSAGING=1 # Comma-separated absolute directory paths allowed for the sendFile Discord action. # Defaults to /tmp when unset. DISCOCLAW_DATA_DIR and WORKSPACE_CWD are always # auto-included when configured. Symlinks are resolved via fs.realpath() before checking. #DISCOCLAW_SENDFILE_ALLOWED_DIRS=/tmp #DISCOCLAW_DISCORD_ACTIONS_GUILD=1 # Intentionally off — moderation actions require explicit opt-in. #DISCOCLAW_DISCORD_ACTIONS_MODERATION=0 #DISCOCLAW_DISCORD_ACTIONS_POLLS=1 #DISCOCLAW_DISCORD_ACTIONS_TASKS=1 # Allow the AI to self-initiate forge runs (draft + audit loops) via action blocks. # Requires DISCOCLAW_FORGE_COMMANDS_ENABLED=1. Only one forge at a time. Default: 0. #DISCOCLAW_DISCORD_ACTIONS_FORGE=0 # Allow the AI to create, inspect, approve, run, and close plans via action blocks. # Requires DISCOCLAW_PLAN_COMMANDS_ENABLED=1. Default: 0. #DISCOCLAW_DISCORD_ACTIONS_PLAN=0 # Allow the AI to read/write durable memory (facts, preferences) via action blocks. # Requires DISCOCLAW_DURABLE_MEMORY_ENABLED=1. Default: 1. #DISCOCLAW_DISCORD_ACTIONS_MEMORY=1 # Allow the AI to change status, activity, and nickname at runtime. #DISCOCLAW_DISCORD_ACTIONS_BOT_PROFILE=1 # Allow the AI to defer another invocation (e.g., "check on the forge run in 10 minutes"). # The scheduler enforces DISCOCLAW_DISCORD_ACTIONS=1 and respects the requesting message's # channel permissions. Nested defers are allowed up to DEFER_MAX_DEPTH (default: 4). DISCOCLAW_DISCORD_ACTIONS_DEFER=1 # Optional guard rails keep deferred invocations within safe bounds. # Maximum delay (seconds) the scheduler will accept for defer commands (default: 1800 / 30 min). #DISCOCLAW_DISCORD_ACTIONS_DEFER_MAX_DELAY_SECONDS=1800 # Maximum number of pending deferred invocations allowed at once (default: 5). #DISCOCLAW_DISCORD_ACTIONS_DEFER_MAX_CONCURRENT=5 # Maximum nesting depth for deferred runs. Depth 0 = original message, depth 1 = first defer, etc. # When depth reaches this limit, the defer action is disabled for that run (default: 4). #DISCOCLAW_DISCORD_ACTIONS_DEFER_MAX_DEPTH=4 # Allow the AI to schedule repeating self-invocations with loopCreate/loopList/loopCancel. # Loops are inspectable recurring jobs and should be preferred over chaining repeated defers. # Default: on. Set to 0 to disable. #DISCOCLAW_DISCORD_ACTIONS_LOOP=1 # Minimum interval (seconds) accepted for loopCreate (default: 60). #DISCOCLAW_DISCORD_ACTIONS_LOOP_MIN_INTERVAL_SECONDS=60 # Maximum interval (seconds) accepted for loopCreate (default: 86400 / 24 h). #DISCOCLAW_DISCORD_ACTIONS_LOOP_MAX_INTERVAL_SECONDS=86400 # Maximum number of active loops allowed at once (default: 5). #DISCOCLAW_DISCORD_ACTIONS_LOOP_MAX_CONCURRENT=5 # Allow the AI to spawn parallel sub-agents in target channels. # Each spawned agent is a fire-and-forget invocation that posts output to the specified channel. # Spawned agents run at recursion depth 1 and cannot themselves spawn further agents. # Default: on. Set to 0 to disable. #DISCOCLAW_DISCORD_ACTIONS_SPAWN=1 # Maximum number of spawn actions that may run concurrently (default: 8). #DISCOCLAW_DISCORD_ACTIONS_SPAWN_MAX_CONCURRENT=8 # ---------------------------------------------------------- # Canvas Activities — Discord Embedded App SDK / Activity shell # ---------------------------------------------------------- # Requires manual Discord Developer Portal setup plus public HTTPS exposure for the # mapped Activity endpoint. When local setup is incomplete, explicit requests return # a setup walkthrough instead of silently failing. # Master switch for the experimental canvas subsystem. Default: off. # Fresh installs and upgraded installs both require an explicit opt-in with =1, then a bot restart. # If this variable is unset or removed, canvas stays off after restart, including on upgraded installs. # After enabling it, complete the Discord Developer Portal setup (URL Mapping + enable Activities). # Canvas prompt guidance is only injected when local readiness passes or the user explicitly # asks for an interactive canvas/chart/dashboard/diff/artifact. #DISCOCLAW_CANVAS_ENABLED=1 # Dedicated loopback canvas server port (default: 9402). #DISCOCLAW_CANVAS_PORT=9402 # Optional artifact root. Default: $DISCOCLAW_DATA_DIR/canvas/artifacts (or ./data/canvas/artifacts in source checkout). #DISCOCLAW_CANVAS_ARTIFACT_DIR= # Cap-based LRU limit for generated artifacts (default: 1000). #DISCOCLAW_CANVAS_MAX_ARTIFACTS=1000 # Pending launch TTL in seconds before a clicked launch button expires (default: 120). #DISCOCLAW_CANVAS_PENDING_LAUNCH_TTL_SECONDS=120 # Trusted file-export bridge (default: on). Set to 0 to keep canvas read-only. # This bridge is export-only; it does not grant arbitrary workspace write access. #DISCOCLAW_CANVAS_WRITE_BRIDGE_ENABLED=1 # Optional export root. Default: $WORKSPACE_CWD/exports/canvas #DISCOCLAW_CANVAS_EXPORT_DIR= # Maximum bytes accepted by the trusted export bridge (default: 5242880 / 5 MiB). #DISCOCLAW_CANVAS_EXPORT_MAX_BYTES=5242880 # Optional explicit Discord application ID override. When unset, discoclaw falls back to the logged-in bot application's ID. #DISCORD_CLIENT_ID= # 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 — uncomment sections you need # ============================================================ # ---------------------------------------------------------- # Channel restrictions # ---------------------------------------------------------- # Restrict the bot to specific guild channel IDs (comma/space-separated). # DMs are still allowed. For threads, allowlist the parent channel ID. #DISCORD_CHANNEL_IDS= # Require a channel-context file to exist before responding in a channel. #DISCORD_REQUIRE_CHANNEL_CONTEXT=1 # Auto-create channel context scaffold on first message in a new channel. #DISCORD_AUTO_INDEX_CHANNEL_CONTEXT=1 # Auto-join threads so the bot can respond inside them. # Note: private threads still require manually adding the bot. #DISCORD_AUTO_JOIN_THREADS=1 # ---------------------------------------------------------- # Reaction handler (trigger AI via emoji reactions) # ---------------------------------------------------------- # Master switch — when enabled, reacting to a message with any emoji # triggers the AI to respond to that message (allowlist still applies). #DISCOCLAW_REACTION_HANDLER=0 # Ignore reactions on messages older than this many hours (prevents # accidental triggers when scrolling through old history). #DISCOCLAW_REACTION_MAX_AGE_HOURS=24 # Reaction-remove handler — fires when a user removes a reaction. # Disabled by default; useful for workflows where un-reacting has meaning. #DISCOCLAW_REACTION_REMOVE_HANDLER=0 # Note: 🛑 reactions on bot in-progress messages are reserved for aborting the active stream and will never trigger an AI invocation. # ---------------------------------------------------------- # Memory & summaries # ---------------------------------------------------------- # Rolling AI-generated summaries of past conversations. #DISCOCLAW_SUMMARY_ENABLED=1 #DISCOCLAW_SUMMARY_MODEL=fast #DISCOCLAW_SUMMARY_MAX_CHARS=2000 #DISCOCLAW_SUMMARY_EVERY_N_TURNS=5 # Estimated token threshold for one-pass summary recompression. #DISCOCLAW_SUMMARY_MAX_TOKENS=1500 # Compression target ratio used when recompression runs (target = max_tokens * ratio). #DISCOCLAW_SUMMARY_TARGET_RATIO=0.65 # Override storage directory for rolling summaries. #DISCOCLAW_SUMMARY_DATA_DIR= # Durable per-user facts/preferences (manual via !memory commands). #DISCOCLAW_DURABLE_MEMORY_ENABLED=1 #DISCOCLAW_DURABLE_INJECT_MAX_CHARS=2000 #DISCOCLAW_DURABLE_MAX_ITEMS=200 # Shadow mode for durable memory supersession: log supersession matches without actually deprecating. # Set to 1 to observe what the model would supersede before enabling live deprecation. #DISCOCLAW_DURABLE_SUPERSESSION_SHADOW=0 #DISCOCLAW_MEMORY_COMMANDS_ENABLED=1 # Override storage directory for durable memory. #DISCOCLAW_DURABLE_DATA_DIR= # Cross-channel short-term memory (per-guild, per-user ring buffer). # Records recent exchanges across public channels for cross-channel awareness. #DISCOCLAW_SHORTTERM_MEMORY_ENABLED=0 #DISCOCLAW_SHORTTERM_MAX_ENTRIES=20 #DISCOCLAW_SHORTTERM_MAX_AGE_HOURS=6 #DISCOCLAW_SHORTTERM_INJECT_MAX_CHARS=1000 # Override storage directory for short-term memory. #DISCOCLAW_SHORTTERM_DATA_DIR= # Auto-extract notable facts from user messages into durable memory. # Runs after rolling summary generation. Default on. #DISCOCLAW_SUMMARY_TO_DURABLE_ENABLED=1 # Consolidate durable memory when active item count reaches this threshold. # Merges near-duplicates and removes stale items via a fast-tier model call. # Set to 0 to disable automatic consolidation (default: 50). #DISCOCLAW_MEMORY_CONSOLIDATION_THRESHOLD=50 # Model tier or name used for consolidation (default: fast). #DISCOCLAW_MEMORY_CONSOLIDATION_MODEL=fast # Character budget for recent conversation history in prompts (0 = disabled). #DISCOCLAW_MESSAGE_HISTORY_BUDGET=3000 # 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/none 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 # ---------------------------------------------------------- # Cold storage — vector-indexed conversation history (off by default) # ---------------------------------------------------------- # Master switch — enables SQLite + sqlite-vec backed long-term memory. # When enabled, messages are chunked, embedded, and stored for semantic # retrieval. Matching context is injected into prompts automatically. #DISCOCLAW_COLD_STORAGE_ENABLED=0 # API key for the embedding provider. Falls back to OPENAI_API_KEY when unset. # For the default "openai" provider, this is your OpenAI API key. #COLD_STORAGE_API_KEY= # Embedding provider: openai (default) or openai-compat (any OpenAI-compatible API). #COLD_STORAGE_PROVIDER=openai # Model name for embeddings (required for openai-compat; optional for openai). #COLD_STORAGE_MODEL= # Embedding dimensions (required for openai-compat; optional for openai). #COLD_STORAGE_DIMENSIONS= # Base URL for the embedding API (required for openai-compat; optional for openai). #COLD_STORAGE_BASE_URL= # Path to the SQLite database file. Default: /cold-storage.db #COLD_STORAGE_DB_PATH= # Max characters for the cold-storage prompt section injected into each prompt (default: 1500). #DISCOCLAW_COLD_STORAGE_INJECT_MAX_CHARS=1500 # Max search results returned per query (default: 10). #DISCOCLAW_COLD_STORAGE_SEARCH_LIMIT=10 # Comma-separated channel IDs to restrict cold-storage ingestion and retrieval. # When set, only messages from these channels are stored/searched. Empty = all channels. #COLD_STORAGE_CHANNEL_FILTER= # HyDE (Hypothetical Document Embedding) — generate a hypothetical answer before # embedding, improving semantic search when queries are short or use different # vocabulary than stored content. Only the vector leg is affected; FTS5 keyword # search still uses the raw query. Enabled by default; set to 0 to disable. #DISCOCLAW_COLD_STORAGE_HYDE_ENABLED=1 # Model used to generate the hypothetical document. Any chat-capable model string # accepted by the AI runtime (e.g. "anthropic/claude-sonnet-4-5"). Falls back to a # sensible default when unset. #COLD_STORAGE_HYDE_MODEL= # ---------------------------------------------------------- # Bot identity # ---------------------------------------------------------- # Bot display name (server nickname). Falls back to workspace/IDENTITY.md name, then "Discoclaw". #DISCOCLAW_BOT_NAME= # Presence status on startup: online | idle | dnd | invisible (default: don't set) #DISCOCLAW_BOT_STATUS= # Activity text on startup (empty = no activity) #DISCOCLAW_BOT_ACTIVITY= # Activity type: Playing (default) | Listening | Watching | Competing | Custom #DISCOCLAW_BOT_ACTIVITY_TYPE=Playing # Avatar image: absolute file path or URL (applied once on startup; empty = don't change) #DISCOCLAW_BOT_AVATAR= # ---------------------------------------------------------- # Status & observability # ---------------------------------------------------------- # Channel name or ID to post status embeds (bot online/offline, errors). #DISCOCLAW_STATUS_CHANNEL= # Enable health commands (`!health`, `!health verbose`) for allowlisted users. #DISCOCLAW_HEALTH_COMMANDS_ENABLED=1 # Optional subset allowlist for `!health verbose` (comma/space-separated IDs). # Empty = any allowlisted user can use verbose mode. #DISCOCLAW_HEALTH_VERBOSE_ALLOWLIST= # ---------------------------------------------------------- # Advanced / debug # ---------------------------------------------------------- # Data root — if set, workspace defaults to $DISCOCLAW_DATA_DIR/workspace. #DISCOCLAW_DATA_DIR= # Content directory override. #DISCOCLAW_CONTENT_DIR= # Force re-create workspace/BOOTSTRAP.md from the template on next startup (set to 1; auto-clears after first boot). #DISCOCLAW_FORCE_BOOTSTRAP=0 # Enable per-session runtime isolation. #DISCOCLAW_RUNTIME_SESSIONS=1 # Path to claude CLI binary (if not on $PATH). #CLAUDE_BIN=claude # Forward Claude CLI stderr to Discord (useful for debugging). #CLAUDE_ECHO_STDIO=0 # Pass --verbose to the Claude CLI for increased output detail. # Requires CLAUDE_OUTPUT_FORMAT=stream-json (auto-disabled with text format). #CLAUDE_VERBOSE=0 # Write Claude CLI debug logs to this file. #CLAUDE_DEBUG_FILE= # Skip slow MCP plugin init in headless/systemd contexts. #CLAUDE_STRICT_MCP_CONFIG=1 # Dump resolved runtime config at startup. #DISCOCLAW_DEBUG_RUNTIME=0 # Per-group working directories. #GROUPS_DIR= #USE_GROUP_DIR_CWD=0 # Tools available to the runtime (Glob, Grep, Write now included by default). #RUNTIME_TOOLS=Bash,Read,Write,Edit,Glob,Grep,WebSearch,WebFetch # Fallback model tier when primary is overloaded: fast | capable | deep (concrete names accepted as passthrough). #RUNTIME_FALLBACK_MODEL=fast # Max USD spend per Claude CLI process. One-shot: per invocation. # Multi-turn: per session lifetime (accumulates across turns). Recommend $5-10. #RUNTIME_MAX_BUDGET_USD=5.00 # Append to Claude's system prompt (pre-loads PA identity, skips workspace PA file reads). # Max 4000 chars. Condense SOUL.md + IDENTITY.md + USER.md + TOOLS.md content here. # Note: Do not set this on first run before workspace/BOOTSTRAP.md has been consumed, # as the skip logic also bypasses BOOTSTRAP.md loading. #CLAUDE_APPEND_SYSTEM_PROMPT= # 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= # Sets the systemd unit / launchd label name used by !restart and !update apply. # Default: discoclaw. Ignored when DC_RESTART_CMD is set (that overrides the entire command). #DISCOCLAW_SERVICE_NAME=discoclaw # Disable the local operator dashboard HTTP server inside the main discoclaw process. # It is enabled by default and bound to 127.0.0.1; see DISCOCLAW_DASHBOARD_TRUSTED_HOSTS # for Tailscale/LAN access. When DISCOCLAW_DASHBOARD_TRUSTED_HOSTS is set, the server # binds to 0.0.0.0 and accepts only loopback Host headers plus the trusted list. #DISCOCLAW_DASHBOARD_ENABLED=0 # Operator dashboard port (default: 9401). #DISCOCLAW_DASHBOARD_PORT=9401 # Comma-separated Host header allowlist for dashboard access over Tailscale or another # trusted network path. Supports hostnames and IPv4 addresses only; IPv6 literals are # rejected because Host parsing is ambiguous here. Example: #DISCOCLAW_DASHBOARD_TRUSTED_HOSTS=phone.tailnet.ts.net,100.64.0.12 # Global cap on parallel runtime invocations across all Discord sessions (0 = unlimited). #DISCOCLAW_MAX_CONCURRENT_INVOCATIONS=3 # Max depth for chained action follow-ups (e.g. defer → action → response). 0 = disabled. #DISCOCLAW_ACTION_FOLLOWUP_DEPTH=3 # Timeout (ms) before a pending Discord action auto-follow-up is marked stalled. Default: 30000. #DISCOCLAW_ACTION_FOLLOWUP_TIMEOUT_MS=30000 # Timeout for runtime invocations (ms). #RUNTIME_TIMEOUT_MS=1800000 # Global runtime supervisor wrapper (off by default; preserves legacy behavior). # When enabled, all runtime invocations run through plan -> execute -> evaluate -> decide. #DISCOCLAW_GLOBAL_SUPERVISOR_ENABLED=0 # Emit supervisor cycle audit JSON on stdout or stderr. #DISCOCLAW_GLOBAL_SUPERVISOR_AUDIT_STREAM=stderr # Max supervisor cycles before forced bail (must be >= 1). #DISCOCLAW_GLOBAL_SUPERVISOR_MAX_CYCLES=3 # Max retries allowed across cycles (must be >= 0). #DISCOCLAW_GLOBAL_SUPERVISOR_MAX_RETRIES=2 # Max escalation prompt level applied across retries (must be >= 0). #DISCOCLAW_GLOBAL_SUPERVISOR_MAX_ESCALATION_LEVEL=2 # Hard cap on total streamed events across all cycles (must be >= 1). #DISCOCLAW_GLOBAL_SUPERVISOR_MAX_TOTAL_EVENTS=5000 # Wall-time cap for the full supervisor loop (ms). 0 disables wall-time cap. #DISCOCLAW_GLOBAL_SUPERVISOR_MAX_WALL_TIME_MS=0 # Multi-turn mode: persistent subprocess per session, keeping session context across messages (default: 1). #DISCOCLAW_MULTI_TURN=1 # Timeout (ms) before a multi-turn process is considered hung and restarted. #DISCOCLAW_MULTI_TURN_HANG_TIMEOUT_MS=60000 # Idle timeout (ms) before an inactive multi-turn process is recycled. #DISCOCLAW_MULTI_TURN_IDLE_TIMEOUT_MS=300000 # Maximum concurrent multi-turn processes (per bot instance). #DISCOCLAW_MULTI_TURN_MAX_PROCESSES=5 # Enable session-ID scanning to detect and resume existing Claude sessions. #DISCOCLAW_SESSION_SCANNING=1 # Parse tool-use events during streaming for better progress reporting and stall suppression. #DISCOCLAW_TOOL_AWARE_STREAMING=1 # Render a denser "Thinking..." streaming preview tail (more lines + wider logs + richer tool signals). # Helps previews update more visibly during long runs; action tags are still stripped from preview text. #DISCOCLAW_STREAM_PREVIEW_RAW=0 # Stream stall detection: kill one-shot process if no stdout/stderr for this long (ms). 0 = disabled. (default: 1800000) #DISCOCLAW_STREAM_STALL_TIMEOUT_MS=1800000 # Progress stall timeout: alert after this many ms with no progress event (ms). 0 = disabled. (default: 1800000) #DISCOCLAW_PROGRESS_STALL_TIMEOUT_MS=1800000 # Stream stall warning: show user-visible warning in Discord after this many ms of no events. 0 = disabled. (default: 300000) #DISCOCLAW_STREAM_STALL_WARNING_MS=60000 # Enable long-run watchdog follow-up status updates. # Normal path: after the threshold delay, a deferred "Still running..." check-in is posted. # Recovery path: lifecycle state is persisted and swept on startup so interrupted long-running # runs still get a final status update after restart. # Persistence-first lifecycle: run completion is persisted before attempting the final Discord # post/edit, and finalPosted is set only after a successful post/edit. Crash boundaries may # duplicate follow-up/final updates, but should not omit them. Set to 0 to disable watchdog # follow-up posting entirely. #DISCOCLAW_COMPLETION_NOTIFY=1 # Delay (ms) before the in-process "Still running..." follow-up timer fires. Fast runs shorter # than this are considered non-long-running and do not post watchdog follow-ups. Default: 30000. #DISCOCLAW_COMPLETION_NOTIFY_THRESHOLD_MS=30000 # ---------------------------------------------------------- # Plan & Forge — AI-assisted planning and implementation # ---------------------------------------------------------- # Enable/disable !plan and !forge commands. Default: 0 (off). # When off, !plan and !forge respond with a friendly nudge explaining how to enable. #DISCOCLAW_PLAN_COMMANDS_ENABLED=0 #DISCOCLAW_FORGE_COMMANDS_ENABLED=0 # Phase decomposition for approved plans. #PLAN_PHASES_ENABLED=1 # Max files per phase batch during decomposition. #PLAN_PHASE_MAX_CONTEXT_FILES=5 # Per-phase execution timeout (ms). Default: 1800000 (30 min). #PLAN_PHASE_TIMEOUT_MS=1800000 # Max audit-fix attempts per phase before marking failed. #PLAN_PHASE_AUDIT_FIX_MAX=3 # Default heartbeat interval (ms) for command-path phase progress updates # in `!plan run*` and `!forge`. Set to 0 to disable periodic heartbeats; # phase starts/transitions and the single terminal outcome still post. #PLAN_FORGE_HEARTBEAT_INTERVAL_MS=45000 # Max draft-audit-revise loops before CAP_REACHED. #FORGE_MAX_AUDIT_ROUNDS=5 # Model overrides for forge roles (fall back to RUNTIME_MODEL). #FORGE_DRAFTER_MODEL= #FORGE_AUDITOR_MODEL= # Per-agent timeout within forge (ms). #FORGE_TIMEOUT_MS=1800000 # Min interval between Discord progress message edits (ms). #FORGE_PROGRESS_THROTTLE_MS=3000 # Enabling this immediately approves/runs clean plans (no blocking/medium/minor severity markers); # disabling it keeps the manual `!plan approve` + `!plan run` prompts. #FORGE_AUTO_IMPLEMENT=1 # ---------------------------------------------------------- # Multi-provider runtime overrides # ---------------------------------------------------------- # Route the forge drafter to a non-Claude runtime. # Valid values: "codex" (Codex CLI), "openai" (OpenAI-compatible HTTP API), "openrouter" (OpenRouter). #FORGE_DRAFTER_RUNTIME= # Route the forge auditor to a non-Claude runtime. # Valid values: "codex" (Codex CLI), "openai" (OpenAI-compatible HTTP API), "openrouter" (OpenRouter). #FORGE_AUDITOR_RUNTIME= # --- Codex CLI adapter --- # Path to the Codex CLI binary (default: codex). #CODEX_BIN=codex # Readiness note: CODEX_BIN / CODEX_HOME only configure the path; they do not prove the current Codex session can authenticate. # Source checkouts use the manual `codex exec ...` gate from docs/audit/codex-blank-machine-readiness.md. # npm/global installs still have no shipped `discoclaw codex auth-smoke`; see docs/audit/codex-npm-managed-path.md. # Optional: isolate Codex state/sessions from ~/.codex (helps avoid stale rollout DB issues). #CODEX_HOME=/absolute/path/to/.codex-home-discoclaw # Default model for the Codex CLI adapter. Used when FORGE_AUDITOR_MODEL is not set. #CODEX_MODEL=gpt-5.4 # WARNING: disables Codex approval prompts and sandbox protections (full-access mode). # Equivalent to passing --dangerously-bypass-approvals-and-sandbox to codex exec. #CODEX_DANGEROUSLY_BYPASS_APPROVALS_AND_SANDBOX=0 # Disable Codex session persistence/resume (workaround for session DB issues). #CODEX_DISABLE_SESSIONS=0 # --- OpenAI-compatible HTTP adapter --- # API key for the OpenAI-compatible adapter. Required when FORGE_AUDITOR_RUNTIME=openai. # Readiness note: key presence only satisfies config checks. # Source checkouts: run `OPENAI_SMOKE_TEST_TIERS= pnpm test` for the routed OpenAI path. # npm/global installs: start discoclaw and confirm `!status` or the startup credential report shows `openai-key: ok`. #OPENAI_API_KEY= # Base URL (override for proxies, Azure OpenAI, Ollama, etc.). #OPENAI_BASE_URL=https://api.openai.com/v1 # Default model when FORGE_AUDITOR_MODEL is not set. #OPENAI_MODEL=gpt-4o # Enable tool use (function calling) for OpenAI-compat and OpenRouter adapters. # When enabled, models can autonomously read files, run commands, edit code, etc. # via the standard OpenAI function-calling protocol with a server-side tool loop. # File/path access is scoped to the workspace CWD (WORKSPACE_CWD) plus any # additional directories from --add-dir / group CWD configuration. # Default: 0 (disabled — streaming text only). #OPENAI_COMPAT_TOOLS_ENABLED=0 # --- OpenRouter adapter --- # API key for OpenRouter. Required when PRIMARY_RUNTIME=openrouter or FORGE_*_RUNTIME=openrouter. # Treat key presence as config-only until `!status` (or the startup credential report) # shows `openrouter-key: ok` for the shipped runtime path. #OPENROUTER_API_KEY= # Base URL (default: OpenRouter API endpoint). #OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 # Default model for the OpenRouter adapter. #OPENROUTER_MODEL=anthropic/claude-sonnet-4.6 # Optional OpenRouter-only provider routing preferences JSON. # Unset by default; set this only when you want operator-specified provider routing. # Passed through as the request `provider` object for OpenRouter chat completions. #OPENROUTER_PROVIDER_PREFERENCES='{"order":["anthropic"],"allow_fallbacks":false}' # ---------------------------------------------------------- # Webhooks — inbound HTTP triggers from external services # ---------------------------------------------------------- # TCP port the webhook server listens on (default: 9400). #DISCOCLAW_WEBHOOK_PORT=9400 # Absolute path to the webhook source config file. # JSON object mapping source names to their config: # { # "github": { "secret": "hmac-secret", "channel": "123456789" }, # "gms": { "secret": "hmac-secret", "channel": "987654321" } # } # - secret: HMAC-SHA256 secret used to verify the X-Hub-Signature-256 header. # - channel: Discord channel name or ID where the webhook posts (reuses cron pipeline). #DISCOCLAW_WEBHOOK_CONFIG= # Set to 1 to enable the webhook server. #DISCOCLAW_WEBHOOK_ENABLED=0 # To expose webhooks to external services, see docs/webhook-exposure.md # ---------------------------------------------------------- # Browser automation (agent-browser) # ---------------------------------------------------------- # Browser automation uses Discoclaw's managed Chrome/Chromium launcher flow. # Run `discoclaw browser setup` to inspect readiness, then `discoclaw browser launch` # for the one-time headed login window and verified CDP handoff. Later launches can # reuse the same profile with `discoclaw browser launch --headless`. # Repo-local source installs may store this managed profile only at the ignored # default `data/browser/` path. Custom in-repo data dirs are refused for this feature. # Chromium path override for the managed launcher. Only needed if auto-discovery or # the bundled browser (from `agent-browser install`) doesn't work. #AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium-browser # ---------------------------------------------------------- # Image generation # ---------------------------------------------------------- # Discoverable by default on the normal user-facing help/manual surfaces: # `!models`, `!models help`, and the normal manual message/follow-up action path # can advertise `imagegen` before setup is complete. # `!models` shows `imagegen` as setup-required when unconfigured; `!models help` # points operators back to env setup because `!models set` does not configure imagegen. # Master switch for actual image generation execution (default: off). # When set to 1 and a provider key is configured, the AI can generate images via # action blocks using OpenAI or Gemini. When left at 0, normal manual/follow-up # invocations return a setup walkthrough instead of generating an image. # Reaction/deferred advertisement rules remain on their existing flag-driven contract, # and loop execution does not use the manual setup walkthrough path. DISCOCLAW_DISCORD_ACTIONS_IMAGEGEN=0 # API key for Gemini image generation (Imagen and native Gemini models). # Leave unset to use OpenAI only. #IMAGEGEN_GEMINI_API_KEY= # Override the default image generation model. If unset, auto-detected: # only IMAGEGEN_GEMINI_API_KEY set → imagen-4.0-generate-001; otherwise → dall-e-3. # OpenAI models: dall-e-3, gpt-image-1 # Gemini Imagen models: imagen-4.0-generate-001, imagen-4.0-fast-generate-001, imagen-4.0-ultra-generate-001 # Gemini native models (text+image in one call): gemini-3.1-flash-image-preview, gemini-3-pro-image-preview #IMAGEGEN_DEFAULT_MODEL= # Note: OpenAI image generation reuses OPENAI_API_KEY (documented above in the # OpenAI-compatible HTTP adapter section). Actual generation stays disabled until # DISCOCLAW_DISCORD_ACTIONS_IMAGEGEN=1 and at least one of OPENAI_API_KEY or # IMAGEGEN_GEMINI_API_KEY is set. # ---------------------------------------------------------- # Voice — Gemini Live voice chat # ---------------------------------------------------------- # Master switch — enables Discord voice interaction (default: off). # Gemini Live handles speech recognition, reasoning, and speech synthesis in one session. #DISCOCLAW_VOICE_ENABLED=0 # Enable voice Discord action category (voiceJoin, voiceLeave, voiceStatus, voiceMute, voiceDeafen). # Requires DISCOCLAW_VOICE_ENABLED=1 to take effect (default: off). #DISCOCLAW_DISCORD_ACTIONS_VOICE=0 # Auto-join voice channels when a non-bot user joins, and auto-leave when the last # non-bot user leaves. Requires DISCOCLAW_VOICE_ENABLED=1 (default: off). #DISCOCLAW_VOICE_AUTO_JOIN=0 # Voice text channel name or ID — used for prompt context and voice-triggered actions. # The old env var DISCOCLAW_VOICE_TRANSCRIPT_CHANNEL is still accepted as a fallback. # Leave unset to skip voice channel context in prompts. #DISCOCLAW_VOICE_HOME_CHANNEL= # e.g. "voice" if using the default scaffold # Text channel name or ID for posting voice transcripts. # Optional — auto-discovered via bootstrap (the bot creates "voice-log" and stores its ID # in system-scaffold.json). Only set this to override the auto-discovered channel. # Leave unset to disable transcript mirroring. #DISCOCLAW_VOICE_LOG_CHANNEL= # e.g. "voice-log" if using the default scaffold # Model for voice AI responses: tier (fast | capable | deep) or concrete name (sonnet, opus, haiku). # Independent of the chat model — allows tuning voice latency vs quality separately from chat. # Switchable at runtime via `!models set voice `. # Default: follows the startup chat model unless overridden here. #DISCOCLAW_VOICE_MODEL=sonnet # Custom system prompt prepended to voice AI invocations. Max 4000 chars. # Use this to set a conversational tone, brevity instructions, or persona for voice responses. #DISCOCLAW_VOICE_SYSTEM_PROMPT= # 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 # Google Gemini API key. Required when voice is enabled. #GEMINI_API_KEY= # Anthropic API key for the optional direct Messages API voice runtime. # When set, `!models set voice claude-api` can bypass CLI cold-start for voice responses. #ANTHROPIC_API_KEY=