Environment variables¶
Every setting trimus-server, trimus-worker, and trimus-cli read
from the environment — with defaults, meanings, and the component that
reads each one. This is the operator's #1 reference; treat it as
authoritative.
Where each var is read
Most server config is parsed once by internal/config/config.go
at startup (the ~45 vars in the Server config tables below).
A second set of vars is read directly by the workers, adapters,
crypto vault, health probes, and the CLI — those are noted with
their reading component. A handful (embeddings,
context-compression enabled + threshold, GEPA evaluator) are also
editable at runtime from /admin/operations without a restart.
Master table¶
Every environment variable Trimus reads, alphabetically. Detail sections follow.
Core server (internal/config/config.go)¶
| Variable | Default | Read by | Meaning |
|---|---|---|---|
DATABASE_URL |
required | server, worker‑none, CLI | Postgres connection string. Server refuses to start if unset. |
TRIMUS_HOST |
"" (all interfaces) |
server | Bind address. |
PORT |
3100 |
server | HTTP listen port. |
LOG_LEVEL |
info |
server, worker | debug / info / warn / error. |
WORKER_POOL_SIZE |
5 |
server | In‑process heartbeat worker goroutines. |
RATE_LIMIT_RPM |
300 |
server | Requests/min per limiter key. |
TRIMUS_MAX_REMOTE_WORKERS |
10000 |
server | Cap on total remote_workers rows; a fresh registration past it → 503. 0 disables the cap. Idempotent re-registration is exempt (#153). |
TRIMUS_REQUIRE_WORKER_APPROVAL |
false |
server | When true, a worker registered via the public POST /api/workers/register endpoint sits pending with an inert key and no operating prompt until an instance-admin approves it on /admin/workers; its register/heartbeat return 403 until then. Workers created from the /admin/workers Register worker form are approved immediately — the admin's action is the admission decision (#335). false keeps today's auto-onboard. Existing workers backfill to approved (#210 / #148). |
TRIMUS_MAX_SSE_CONNS_PER_USER |
20 |
server | Cap on concurrent live-event (SSE) subscriptions per actor (API-key id, else user id); over it → 429. Instance admins exempt. 0 disables (#183). |
TRIMUS_METRICS_TOKEN |
"" (unauthenticated) |
server | When set, /metrics requires Authorization: Bearer <token>. Unset keeps the usual unauthenticated Prometheus-scrape behaviour (#147). |
TRIMUS_TRUSTED_PROXIES |
"" (none trusted) |
server | CIDR allowlist; X-Forwarded-For is honoured only from these. Invalid CIDR = boot error (SEC‑014). |
SECRET_KEY |
"" |
server | App secret used on the login submit path. |
TRIMUS_PUBLIC_URL |
http://localhost:<PORT> |
server | URL agents/integrations use to reach the API. Trailing slash trimmed. |
TRIMUS_STORAGE_DIR |
./storage |
server | Disk root for attachments + assets + logos. |
TRIMUS_HOME |
$HOME/.trimus |
server, worker | Disk root for company/agent/project working dirs. |
TRIMUS_ADMIN_EMAIL |
"" |
server | Seed admin email (first boot only). Also folded into the instance-admin allowlist below. |
TRIMUS_ADMIN_PASSWORD |
"" |
server | Seed admin password (first boot only). |
TRIMUS_INSTANCE_ADMINS |
"" |
server | Comma-separated emails who are instance admins (see all companies). Env-authoritative (#142): the DB users.instance_role column does not grant instance-admin. TRIMUS_ADMIN_EMAIL is included automatically. Changing this requires a restart. |
TRIMUS_SESSION_SECRET |
— | — | Removed (#155): no-op. Sessions are opaque random tokens persisted in user_sessions and validated against the DB, so they survive restarts regardless of any secret. Setting this now does nothing; the old "sessions die on restart" warning was incorrect and is gone. |
TRIMUS_ENCRYPTION_KEY |
nil (warns SEC‑010) |
server, CLI | base64 32‑byte AES‑256 KEK. Unset ⇒ encrypted writes refused. |
TRIMUS_SECURE_COOKIES |
false |
server | Secure flag on session/auth cookies. Set true behind HTTPS. When secure, the session cookie also uses the hardened __Host- prefix (#154); reads tolerate the legacy name so no forced re-login. |
TRIMUS_CSRF_TRUSTED_ORIGINS |
"" |
server | Comma‑sep cross‑origin POST allowlist. |
TRIMUS_MAX_UPLOAD_SIZE |
25000000 (25 MB) |
server | Global multipart upload cap, bytes. |
TRIMUS_RUN_EVENTS_RETENTION_DAYS |
30 |
server | Retain run‑event rows for succeeded runs (failed kept indefinitely). |
TRIMUS_ANTHROPIC_API_VERSION |
2023-06-01 |
server | anthropic-version request header. |
TRIMUS_MODE |
local |
server | Deployment posture. local = permissive defaults (current behavior). hosted = enforce production invariants at startup (see Deployment mode & TLS). Unknown value = boot error. |
TRIMUS_LICENSE |
"" |
server | Inline Ed25519-signed license token (#136). Empty ⇒ a built-in 30-day trial, then read-only. Verified offline at boot; a bad/expired/missing license degrades the instance to read-only (data still viewable) but never blocks boot. See Licensing. |
TRIMUS_LICENSE_FILE |
"" |
server | Path to a file containing the license token, used when TRIMUS_LICENSE is unset. A configured-but-unreadable path is a boot error. |
TRIMUS_ROLE |
all |
server | Process role (#134). all = one process serves HTTP and runs every background singleton — identical to the binary/single-process deploy (the default). web = HTTP/API/UI only, no singletons (scale N replicas). scheduler = the singletons only (heartbeat dispatch, backup crons, GEPA, retention, …), no HTTP — run exactly one replica (no leader election yet). Unknown value = boot error. See Kubernetes. |
TRIMUS_TLS_CERT |
"" |
server | PEM cert path for built-in TLS. Must be set together with TRIMUS_TLS_KEY (one without the other = boot error). Unset ⇒ plain HTTP (terminate TLS at a proxy). |
TRIMUS_TLS_KEY |
"" |
server | PEM private-key path for built-in TLS. |
TRIMUS_SELFTEST_PUBLIC_URL |
false |
server | When true, background‑probe <TRIMUS_PUBLIC_URL>/healthz after startup and WARN if unreachable. Non‑blocking, opt‑in. |
Default LLM fallback (config.go)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_DEFAULT_LLM_PROVIDER |
openai |
Fallback provider for agents with no adapter_config/provider binding. |
TRIMUS_DEFAULT_LLM_MODEL |
gpt-4o |
Fallback model id. |
TRIMUS_DEFAULT_LLM_API_KEY |
"" |
Fallback LLM API key. |
TRIMUS_DEFAULT_LLM_BASE_URL |
https://api.openai.com/v1 |
Fallback upstream base URL. |
OAuth (config.go)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_OAUTH_GOOGLE_CLIENT_ID |
"" |
Google OAuth client id. |
TRIMUS_OAUTH_GOOGLE_CLIENT_SECRET |
"" |
Google OAuth client secret. |
TRIMUS_OAUTH_GITHUB_CLIENT_ID |
"" |
GitHub OAuth client id. |
TRIMUS_OAUTH_GITHUB_CLIENT_SECRET |
"" |
GitHub OAuth client secret. |
TRIMUS_OAUTH_REDIRECT_BASE_URL |
"" (→ TRIMUS_PUBLIC_URL) |
OAuth redirect base (also the OIDC redirect base). |
TRIMUS_OIDC_ISSUER |
"" |
Generic OIDC issuer URL (e.g. https://login.example.com). Discovery hits <issuer>/.well-known/openid-configuration at startup. When set with the client id+secret, a "Sign in with …" SSO button appears on the login page. |
TRIMUS_OIDC_CLIENT_ID |
"" |
OIDC client id. |
TRIMUS_OIDC_CLIENT_SECRET |
"" |
OIDC client secret. Encryption key required (OIDC tokens are stored encrypted, like other OAuth tokens). |
TRIMUS_OIDC_DISPLAY_NAME |
"SSO" |
Label for the OIDC login button (e.g. Okta, Company SSO). |
Channels (config.go) — see slack.md¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_TELEGRAM_BOT_TOKEN |
"" |
Enables Telegram (with company id). |
TRIMUS_TELEGRAM_COMPANY_ID |
"" |
Company Telegram binds to. |
TRIMUS_TELEGRAM_DEFAULT_AGENT_ID |
"" |
Default agent for Telegram DMs. |
TRIMUS_SLACK_BOT_TOKEN |
"" |
Slack bot user token (xoxb-). |
TRIMUS_SLACK_APP_TOKEN |
"" |
Slack app‑level token (xapp-, Socket Mode). |
TRIMUS_SLACK_COMPANY_ID |
"" |
Company Slack binds to. |
TRIMUS_SLACK_DEFAULT_AGENT_ID |
"" |
Default agent for Slack DMs. |
TRIMUS_SLACK_USER_ALLOWLIST |
"" |
Required when Slack is otherwise configured. CSV user IDs or *. Unset ⇒ boot error. |
TRIMUS_SLACK_ENFORCE_ALLOWLIST_ON_MENTIONS |
false |
true also enforces TRIMUS_SLACK_USER_ALLOWLIST on channel @-mentions (default: mentions are gated only by the bot's channel membership). |
Concierge chat context (config.go)¶
| Variable | Default | Meaning |
|---|---|---|
CONCIERGE_CONTEXT_NOTES_LIMIT |
15 |
Recent user notes per chat digest (storage clamps >200). |
CONCIERGE_CONTEXT_ISSUES_LIMIT |
15 |
Issues per chat digest. |
Attachments (config.go) — see attachments.md¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_ATTACHMENT_MAX_UPLOAD_BYTES |
50000000 (50 MB) |
Per‑attachment cap (413 over). |
TRIMUS_ATTACHMENT_MAX_FILES_PER_REQUEST |
20 |
Files per multipart create‑issue. |
TRIMUS_ATTACHMENT_EXTRACT_TIMEOUT_SEC |
5 |
Per‑attachment text‑extraction timeout. |
TRIMUS_ATTACHMENT_EXTRACTED_TEXT_MAX_BYTES |
200000 |
extracted_text column cap per row. |
TRIMUS_ATTACHMENT_CONTEXT_CHAR_LIMIT |
50000 |
Char cap on the rendered ## Attachments block. |
Self‑evolution (config.go)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_EVOLUTION_SETTLER_CHAT_QUIET_SEC |
900 |
Quiet window before scoring a chat trace. |
TRIMUS_EVOLUTION_SETTLER_HEARTBEAT_QUIET_SEC |
3600 |
Quiet window before scoring a heartbeat trace. |
TRIMUS_EVOLUTION_TRACE_RETENTION_DAYS |
90 |
Evolution‑trace retention. |
Observability & tracing (read directly)¶
| Variable | Default | Read by | Meaning |
|---|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
"" |
server (main.go) |
Enables OTLP/HTTP trace export. Standard OTel vars (OTEL_SERVICE_NAME, …) honoured. |
Stale‑run watcher (read in main.go)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_STALE_RUN_THRESHOLD_SEC |
600 |
Seconds with no activity → mark stale. |
TRIMUS_STALE_RUN_GRACE_SEC |
300 |
Additional seconds → grace prompt. |
TRIMUS_STALE_RUN_CANCEL_SEC |
300 |
Additional seconds → auto‑cancel. |
Model lifecycle (read in main.go) — see #99¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_MODEL_LIFECYCLE_ENABLED |
false |
Set true to start the model‑lifecycle worker. It periodically queries each provider's live model catalog and flags agents whose configured model has been retired (after two consecutive misses, so a transient provider‑API blip never false‑positives). Affected agents surface on each company's Model Lifecycle page (/companies/{id}/models) with a one‑click bulk migration. Off by default because it makes scheduled outbound provider‑API calls. |
TRIMUS_MODEL_CHECK_INTERVAL_SEC |
21600 (6h) |
Interval between model‑catalog checks when the worker is enabled. |
Egress / DNS (read in main.go) — see adapter-isolation.md¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_EGRESS_DNS_ADDR |
"" (off) |
When set (e.g. :5353), starts the deny‑by‑default egress DNS resolver. Also propagated to remote workers (#79): if it resolves to an ip:53 address, the docker exec path passes --dns <ip>. |
TRIMUS_WORKER_EGRESS_PROXY |
"" (off) |
HTTPS/HTTP proxy URL propagated to remote workers (#79). Remote agents run with HTTPS_PROXY/HTTP_PROXY set to this (and NO_PROXY exempting loopback) so their outbound traffic routes through your egress proxy, which enforces the per‑company allowlist and logs connections. Best‑effort routing for cooperative agents — not a hard sandbox (a --dangerously-skip-permissions agent can unset it; for hard containment run workers in a network‑restricted environment). |
TRIMUS_EGRESS_DNS_DEFAULT |
bridge gateway | Override the DNS server address published into sandbox containers. |
Outbound HTTP proxy (read in internal/httpclient)¶
Corporate environments (financial services, healthcare, government) commonly
require all outbound traffic to traverse a proxy. Every outbound *http.Client
in Trimus is now constructed through internal/httpclient, which honours the
standard proxy env vars and the Trimus‑specific overrides below. The
SSRF‑guarded clients (plugin http_fetch, A2A, webhooks) trust the configured
proxy host even when it lives on a private IP, while still blocking direct
dials to private/reserved IPs.
| Variable | Default | Read by | Meaning |
|---|---|---|---|
HTTP_PROXY / HTTPS_PROXY / NO_PROXY |
"" |
server, worker, CLI | Standard Go proxy env. Honoured by all outbound clients. Lowercase variants also read. |
TRIMUS_HTTP_PROXY |
"" (→ HTTP_PROXY) |
server, worker, CLI | Trimus‑specific HTTP proxy override. Wins over HTTP_PROXY so Trimus can use a different proxy than the host OS. |
TRIMUS_HTTPS_PROXY |
"" (→ HTTPS_PROXY) |
server, worker, CLI | Trimus‑specific HTTPS proxy override. |
TRIMUS_NO_PROXY |
"" (→ NO_PROXY) |
server, worker, CLI | Trimus‑specific bypass list. Include the Trimus server host here when workers are co‑located so worker→server traffic stays direct. |
TRIMUS_PROXY_AUTH_USER |
"" |
server, worker, CLI | Username injected into the effective proxy URL when it carries no credentials. |
TRIMUS_PROXY_AUTH_PASS |
"" |
server, worker, CLI | Password paired with TRIMUS_PROXY_AUTH_USER. |
Notes:
- A bare
&http.Client{}already honoursHTTP_PROXYvia Go'sDefaultTransport; theTRIMUS_*overrides only take effect because clients route throughinternal/httpclient. - The worker passes its environment (including proxy vars) to the Claude CLI
subprocess via
cmd.Env = os.Environ(), so the agent's own outbound calls inherit the proxy. - AWS Bedrock uses the AWS SDK, which reads
HTTPS_PROXYitself — leave it to the SDK rather than double‑configuring. - Per‑provider proxy routing (a
proxy_urlcolumn oncompany_providers) is a future enhancement and intentionally out of scope here.
Sandbox / adapter hardening (read in adapters)¶
| Variable | Default | Read by | Meaning |
|---|---|---|---|
TRIMUS_PLUGIN_SANDBOX |
"" (sandbox on) |
internal/plugins/sandbox.go |
disabled bypasses the plugin Docker sandbox (dev only). |
TRIMUS_PLUGIN_SANDBOX_SECURITY_OPTS |
"" |
plugins | Comma‑sep extra --security-opt flags for plugin containers. |
TRIMUS_PLUGIN_PIDS_LIMIT |
100 |
plugins | --pids-limit for plugin containers. |
TRIMUS_DOCKER_PIDS_LIMIT |
100 |
adapters/docker.go |
--pids-limit default for the docker adapter (per‑agent config wins). |
TRIMUS_DOCKER_SECURITY_OPTS |
"" |
adapters/docker.go |
Comma‑sep extra --security-opt for docker/sandbox adapters (seccomp/AppArmor). |
TRIMUS_SANDBOX_PIDS_LIMIT |
100 |
adapters/sandbox_wrap.go |
--pids-limit for claude_sandbox/codex_sandbox. |
TRIMUS_MOUNT_ALLOWLIST_ROOT |
"" (blocklist only) |
adapters/sandbox_wrap.go |
Comma‑sep host path prefixes; when set, an agent sandbox bind mount (adapter_config.extra_mounts) must sit under one of them. A blocklist of host‑sensitive paths (Docker/containerd sockets, /, /etc, /root, /proc, /sys, /dev, …) is always enforced regardless of this var (#158). |
TRIMUS_FORBID_DANGEROUS_CLAUDE_PERMISSIONS |
"" (allowed) |
adapters/safety.go |
Truthy ⇒ drop the Claude CLI --dangerously-skip-permissions flag (SEC‑015). |
TRIMUS_CLAUDE_BINARY_ALLOWLIST |
"" (any) |
adapters/safety.go |
Comma‑sep basenames/abs‑paths the claude binary must match. |
TRIMUS_PLUGIN_BINARY_ALLOWLIST |
"" (any) |
internal/plugins/sandbox.go |
Comma-separated basenames/abs-paths the plugin host binary must match before it runs (empty = allow all). Mirrors TRIMUS_CLAUDE_BINARY_ALLOWLIST for plugins (#184). |
TRIMUS_CLAUDE_EXTRA_PATH |
"" |
adapters/claude_local.go (BuildClaudeEnv) + cmd/worker |
Colon‑sep directories prepended to the PATH of the spawned claude CLI (and the Bash tool it runs skills with). Use this when the server/worker runs under a minimal‑environment supervisor (#117/#119): launchd/systemd give the service a bare PATH (/usr/bin:/bin:/usr/sbin:/sbin), so skill‑invoked tools in ~/.local/bin, ~/.cargo/bin, /opt/homebrew/bin, etc. (and an apiKeyHelper like forge) aren't found. Leading ~/ and $HOME expand against the service's HOME; dirs already on PATH are skipped. Example: TRIMUS_CLAUDE_EXTRA_PATH=~/.local/bin:/opt/homebrew/bin:~/.cargo/bin. |
TRIMUS_HOMES_ROOT |
"" (any abs path) |
internal/home |
Comma‑sep allowed ancestors for a company home_dir. |
Subagents (read in engine/handler)¶
| Variable | Default | Read by | Meaning |
|---|---|---|---|
TRIMUS_MAX_SUBAGENT_RUNS_PER_MINUTE |
50 |
engine/subagent_limits.go |
Cross‑tenant trailing‑60s subagent run budget. Env-only (not overridable from /admin/operations; takes effect on restart). |
TRIMUS_AWAIT_SUBAGENTS_TIMEOUT |
60 |
handler/chat_actions.go |
Seconds /await-subagents blocks before timing out. Env-only (not overridable from /admin/operations; takes effect on restart). |
TRIMUS_MAX_SUBAGENT_DEPTH |
3 |
db/query/agents.go |
Max depth of the subagent spawn chain (spawn refused past it). Env-only. |
TRIMUS_MAX_SUBAGENTS_PER_PARENT |
5 |
db/query/agents.go |
Max direct children per parent agent. Env-only. |
TRIMUS_SUBAGENT_COST_WARN_USD |
1.0 |
handler/ui_subagents.go |
Per‑run cost yellow‑band on the /admin/subagents dashboard. |
TRIMUS_SUBAGENT_COST_CRITICAL_USD |
5.0 |
handler/ui_subagents.go |
Per‑run cost red‑band on /admin/subagents. |
Pricing & cost (read in engine/workers)¶
| Variable | Default | Read by | Meaning |
|---|---|---|---|
TRIMUS_PRICING_FILE |
"" (embedded table) |
engine/pricing.go |
Path to a JSON model‑pricing override file. |
TRIMUS_COST_BUDGET_ALERTER |
"" (on) |
worker | disable turns off the monthly‑budget DM alerter. |
TRIMUS_COST_BUDGET_ALERTER_INTERVAL_HOURS |
1 |
worker | Alerter tick cadence (1–24). |
TRIMUS_OPS_SPEND_WARN_USD |
10.0 |
handler/ui_operations_spend.go |
24 h spend tile yellow‑band threshold on /admin/operations. |
TRIMUS_OPS_SPEND_CRITICAL_USD |
100.0 |
handler/ui_operations_spend.go |
24 h spend tile red‑band threshold. |
Feature toggles (read in workers/engine)¶
| Variable | Default | Read by | Meaning |
|---|---|---|---|
TRIMUS_EMBEDDING_ENABLED |
false |
worker, engine | true enables note + company-knowledge embedding and semantic retrieval. Runtime‑editable. |
TRIMUS_KNOWLEDGE_GIT_SYNC_ENABLED |
false |
worker | true enables the scheduled git-sync worker that imports company-knowledge docs from each company's configured repository. Manual "Sync now" works regardless. Runtime‑editable. |
TRIMUS_SLACK_INGEST_ENABLED |
false |
worker | true enables the Slack knowledge-sync worker that ingests admin-selected Slack channels into each company's Knowledge Base (~90-day re-scan) (#266). Runtime-editable. See slack.md. |
TRIMUS_COMPILED_KNOWLEDGE_ENABLED |
false |
worker, engine | true enables Compiled Knowledge (#220): the compile worker distils each company/project/agent's knowledge into typed, cross-linked wiki articles, and the engine injects a compact index of them into every heartbeat prompt. Needs a company LLM provider. Runtime‑editable. See concepts/compiled-knowledge.md. |
TRIMUS_CONTEXT_COMPRESSION_ENABLED |
false |
worker | true enables the context‑compression worker. |
TRIMUS_CONTEXT_COMPRESSION_THRESHOLD_TOKENS |
50000 |
worker | Token budget above which an agent is a compression candidate. Runtime‑editable. |
TRIMUS_GEPA_EVAL_ENABLED |
false |
worker | true enables the GEPA prompt‑evolution evaluator. |
TRIMUS_GEPA_EVAL_LLM_ENABLED |
false |
worker | true lets GEPA call an LLM to draft prompt revisions (else heuristic). |
TRIMUS_EVOLUTION_ENABLED |
false |
worker | true enables the self-evolution optimizer worker (drafts prompt revisions from scored traces; winning candidates land in each agent's proposals queue for approval). Runtime-editable. |
TRIMUS_LOCAL_ADAPTERS |
"" |
server (main.go) |
Reserved — logged only; enforcement deferred. See local-adapter-deprecation.md. |
Heartbeat‑run retention (read in worker)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_HEARTBEAT_RUN_RETENTION |
"" (on) |
disable skips the terminal‑run retention worker. |
TRIMUS_HEARTBEAT_RUN_RETENTION_DAYS |
90 |
Retain terminal heartbeat_runs rows this long (clamped 1–3650). |
TRIMUS_HEARTBEAT_RUN_RETENTION_INTERVAL_HOURS |
24 |
Sweep cadence (clamped 1–168). |
Readiness probe thresholds (read in handler/health.go) — see monitoring.md¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_READYZ_WORKER_ERROR_RATE_PCT |
50.0 |
Worker error‑rate above which /readyz flips not‑ready. |
TRIMUS_READYZ_POOL_UTILIZATION_PCT |
90.0 |
DB pool utilisation escalation threshold. |
TRIMUS_READYZ_CHANNEL_STALENESS_SEC |
60 |
Channel staleness before channel:<name> is not‑ready. |
TRIMUS_READYZ_DISK_PCT |
90.0 |
Root‑fs usage escalation threshold. |
TRIMUS_READYZ_CHECK_P99_MS |
1000 |
Per‑check p99 latency escalation (clamped 1–60000). |
TRIMUS_READYZ_BACKUP_MAX_AGE_HOURS |
36 |
Backup‑freshness staleness threshold on /readyz. |
Backups (read in CLI + workers) — see backup-and-restore.md¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_BACKUP_DIR |
/var/backups/trimus |
Local backup directory. |
TRIMUS_BACKUP_RETENTION_DAYS |
30 |
Local prune horizon; 0 disables pruning. |
TRIMUS_BACKUP_CRON |
"" (on) |
disable turns off the daily backup cron. |
TRIMUS_BACKUP_CRON_INTERVAL_HOURS |
24 |
Backup cron cadence. |
TRIMUS_BACKUP_VERIFY_INTERVAL_HOURS |
24 |
Verify‑cron cadence. |
TRIMUS_BACKUP_RECONCILE |
"" (on) |
disable turns off on‑disk↔audit reconciliation. |
TRIMUS_BACKUP_RECONCILE_INTERVAL_HOURS |
6 |
Reconcile cadence. |
TRIMUS_BACKUP_HEALTH_CHECK |
"" (on) |
disable turns off the composite backup‑health worker. |
TRIMUS_BACKUP_HEALTH_INTERVAL_HOURS |
1 |
Health‑check cadence. |
TRIMUS_BACKUP_NO_VERIFY |
"" |
Truthy skips the inline verify after a CLI backup. |
TRIMUS_BACKUP_S3_BUCKET |
"" (S3 off) |
Enables S3 upload when set. |
TRIMUS_BACKUP_S3_PREFIX |
trimus-backups/ |
S3 key prefix. |
TRIMUS_BACKUP_S3_REGION |
us-east-1 |
S3 region. |
TRIMUS_BACKUP_S3_ENDPOINT |
"" |
Custom S3 endpoint (MinIO, R2, …). |
TRIMUS_BACKUP_S3_PATH_STYLE |
"" |
true forces path‑style addressing. |
Login lockout (read in db/query/login_attempts.go)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_LOGIN_LOCKOUT_THRESHOLD |
(see security.md) | Consecutive failures before lockout. |
TRIMUS_LOGIN_LOCKOUT_WINDOW |
15m |
Sliding failure window. |
TRIMUS_LOGIN_LOCKOUT_DURATION |
30m |
Lockout duration once tripped. |
Remote worker (cmd/worker) — see remote-workers.md¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_SERVER_URL |
required | URL of the trimus-server the worker claims tasks from. |
TRIMUS_WORKER_KEY |
required | Worker bearer key from /api/workers/register. |
TRIMUS_WORKER_NAME |
hostname | Worker display name. |
TRIMUS_WORKER_TAGS |
"" |
CSV capability tags sent at first registration. Server-authoritative thereafter — retag on /admin/workers; changing this var later has no effect (#336). |
TRIMUS_WORKER_CONCURRENCY |
2 |
Parallel task slots. |
TRIMUS_WORKER_POLL_SEC |
5 |
Claim‑loop poll interval. |
TRIMUS_WORKER_LLM_ALLOWED_HOSTS |
"" |
CSV of extra hostnames the worker may send its own environment LLM API key to when dialing that base_url (api.openai.com and api.anthropic.com are always allowed; #170). |
CLI & chat REPL (cmd/trimus-cli)¶
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_QUIET |
"" |
1 suppresses non‑essential CLI output. |
TRIMUS_API_KEY |
"" |
Bearer key for trimus-cli chat. |
TRIMUS_BASE_URL |
"" |
API base for trimus-cli chat. |
TRIMUS_CHAT_HISTORY / TRIMUS_NO_HISTORY |
— | REPL history file / disable. |
NO_COLOR / TRIMUS_CHAT_NO_COLOR |
— | Disable ANSI colour in the REPL. |
Provider CLI credentials inside local adapters
The claude_local / codex_local adapters inherit the host
environment, so the upstream CLIs may also consult their own vars
(ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, OPENAI_API_KEY,
OPENAI_BASE_URL, CODEX_HOME, AWS_REGION/AWS_DEFAULT_REGION).
These are the CLIs' own contracts, not Trimus config — set them on
the service only when you mean to.
The vars you must get right¶
DATABASE_URL (required)¶
Postgres connection string. Server refuses to start if unset.
Use sslmode=require (or verify-full with a CA bundle) in
production. Postgres 16+ with the pgvector extension is expected
(semantic note search uses it). See database.md.
TRIMUS_ENCRYPTION_KEY (load‑bearing)¶
Base64‑encoded 32‑byte AES‑256 Key Encryption Key (KEK). Generate:
Unset ⇒ encrypted writes are REFUSED (not plaintext)
Without this key the KEK/DEK vault is not initialised. The server still boots and read‑only paths work, but every encrypted‑write endpoint returns 503 — company secrets, provider API keys, OAuth tokens, and signed‑trigger secrets cannot be created or rotated (finding SEC‑010). The warning is surfaced on stderr, a structured WARN log, and a UI banner on the secrets form. There is no "store in plaintext" mode.
Validated at startup: must be valid base64 decoding to exactly 32 bytes, or the server exits with a clear error. See secrets-and-encryption.md and key-rotation.md.
TRIMUS_SESSION_SECRET¶
Signs user session cookies. Unset ⇒ a random key is generated at startup and every restart invalidates all sessions (logged WARN). Set it long, random, and durable:
TRIMUS_PUBLIC_URL¶
The URL agents and integrations use to reach the API (skill callbacks,
OAuth redirects, webhook payload links). Default
http://localhost:<PORT>; trailing slash is trimmed. Set this whenever
Trimus sits behind a reverse proxy or has a public hostname.
TRIMUS_TRUSTED_PROXIES (SEC‑014)¶
CIDR allowlist. X-Forwarded-For is honoured only when the direct
caller IP falls inside one of these ranges — otherwise the spoofable
header is ignored and the rate limiter keys on the socket peer. Empty
(the default) is the secure posture for a fresh install not yet behind
a proxy. An invalid CIDR is a boot error (fail loud, never silently
re‑open the bypass).
Server / runtime¶
PORT (default 3100), TRIMUS_HOST (default all interfaces),
LOG_LEVEL (info).
WORKER_POOL_SIZE (default 5) — concurrent heartbeat‑running
goroutines inside trimus-server. Raise if agents queue; lower under
memory pressure.
RATE_LIMIT_RPM (default 300) — per‑limiter requests/minute,
applied to public, SSE, and API groups. See security.md.
TRIMUS_MAX_UPLOAD_SIZE (default 25_000_000, 25 MB) — global
multipart cap. The 1 MB JSON body cap on most API/UI routes and the
per‑attachment cap (TRIMUS_ATTACHMENT_MAX_UPLOAD_BYTES) are separate.
TRIMUS_RUN_EVENTS_RETENTION_DAYS (default 30) — retain
streaming‑event rows for succeeded runs. Failed‑run events are kept
indefinitely. Invalid values revert to default with a WARN.
Storage¶
TRIMUS_HOME (default $HOME/.trimus) — company/agent/project
working dirs. Move to /var/lib/trimus on multi‑user hosts.
TRIMUS_STORAGE_DIR (default ./storage) — uploaded attachments,
assets, and per‑company logos; use an absolute path in production. See
storage.md.
Default LLM fallback¶
Used only by agents with no provider binding and no adapter_config
provider — mostly the seed/test path. In production, configure
providers explicitly (see providers.md).
TRIMUS_DEFAULT_LLM_PROVIDER (openai), TRIMUS_DEFAULT_LLM_MODEL
(gpt-4o), TRIMUS_DEFAULT_LLM_API_KEY (none),
TRIMUS_DEFAULT_LLM_BASE_URL (https://api.openai.com/v1).
TRIMUS_ANTHROPIC_API_VERSION (2023-06-01) sets the
anthropic-version header on every Anthropic call.
Auth / security¶
TRIMUS_ADMIN_EMAIL / TRIMUS_ADMIN_PASSWORD seed a single admin at
first boot only (ignored once any user exists). TRIMUS_SECURE_COOKIES
→ true behind HTTPS. TRIMUS_CSRF_TRUSTED_ORIGINS is the cross‑origin
POST allowlist. SECRET_KEY is the login‑submit secret. OAuth: setting
both client‑id and client‑secret for a provider enables its login
button; redirect base defaults to TRIMUS_PUBLIC_URL. Full setup in
security.md.
Login lockout (SEC‑013)¶
Per‑(email, IP) sliding‑window lockout, read directly by
db/query/login_attempts.go: TRIMUS_LOGIN_LOCKOUT_THRESHOLD
(consecutive failures), TRIMUS_LOGIN_LOCKOUT_WINDOW (default 15 min),
TRIMUS_LOGIN_LOCKOUT_DURATION (default 30 min). Recover a locked
account with trimus-cli unlock-user <email>. Client IP is keyed via
the TRIMUS_TRUSTED_PROXIES logic above.
Channel adapters¶
Off by default; each starts at boot once its var set is configured.
Telegram — TRIMUS_TELEGRAM_BOT_TOKEN + TRIMUS_TELEGRAM_COMPANY_ID
(optionally …_DEFAULT_AGENT_ID). No allowlist — anyone who finds the
bot can DM it. One bot → one company → one default agent.
Slack — see slack.md. Requires TRIMUS_SLACK_BOT_TOKEN
+ TRIMUS_SLACK_APP_TOKEN + TRIMUS_SLACK_COMPANY_ID and
TRIMUS_SLACK_USER_ALLOWLIST.
Slack will not start without an allowlist
TRIMUS_SLACK_USER_ALLOWLIST (CSV of U… user IDs, or * for the
whole workspace) is required when Slack is otherwise
configured. The dispatcher refuses to construct without it, so you
cannot accidentally deploy a no‑policy bot into a workspace
containing contractors.
Concierge chat context¶
CONCIERGE_CONTEXT_NOTES_LIMIT / CONCIERGE_CONTEXT_ISSUES_LIMIT (both
default 15) size the per‑message digest the Concierge prepends to each
chat turn. Larger = more context, more tokens. Values ≤ 0 revert to
default; the notes query hard‑caps at 200 internally.
Subagent guardrails¶
TRIMUS_MAX_SUBAGENT_RUNS_PER_MINUTE (default 50) — cross‑tenant
trailing‑60‑second budget for subagent heartbeat runs; a typo (≤ 0 /
non‑numeric) reverts to default rather than disabling the guard.
TRIMUS_AWAIT_SUBAGENTS_TIMEOUT (default 60 s) — how long
/await-subagents blocks. Both are re‑read per call from the process environment — the
Operations page marks them env-only (no instance_flags override is
consulted), so a new value takes effect only on restart with a new env.
Issue attachments¶
See attachments.md for the full pipeline. Caps:
TRIMUS_ATTACHMENT_MAX_UPLOAD_BYTES (50 MB),
TRIMUS_ATTACHMENT_MAX_FILES_PER_REQUEST (20),
TRIMUS_ATTACHMENT_EXTRACT_TIMEOUT_SEC (5),
TRIMUS_ATTACHMENT_EXTRACTED_TEXT_MAX_BYTES (200 KB),
TRIMUS_ATTACHMENT_CONTEXT_CHAR_LIMIT (50 KB ≈ 12k tokens).
Adapter & sandbox hardening¶
See adapter-isolation.md. The docker,
claude_sandbox, and codex_sandbox adapters honour
TRIMUS_DOCKER_PIDS_LIMIT / TRIMUS_SANDBOX_PIDS_LIMIT (100),
TRIMUS_DOCKER_SECURITY_OPTS (comma‑sep --security-opt). Plugin
containers honour TRIMUS_PLUGIN_PIDS_LIMIT (100),
TRIMUS_PLUGIN_SANDBOX_SECURITY_OPTS, and
TRIMUS_PLUGIN_SANDBOX=disabled (dev opt‑out). The Claude CLI guardrails
TRIMUS_FORBID_DANGEROUS_CLAUDE_PERMISSIONS and
TRIMUS_CLAUDE_BINARY_ALLOWLIST default permissive and can be tightened
per instance.
Egress DNS¶
When TRIMUS_EGRESS_DNS_ADDR is set, the deny‑by‑default DNS resolver
starts: sandboxed containers resolve only allow‑listed hostnames,
everything else gets NXDOMAIN. TRIMUS_EGRESS_DNS_DEFAULT overrides the
resolver address published into containers (default: the bridge
gateway). See adapter-isolation.md.
Observability¶
OTEL_EXPORTER_OTLP_ENDPOINT enables OTLP/HTTP trace export; the
standard OTel env vars are honoured. See monitoring.md.
Stale‑run watcher¶
Two‑stage stale → grace → cancel pipeline (defaults total 20 min):
| Variable | Default | Meaning |
|---|---|---|
TRIMUS_STALE_RUN_THRESHOLD_SEC |
600 |
No activity → stale. |
TRIMUS_STALE_RUN_GRACE_SEC |
300 |
→ grace prompt. |
TRIMUS_STALE_RUN_CANCEL_SEC |
300 |
→ auto‑cancel (error=auto_cancel_stale). |
Per‑agent / per‑company column overrides (migration 088) take
precedence: agent → company → env default; NULL inherits upward. The
poll cadence (30 s) is code‑tunable only. Activity kinds emitted:
run.stale_detected, run.grace_prompt_sent, run.auto_cancelled.
Reading them all at once¶
trimus-server logs the resolved configuration at INFO on startup with
secret values redacted (internal/middleware/redact.go). When debugging
"is this var being picked up?", grep the startup log. Live‑editable
flags and their effective values are also shown at /admin/operations.
A minimum production environment¶
DATABASE_URL='postgres://trimus:STRONGPW@db.internal:5432/trimus?sslmode=require'
TRIMUS_ENCRYPTION_KEY='<base64 32-byte>'
TRIMUS_SESSION_SECRET='<long random string>'
TRIMUS_PUBLIC_URL='https://trimus.example.com'
TRIMUS_HOME=/var/lib/trimus/home
TRIMUS_STORAGE_DIR=/var/lib/trimus/storage
TRIMUS_SECURE_COOKIES=true
TRIMUS_CSRF_TRUSTED_ORIGINS=https://trimus.example.com
TRIMUS_TRUSTED_PROXIES=10.0.0.0/8
LOG_LEVEL=info
That plus a reachable Postgres is enough for a real deployment. Layer OAuth, OTel, backups, and channels on as separate concerns.
Where to next¶
- installing.md — how the env file gets created.
- database.md — Postgres specifics.
- storage.md — what
TRIMUS_HOME/TRIMUS_STORAGE_DIRcontain. - security.md — production hardening.
- monitoring.md — the
TRIMUS_READYZ_*knobs in context.