# Required UNLESS you run entirely on local or OpenRouter models (see # LOCAL_MODELS_ENABLED / OPENROUTER_ENABLED below). At least one provider must # be configured or the app refuses to start. ANTHROPIC_API_KEY=sk-ant-your-key-here # --- Auth (UI: Auth.js / NextAuth v5 with Google) ----------------------------- # Generate AUTH_SECRET with: openssl rand -base64 32 # AUTH_GOOGLE_ID / AUTH_GOOGLE_SECRET come from a Google Cloud OAuth Client # (Web application). Authorized redirect URIs must include: # - http://localhost:3000/api/auth/callback/google # - https://.fly.dev/api/auth/callback/google # ALLOWED_EMAILS = comma-separated list of Google-account emails permitted to # sign in. Other emails (even with a valid Google login) are rejected. # AUTH_TRUST_HOST = "true" is required when running behind a reverse proxy. # AUTH_URL = public origin of the UI. LEAVE BLANK for local dev (localhost is # inferred). Required on Fly / any public deployment; AUTH_TRUST_HOST alone # isn't enough — without AUTH_URL the post-callback redirect lands on the # container's bind address (0.0.0.0) instead of the public hostname, # e.g. AUTH_URL=https://your-ui-app.fly.dev AUTH_SECRET= AUTH_GOOGLE_ID= AUTH_GOOGLE_SECRET= ALLOWED_EMAILS=alice@example.com,bob@example.com AUTH_TRUST_HOST=true AUTH_URL= # Shared secret between the Next.js proxy and the FastAPI backend. The UI # attaches this as `x-api-key`; the API requires it on every non-exempt # request. Leave unset for `make dev` (gate off); set it to the same random # value on both apps in any deployed environment. Generate with: # openssl rand -hex 32 BACKEND_SHARED_SECRET= # Comma-separated extra CORS origins for the FastAPI backend; localhost is # always allowed. Deployment-only — LEAVE BLANK for local dev: with the # shared-secret gate unset, listing a public origin here lets scripts on # that origin read your local API with credentials. # On deploy: BACKEND_ALLOWED_ORIGINS=https://your-ui-app.fly.dev BACKEND_ALLOWED_ORIGINS= # Model configuration (defaults shown) DEFAULT_MODEL=claude-sonnet-4-6 DEEP_REASONING_MODEL=claude-opus-4-7 ROUTING_MODEL=claude-haiku-4-5-20251001 # Data paths (defaults shown — relative to repo root, override with absolute paths if needed) # VECTOR_STORE_PATH=./chroma_db # COMPANY_PROFILE_PATH=./company/profile.yaml # EPISODIC_DB_PATH=./episodic_memory.db # SQLite for episodic memory, alerts, knowledge review # Feature flags ENABLE_CACHING=true # --- OpenRouter routing ------------------------------------------------------- # Toggle that routes Claude calls through OpenRouter (so usage is billed to # your OpenRouter account) AND unlocks the curated set of non-Anthropic # models (GPT-5, Gemini 2.5 Pro, Llama, DeepSeek, Grok) in the Council UI # dropdown so any agent can be flipped to a non-Anthropic model per-agent. # Off by default — a fresh checkout's behavior is identical to before. OPENROUTER_ENABLED=false # Required when OPENROUTER_ENABLED=true. Get one at https://openrouter.ai. OPENROUTER_API_KEY= # --- Local / self-hosted models ---------------------------------------------- # Route selected model slugs to a local OpenAI-compatible server (Ollama, # LM Studio, vLLM, llama.cpp, …) instead of the Anthropic API. Off by default; # a fresh checkout behaves identically to before. LOCAL_MODELS_ENABLED=false # Base URL of the local server, INCLUDING the version path. Required when # LOCAL_MODELS_ENABLED=true. # Ollama http://localhost:11434/v1 # LM Studio http://localhost:1234/v1 # vLLM http://localhost:8000/v1 LOCAL_BASE_URL= # Optional bearer token. Ollama / LM Studio need none (leave blank); vLLM or a # gateway in front may require one. LOCAL_API_KEY= # Comma-separated model slugs to surface in the Council UI and route locally. # Sent to the server verbatim, so they must match what it serves # (e.g. `ollama list`). Example: llama3.3,qwen2.5:14b LOCAL_MODELS= # Local generation (especially on CPU) can be slow — generous timeout (seconds). LOCAL_TIMEOUT_S=300 # # To run with NO Anthropic key, configure the three lines above AND point the # model settings at local slugs: # DEFAULT_MODEL=llama3.3 # DEEP_REASONING_MODEL=llama3.3 # ROUTING_MODEL=llama3.3 # (Server-side web search has no local equivalent and is disabled for local # models; tool-use quality depends on the model you choose.) # --- Honcho per-person memory ------------------------------------------------ # External memory layer (https://honcho.dev) that gives the Executive a # per-person peer card shared across Slack, Discord, Telegram, email, and the # web UI. When enabled, each turn does one dialectic prefetch + fire-and-forget # sync_turn keyed off the inbound user's Person.id; turns with no matching # Person row pass through with no Honcho call. Self-hosted only (set # HONCHO_BASE_URL to your deployment). Off by default — a fresh checkout # behaves identically to before. HONCHO_ENABLED=false # Required when HONCHO_ENABLED=true. HONCHO_API_KEY= # Self-hosted Honcho endpoint, e.g. http://honcho.internal:8000 HONCHO_BASE_URL= # Workspace id scopes peer cards within a Honcho deployment. Keep stable # across environments unless you intentionally want isolated memory. HONCHO_WORKSPACE_ID=openexec # Hard timeout on the per-turn prefetch. On timeout the turn proceeds with # whatever the builtin episodic block provides (no peer_memory injected). HONCHO_PREFETCH_TIMEOUT_S=3.0 # Override if you're proxying OpenRouter or running an Azure-style gateway. # OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 # OPENROUTER_APP_TITLE="Open Executive" # OPENROUTER_REFERER=https://your-deployment.example.com # OPENROUTER_TIMEOUT_S=180.0 # Web search — Anthropic's native server-side web_search tool. Off by default # since each search is billed separately. Enable to let the Executive look up # live facts (market data, news, regulatory changes, competitor moves). ENABLE_WEB_SEARCH=false WEB_SEARCH_MAX_USES=5 # Optional allowlist OR blocklist (comma-separated bare domains, no scheme). # Set at most one of the two. # WEB_SEARCH_ALLOWED_DOMAINS= # WEB_SEARCH_BLOCKED_DOMAINS= # Slack integration (optional) SLACK_BOT_TOKEN=xoxb-your-bot-token SLACK_APP_TOKEN=xapp-your-app-token # Exec email address — REQUIRED. Must match the Google account authenticated with # Gmail MCP OAuth. No default: the Executive must never operate from a fallback # address because EXEC_EMAIL_ADDRESS silently fell through. EXEC_EMAIL_ADDRESS=exec@example.com # How often the email poller checks for new messages (seconds, default 60) EMAIL_POLL_INTERVAL_SECONDS=60 # Channel access (Email/Telegram/Discord) is roster-driven: only senders # whose channel ID matches a non-archived Person row receive a response. # Manage access via the /people UI; no env-var allowlists. # Telegram integration (optional) TELEGRAM_BOT_TOKEN= # from @BotFather — see docs/telegram_setup.md TELEGRAM_WEBHOOK_SECRET= # any random string; set when registering the webhook # Discord integration (optional) # Setup: create an application at https://discord.com/developers/applications # Enable the "Message Content" privileged intent. Invite with bot + applications.commands scopes. # Run: make discord (in a second shell alongside make dev) # Bot token from the Discord Developer Portal → Bot tab DISCORD_BOT_TOKEN= # Application ID (General Information tab) DISCORD_APP_ID= # comma-separated guild (server) IDs for instant slash-command registration during dev; leave blank for global DISCORD_GUILD_IDS= # default channel ID for outbound notifications/alerts (optional) DISCORD_NOTIFY_CHANNEL_ID= DISCORD_THREAD_RESPONSE_GATE_ENABLED=true # in bot-owned threads, ask Haiku whether each non-mention message warrants a reply (filters side chatter in multi-party threads); set to false to reply to every thread message # Google Chat integration (optional) GOOGLE_CHAT_PROJECT_NUMBER= # numeric project number (not project ID) — see docs/google_chat_setup.md # Auth — set ONE of the following (see docs/google_chat_setup.md for which to use): GOOGLE_CHAT_SERVICE_ACCOUNT_FILE= # Option A: absolute path to SA JSON key (blocked by some org policies) GOOGLE_CHAT_SERVICE_ACCOUNT_EMAIL= # Option B: SA email for impersonation via ADC (gcloud auth application-default login) # Google Workspace MCP (optional — enables Gmail, Calendar, Drive access) # Outbound email is sent via Gmail MCP using the account authenticated below. # Setup: https://github.com/taylorwilsdon/google_workspace_mcp # 1. Create OAuth Desktop credentials at console.cloud.google.com # Enable: Gmail API, Google Calendar API, Google Drive API # 2. Set these two vars, then mint a token (workspace-mcp has no `auth` # subcommand — OAuth fires on the first tool call): # uv run --with mcp python scripts/mint-google-token.py # Sign in as EXEC_EMAIL_ADDRESS. Credentials land in # .gworkspace-credentials/ (gitignored). GOOGLE_OAUTH_CLIENT_ID= GOOGLE_OAUTH_CLIENT_SECRET= # Outbound DM anti-spam guard (optional tuning) # Applied at the send-tool chokepoint: a proactive Slack/Telegram/Discord DM is # suppressed (and audited) when it would exceed the per-recipient rate cap, # duplicate a recently-sent message, or land while the recipient is on leave / # outside their availability windows. Defaults shown. OUTBOUND_MAX_PER_RECIPIENT_PER_WINDOW=5 # max DMs to one recipient per rate window OUTBOUND_RATE_WINDOW_MINUTES=60 # rolling window for the rate cap OUTBOUND_DEDUP_WINDOW_MINUTES=360 # suppress a near-identical resend within this window OUTBOUND_RESPECT_QUIET_HOURS=true # honor recipient availability windows / on-leave; set false to disable # Overnight client rotation (multi-client practice mode). OFF by default: # rotating activates each parked client at the configured time (UTC) to # generate its brief + run monitors — conscious opt-in (LLM cost per client # per night + automated context switching). # CLIENT_ROTATION_ENABLED=true # CLIENT_ROTATION_TIME=03:30