Skip to content

Runtime Settings

diegokoes edited this page Jul 5, 2026 · 1 revision

Runtime Settings

Two kinds of configuration exist, and the split is deliberate:

  • Secrets (DB URL, tokens, API keys, session secret) come from the environment only, never the database.
  • Non-secret runtime settings (redaction switch, agent cost policy, org name) live in the database (settings table), managed by the setup wizard or Admin › System. The matching env vars act as fallback defaults until a DB value is set, so a pre-wizard deployment behaves exactly as before.

Implementation: packages/core/src/platform/settings.ts.

The settings

Key Type Env fallback Default Used by
redaction_global boolean TACHY_REDACT=true false redaction
agent_model string TACHY_AGENT_MODEL claude-sonnet-5 agent
agent_effort low..max TACHY_AGENT_EFFORT medium agent
allowed_models string[] TACHY_ALLOWED_MODELS (comma-sep) [] (no restriction) agent
org_name string (none) null web UI

Each value is validated with a zod schema on write, so a bad value is rejected with a clear message rather than stored.

Precedence

effectiveSettings() resolves each key as DB setting > env var > built-in default and reports the winning source for each, so Admin › System can show exactly where a value came from (db, env, or default). GET /api/system returns that, plus read-only facts about which secrets are set (never their values).

Caching and materialization

The settings map is cached in-process and invalidated on write. Two consumers read settings synchronously and need them in process.env:

  • The redaction check (globalRedactionEnabled()) reads TACHY_REDACT synchronously, including inside the standalone MCP process.
  • loadSettingsIntoEnv() materializes the DB-backed redaction_global into TACHY_REDACT once at boot. The MCP server and the CLI sync command both call it before doing work.

The agent route reads effectiveSettings() per turn and snapshots the cost policy plus redaction switch into the MCP subprocess env at spawn, so a settings change takes effect on the next turn without a restart.

Clone this wiki locally