Skip to main content

Environment variables

Important: Poindexter runs virtually ALL configuration out of the app_settings Postgres table, not environment variables. Env vars and ~/.poindexter/bootstrap.toml exist only to bootstrap the stack (enough config to connect to the database and start Docker). Once the worker connects, everything — model thresholds, prompt templates, QA weights, auto-publish rules, algorithm windows, SEO pinging endpoints — is changed with SQL against app_settings (hundreds of keys — see docs/reference/app-settings.md for the full, nightly-regenerated catalog), no redeploy needed. Preferred path: run poindexter setup once on first install. It writes ~/.poindexter/bootstrap.toml with 5 bootstrap values (database URL + 4 generated passwords). Then bash scripts/start-stack.sh reads bootstrap.toml and exports them for Docker. No .env file needed. See reference/app-settings.md for the full list of DB-backed settings.
This document enumerates the environment variables consumed by the stock docker-compose.local.yml deployment. If you’re running a custom configuration, start from this list.

Required

These variables are generated by poindexter setup and stored in ~/.poindexter/bootstrap.toml. The scripts/start-stack.sh wrapper exports them automatically for Docker. Missing any causes the stack to fail fast with a clear error — no silent fallbacks. All three are generated automatically by poindexter setup on first run and written to ~/.poindexter/bootstrap.toml (safe permissions, outside the repo). No .env file is needed. Worker authentication uses OAuth 2.1 client credentials (Phase 3 finalised in Glad-Labs/poindexter#249). poindexter setup provisions an initial CLI client and stores the credentials encrypted in app_settings.cli_oauth_client_id / cli_oauth_client_secret. There is no API_TOKEN env var.

Optional (with sensible defaults)

Optional (no default — feature off unless set)

Local Ollama only in the core stack. Paid-API providers (OpenAI, Anthropic, Google) live in community plugins, never the core. If you install one of those plugins, it reads its own keys from app_settings at runtime via the settings API — not from env vars.

.env.local template

A fully-populated .env.local for a standard local install looks like this (the bootstrap script writes something equivalent):

MCP HTTP tool allowlist (POINDEXTER_MCP_HTTP_TOOL_ALLOWLIST)

The remote MCP HTTP server (mcp-server/http_server.py) exposes the same tool registry as the stdio transport — by default that’s all 25+ tools, including write-capable ones like publish_post, approve_post, reject_post, set_setting, and create_post. When you register the HTTP server as a Custom Connector for the mobile or voice Claude app, write tools become a real risk: a misheard query plus an LLM that “follows through” can publish or reject content from the road, exactly when you’re least able to course-correct quickly. Set POINDEXTER_MCP_HTTP_TOOL_ALLOWLIST to the comma-separated list below to expose only the 13 read-only tools — covers “what’s the system state?”, “what did I decide about X?”, and “what’s in the queue?” without giving voice mode the keys to the publishing button:
The same list lives as the DEFAULT_VOICE_MOBILE_ALLOWLIST constant in mcp-server/http_server.py for in-code reference. Behaviour notes:
  • Unset ⇒ all registered tools exposed (pre-#239 default).
  • Empty string ("") ⇒ explicit “expose nothing” — useful if you want the route mounted but locked down without unmounting it.
  • Whitespace-toleranta, b ,c parses as {a, b, c}.
  • Unknown names silently ignored — copying the recommended list verbatim never crashes startup, even after a tool is renamed upstream.
  • Stdio transport unaffected — running python mcp-server/server.py always exposes the full registry, since the stdio path doesn’t go through http_server.build_app.
The filter runs before MCPServer builds its streamable_http_app(), so both tools/list and tools/call reflect the trimmed registry — unlisted tools surface as Unknown tool: <name> to the client.

How the worker actually reads these

The worker resolves configuration in this order:
  1. Environment variable — for bootstrap-only values (DATABASE_URL, passwords). Read once at startup. Worker API auth uses OAuth JWTs (no env var); see poindexter auth migrate-cli.
  2. app_settings table — for runtime-mutable values (model thresholds, prompt overrides, cost guards, feature flags). Consulted on every call via site_config.get(key, default).
  3. Hardcoded fallback — the _DEFAULTS dict in services/site_config.py. Used only when the DB value is absent AND no env var provides a value.
Never edit _DEFAULTS to change runtime behavior — that requires a rebuild. Use the settings API or SQL against app_settings instead.

Where to go next