> ## Documentation Index
> Fetch the complete documentation index at: https://gladlabs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Environment variables

# 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`](../reference/app-settings) 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](../reference/app-settings) 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.

| Variable                  | Purpose                                   | Example            |
| ------------------------- | ----------------------------------------- | ------------------ |
| `LOCAL_POSTGRES_PASSWORD` | Password for the local Postgres superuser | random 32-char hex |
| `GRAFANA_PASSWORD`        | Grafana admin password                    | random 32-char hex |
| `PGADMIN_PASSWORD`        | pgAdmin admin password                    | random 32-char hex |

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)

| Variable               | Default                             | Purpose                                                                                                                                                                           |
| ---------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `API_BASE_URL`         | `http://localhost:8002`             | Base URL clients use to reach the worker                                                                                                                                          |
| `COMPANY_NAME`         | `Glad Labs`                         | Publisher name used in generated content's `<author>` tag                                                                                                                         |
| `DEFAULT_OLLAMA_MODEL` | `auto`                              | Ollama model the router picks when no override                                                                                                                                    |
| `DEVELOPMENT_MODE`     | `true`                              | Enables dev bypasses (token, CORS). **Never set in prod.**                                                                                                                        |
| `ENVIRONMENT`          | `production`                        | Log tag — also tagged on GlitchTip events. Sentry SDK is back via self-hosted GlitchTip; `main.py` initialises it when `app_settings.sentry_dsn` is set (provisioned 2026-05-09). |
| `GRAFANA_USER`         | `admin`                             | Grafana admin username                                                                                                                                                            |
| `LOCAL_POSTGRES_USER`  | `poindexter`                        | Local Postgres user                                                                                                                                                               |
| `LOCAL_POSTGRES_DB`    | `poindexter_brain`                  | Local Postgres database name                                                                                                                                                      |
| `OLLAMA_BASE_URL`      | `http://host.docker.internal:11434` | Where `OllamaClient` reaches Ollama (pipeline generation)                                                                                                                         |
| `OLLAMA_URL`           | `http://host.docker.internal:11434` | Where `MemoryClient` / `auto-embed.py` reaches Ollama (embeddings). Must be set to the same value as OLLAMA\_BASE\_URL.                                                           |
| `PORT`                 | `8002`                              | Worker HTTP port                                                                                                                                                                  |
| `SITE_DOMAIN`          | `gladlabs.io`                       | The operator's public site domain                                                                                                                                                 |
| `SITE_NAME`            | `Glad Labs`                         | Site name in feeds + metadata                                                                                                                                                     |
| `SITE_URL`             | `https://www.gladlabs.io`           | Canonical site URL                                                                                                                                                                |

## Optional (no default — feature off unless set)

| Variable                             | Feature gated on it                                                                                                                                                                                              |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PEXELS_API_KEY`                     | Fallback stock-photo search when image-gen is unavailable                                                                                                                                                        |
| `TELEGRAM_BOT_TOKEN`                 | Brain daemon alerts via Telegram                                                                                                                                                                                 |
| `TELEGRAM_CHAT_ID`                   | Destination chat for Telegram alerts                                                                                                                                                                             |
| `OPENCLAW_GATEWAY_URL`               | Discord + Telegram bridge via OpenClaw                                                                                                                                                                           |
| `OPENCLAW_GATEWAY_TOKEN`             | Bearer token for OpenClaw Tools Invoke API                                                                                                                                                                       |
| `POINDEXTER_MCP_HTTP_TOOL_ALLOWLIST` | Comma-separated tool names exposed by the remote MCP HTTP transport. Unset = expose all 25+ tools. Set to the recommended voice/mobile read-only list when registering a Custom Connector to a phone (see below) |

> **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):

```env theme={null}
# ---- Required ----
# Note: API_TOKEN was removed in Phase 3 (Glad-Labs/poindexter#249).
# Worker auth is OAuth 2.1 only — `poindexter setup` provisions the
# initial CLI OAuth client automatically.
LOCAL_POSTGRES_PASSWORD=REDACTED
GRAFANA_PASSWORD=REDACTED
PGADMIN_PASSWORD=REDACTED

# ---- Optional overrides ----
COMPANY_NAME=Your Brand Here
SITE_NAME=Your Brand Here
SITE_DOMAIN=yourbrand.com
SITE_URL=https://www.yourbrand.com

# ---- Feature flags ----
DEVELOPMENT_MODE=true
ENVIRONMENT=production
PORT=8002

# ---- Optional integrations (leave empty if you don't use them) ----
PEXELS_API_KEY=
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
```

## 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:

```bash theme={null}
export POINDEXTER_MCP_HTTP_TOOL_ALLOWLIST="search_memory,recall_decision,find_similar_posts,list_tasks,get_post_count,get_setting,list_settings,get_audit_log,get_audit_summary,get_brain_knowledge,check_health,get_budget,memory_stats"
```

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-tolerant** — `a, 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** FastMCP 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

* **Full settings catalog:** [reference/app-settings.md](../reference/app-settings)
* **Local dev setup:** [local-development-setup.md](local-development-setup)
* **Troubleshooting:** [troubleshooting.md](troubleshooting)
