DocumentationChangelog
Getting Started

Configuration

Everything the appliance reads from its environment: the four values you fill in, the two the published files supply for you, and the optional ones that switch on voice, semantic recall, dev sessions and the budgets around model calls.

Required

Four values you fill in, and compose refuses to start without them rather than defaulting to something weak. These are the same four the Install page asks for.

POSTGRES_PASSWORD
The database password. Only the app talks to this database and its port is not published, but a weak password plus one future misconfiguration is a breach.
AUTH_SECRET
Signs sessions. Rotating it logs everyone out; nothing else breaks.
TALON_CONTROL_ENCRYPTION_KEY
Encrypts every stored credential before it reaches the database. Cannot be regenerated — escrow it before first boot.
NEXTAUTH_URL
The public origin, scheme included. Auth breaks behind a proxy when this does not match what the proxy serves.

Two more the appliance requires, which the published files already supply — so you set them only when you are assembling your own deployment:

TALON_CONTROL_POSTGRES_URL
The database the appliance owns; migrations run against it at every boot. The compose file composes this from POSTGRES_PASSWORD, so there is nothing to type.
TALON_CONTROL_IMAGE_TAG
Which build to run. The environment template ships with a known-good tag already pinned; changing it is an upgrade — see Upgrades & rollback.

Behind a proxy

TALON_TRUST_PROXY
Trust X-Forwarded-For. On behind a reverse proxy — without it there is no per-client IP to throttle on and traffic analytics can never derive a visitor hash. Off when the app is exposed directly: the header is attacker-controlled there.
TALON_LABS_URL
Your marketing site's origin: the only CORS origin the public traffic collector accepts, and where published content links back to. Blank disables the collector rather than opening it.
TALON_CONTROL_ADMIN_EMAIL
Bootstraps the first admin account from the environment instead of the /setup screen. Ignored once an account exists.
TALON_CONTROL_ADMIN_PASSWORD
The password for that bootstrapped account. Change it after first sign-in.

A note that costs people an afternoon: compose only passes a variable a service names. Putting a value in .env without adding it to the service's environment: block silently does nothing.

AI and the fleet

The fleet's model provider is normally configured in the app, under Settings → AI, so it can be changed without a redeploy. The environment exists for one specific split: running your conversations somewhere other than where the fleet runs.

TALON_CONTROL_AI_CHAT_PROVIDER
Which engine answers the assistant and the stand-up. Leave unset and everything uses the connection saved in Settings → AI.
TALON_CONTROL_AI_CHAT_MODEL
The model name. A provider switch without one is ignored rather than allowed to fail mid-conversation — a model name means nothing to a provider it was not written for.
TALON_CONTROL_AI_CHAT_API_KEY
Key for that endpoint.
TALON_CONTROL_AI_CHAT_URL
An OpenAI-compatible base URL, for a local or self-hosted model server.
CLAUDE_CODE_OAUTH_TOKEN
Subscription auth for the Claude Code dev-session engine.
CODEX_ACCESS_TOKEN
The same, for the Codex engine.
Why the split exists
The fleet can sit on a slow local model all day, because nobody is waiting on it. The assistant panel and the stand-up are you, waiting, with the mic open — and a small model answers slowly and writes spoken prose in one unpunctuated breath. Pointing chat at a faster provider while the fleet stays local is the reason these variables exist.

Semantic recall

Brain search is full-text by default, which matches words — so a question about a refund policy misses a note titled "Credit notes and returns", and that gets worse as the corpus fills. Point these at any OpenAI-compatible /v1/embeddings endpoint and retrieval matches meaning instead.

TALON_CONTROL_EMBEDDING_URL
The endpoint. Semantic recall stays off unless both this and the model are set.
TALON_CONTROL_EMBEDDING_MODEL
The embedding model. Vectors are keyed by the model that made them, so changing it simply leaves the new one with no vectors yet.
TALON_CONTROL_EMBEDDING_API_KEY
Key for that endpoint, if it wants one.
TALON_CONTROL_EMBEDDING_LOCAL
The in-process fallback, on by default. Set false on a box that cannot spare the memory.

Switching it on is retroactive: a background sweep embeds existing notes at twenty a minute, so the Brain fills in behind you rather than needing a reindex.

Voice

Spoken replies are served by the Kokoro sidecar, not by code inside the app — TALON_CONTROL_TTS_URL points at it. With the sidecar down or the variable unset, spoken replies report unavailable and the browser's built-in voice stands in: a different voice, no error. TALON_CONTROL_SPEECH_CACHE_DIR keeps the local speech models on a volume, so recreating the container does not re-download them.

Budgets and timeouts

TALON_CHAT_RATE_LIMIT_PER_MINUTE
Chat turns per account per minute. Defaults to 60 — only a runaway client reaches it.
TALON_AGENT_RUN_RATE_LIMIT_PER_MINUTE
Agent runs per account per minute. Defaults to 20.
TALON_CHAT_STEP_BUDGET
Tool round-trips one conversation turn may take. Default 12; the turn always ends with a written answer either way.
TALON_CHAT_TURN_TIMEOUT_MS
How long a turn may run before it has to start finishing. Default four minutes.
TALON_CONTROL_MODEL_TIMEOUT_MS
How long one model call may take before its socket is cut. Raised well above Node's default, which a local model legitimately exceeds — and which fails as a JSON parse error rather than as a timeout.
TALON_CONTROL_RUN_TIMEOUT_MS
Hard wall-clock stop for one agent run, set under the reaper so a slow run fails as itself rather than being reaped as a dead process.

The two rate limits are per account, not per IP, because they are the endpoints that spend money per model call. They are backstops against a loop, not a capacity plan.

Environment or the app?

The dividing line is worth stating, because it decides whether changing something needs a redeploy:

Environment — anything the process needs before it can serve a request, or anything that must not be editable from a browser: the database URL, the encryption key, the origin, the signing key path.
In the app — anything an operator changes as part of running the company: provider keys, mail accounts, agent tool grants, automations, access. These live in the database, encrypted, and change without a restart.