Skip to content
Board Planner
GitHubOpen the app

Configuration

Everything is environment variables. Three of them decide whether the instance works at all; the rest switch features on, and without them those features are absent from the interface rather than broken. Where they go depends on how you run the app — a .env beside docker-compose.yml, -e flags, a .env in a checkout, or a host’s variables screen — and Installing and running shows each. The running app reads them — none is baked in when it is built — so a change needs a restart and never a rebuild.

Variable Required What it does
MONGODB_URI Yes Connection string.
ENCRYPTION_KEY For integrations and chat 32 bytes of hex or standard base64 — not base64url, and not a passphrase that happens to decode to 32 bytes. Generate one with openssl rand -hex 32. Integration tokens and chat webhook URLs — a project’s team channels, and each person’s own — are stored encrypted with it, so without it none of them can be saved at all. A value that is not one of those shapes stops the app from starting rather than falling back to plaintext; if secrets were already saved with it, keep the same bytes rather than generating a new key — the startup message prints the command that converts them to hex.
PUBLIC_ORIGIN For links, MCP and workers This instance’s own address, as an http(s) URL, read when the app runs. Every link the app sends — in mail, in Slack and Discord messages, in Coda rows, the page a worker’s machine opens to be approved — starts with it. /api/mcp and both /.well-known documents publish it to clients, so it is read from configuration and never from a request header — without it they, enrolling a worker and a password reset by email answer 500 rather than advertising an address a caller supplied, changing an email address answers 503, and notification mail and chat messages go out without their links. Falls back to APP_ORIGIN only when that names exactly one origin — so adding a second origin to APP_ORIGIN without setting this turns all of that off. In the compose file it defaults to NEXT_PUBLIC_APP_URL, then http://localhost:${APP_PORT:-3000} — port 3000 unless APP_PORT moves it.
APP_ORIGIN Recommended Comma-separated origins allowed to make changes. Together with PUBLIC_ORIGIN, it is the fallback check on a mutating request whose browser sends no Sec-Fetch-Site header; the app logs one warning the first time it sees such a request.
BOOTSTRAP_TOKEN No The setup code the first account is created with, at least 16 characters. Unset, the app generates one — see The first account.
ENCRYPTION_KEYS_OLD No Comma-separated retired keys, so a key rotation can still read what the old key wrote. Every value must be hex or standard base64, or the app refuses to start.
WEBHOOK_SIGNING_SECRET No Signs outgoing webhook deliveries, so a receiver can verify they came from you.
OPENAI_API_KEY No Turns on AI Assist in the task form. Without it the box is not rendered.
AI_DAILY_GENERATION_CAP No AI Assist generations one project may run in 24 hours, counted from its first. Default 200.
OPENROUTER_API_KEY No Turns on the PM agent. Without it the PM pages say so and stay inert.
PM_MODEL No Model for the PM agent. Defaults to moonshotai/kimi-k2.6.
PM_MAX_TOKENS No Output tokens per PM call. Default 8192.
PM_DAILY_TURN_CAP No PM turns per project per day. Default 100.
PM_SCHEDULER_TICK_MS No How often the autonomy scheduler wakes. Default 300000 (5 min).
PM_DAILY_TOKEN_CAP No Tokens per project per day — the ceiling, counted in the tokens the model reports rather than in money. Unset means no ceiling. Not the same knob as PM_DAILY_TURN_CAP; see PM agent.
TRUSTED_PROXY_HOPS Behind a proxy How many proxies append to X-Forwarded-For between the internet and the app. Default 0, which ignores the header entirely — and from 1.1.2 a request carrying it to a route that throttles by address (sign-in, password reset, the OAuth endpoints, machine enrolment, account changes) makes the app warn that it is being ignored. In releases after 1.1.2 that warning also names how many entries the header carried, which is the number to set here. A value that is not a whole number fails at startup naming the variable, rather than quietly reverting to 0. The value it settled on is printed at boot.
COOKIE_ALLOW_INSECURE No 1 issues the session cookie over plain HTTP. auto — new in 1.1.2, and what the compose file passes from that release — does so only while PUBLIC_ORIGIN and every APP_ORIGIN are http:// and the sign-in itself did not come over https://. Anything else, empty included, is the secure cookie. See the caution below.
DIGEST_HOUR No Hour the daily digest goes out, 0-23. Default 7. Unset or not a number falls back to 7 rather than failing; an empty value reads as 0, midnight, and anything outside 0-23 is clamped to the nearest end. The digest scheduler only starts when SMTP is configured.
DIGEST_TIMEZONE No The zone that hour is read in. Default Europe/Warsaw. An unrecognised zone falls back to the default.
DIGEST_TICK_MS No How often the digest scheduler wakes. Default 300000 (5 min). It also decides how many times a refused digest is retried: the retry spans up to an hour, so a longer interval means fewer attempts and a shorter one more — capped at 20, which at a one-minute interval is nineteen minutes of retrying rather than an hour.
OPENROUTER_BASE_URL No Where PM calls go. Defaults to https://openrouter.ai/api/v1; set it to put a proxy or a compatible endpoint in front.
GITHUB_SYNC_TICK_MS No How often every project with a GitHub token is re-synced, which is what keeps a pull request’s badge current. Default 300000 (5 min), floor 60000; a value that is not a number falls back to the default and says so in the log rather than silently never starting. 0 switches the background sync off — the buttons in project settings and on a task still work. One tick costs up to 82 GitHub requests per project (42 in the ordinary case) against a limit that is per GitHub account, not per project, so raise it or give each board its own token if one person’s token is pasted into several.
GITHUB_API_BASE_URL No Where GitHub’s API is. Defaults to https://api.github.com; set it for GitHub Enterprise or a proxy. An operator’s setting and never a project’s — a board that could name its own host would be sending that project’s token wherever it liked. It also says where GitHub is for a reader — but only when it is one of GitHub’s own API shapes, api.* with no path or .../api/v3: the web address is derived from those, so a project still on the old owner/repo field links to your GitHub rather than to github.com. A proxy in front of GitHub’s API is neither shape and changes nothing, because a proxy’s address is not a repository’s.
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM No Email notifications, and reset by email for a forgotten password. SMTP_PORT defaults to 587. Without these, notifications stay in-app and a forgotten password needs an administrator to set a new one.

OPENAI_API_KEY is also accepted under the older name OPENAPI_KEY. Prefer the current one; the alias is kept so an existing deployment does not break.

Two variables that decide how safe the instance is

Section titled “Two variables that decide how safe the instance is”

A few variables belong to one way of running the app rather than to the app itself.

Variable Where What it does
APP_PORT The compose file The host port the app is published on. Default 3000. 127.0.0.1:3000 publishes it on the loopback interface only, which is what you want behind a proxy on the same machine — then set PUBLIC_ORIGIN and APP_ORIGIN yourself, because their defaults are built from this value.
BOARD_PLANNER_VERSION The compose file Which published image to run, such as 1.1.2. Default latest.
PORT npm start, and the image The port the app listens on. From 1.1.2, npm start takes it from the environment it is started in, then from .env.production.local, .env.local, .env.production and .env, in that order, and uses 3000 when none names one. Up to 1.1.1 it read only the environment, and a PORT in .env was ignored. The compose file pins it to 3000 inside the container.