Complete reference for all Comis environment variables
What this is for: every environment variable Comis reads — provider API keys, channel tokens, encryption secrets, infrastructure paths. Who it’s for: anyone wiring API keys, deploying to Docker, or running CI pipelines.Comis reads 40+ environment variables across encryption, LLM providers, voice/media, web search, channel credentials, and infrastructure. Most variables are also referenceable from config.yaml via ${VAR_NAME} substitution — you typically pick one location per credential. The canonical templates are /.env.example (host install) and /.env.docker.example (Docker Compose).
The interactive setup wizard (comis init, comis configure) populates the most common variables for you and writes them to ~/.comis/.env. Manual editing is only needed for advanced or non-interactive setups.
Specifies which YAML configuration files to load, as a colon-separated list (like PATH). Files are loaded in order and deep-merged, with later files overriding earlier ones. Non-existent files are silently skipped. The daemon reads this variable at startup to locate config files. The CLI uses it in config validate and pm2 setup commands. For full details on the config-path syntax and merge behavior, see Configuration.
Overrides the base data directory where Comis stores its databases, logs, and runtime files. When set, the daemon uses this path instead of the default ~/.comis directory. This is useful for containerized deployments or when running multiple instances.
Resolved from ~/.comis/config.yaml gateway section, or ws://localhost:4766/ws
Overrides the WebSocket URL the CLI uses to connect to the daemon gateway. The CLI normally reads the gateway host and port from the config file on disk, but this variable takes precedence when set.
Resolved from first token secret in ~/.comis/config.yaml
Overrides the bearer token the CLI sends when connecting to the daemon gateway. The CLI normally extracts the first token secret from the gateway config file, but this variable takes precedence.
Overrides gateway.host. Applied via buildGatewayEnvLayer() at lower priority than config.yaml. Use 0.0.0.0 to bind all interfaces (e.g., Docker deployments).Source: packages/core/src/config/env-layer.ts:27
When set to 1, allows the CLI to send bearer tokens over unencrypted WebSocket connections to non-localhost hosts. Without this variable, the CLI refuses to send credentials over cleartext connections to remote hosts as a security measure.
Setting this variable bypasses transport security checks. Use only for development or when TLS termination happens at a reverse proxy. Never use in production without a TLS layer.
Overrides the file that the comis daemon logs command reads from when systemd is not available. That file is the daemon’s raw stdout/stderr capture (daemon.console.log), written by the CLI when it spawns the daemon in direct mode — not the structured JSON log. For the structured application logs, read ~/.comis/logs/daemon.1.log directly.
When set to 1, disables outbound network calls to fetch optional tooling at startup (e.g. binary downloads, model lists, MCP server discovery). Use this for air-gapped deployments. Configured channels and provider APIs continue to work — COMIS_OFFLINE only gates provisioning traffic, not runtime LLM/channel calls.
Value of observability.trajectory.dirOverride in config.yaml
Overrides observability.trajectory.dirOverride. Relocates runtime trajectory JSONL files to a custom directory. Empty or whitespace values are dropped silently.Source: packages/core/src/config/env-layer.ts:30
Set to 1 to hard-disable the recall trace recorder regardless of config.yaml. Secondary escape hatch alongside diagnostics.recallTrace.enabled: false.Source: packages/observability/src/recall-trace/runtime.ts:304
Internal use only. A single-use proxy token injected into the exec tool’s spawn environment by the daemon’s broker-activation wiring. Consumed by the credential broker via Proxy-Authorization: Bearer. Set internally by the daemon per-command — operators do not set this variable directly. Documented here so operators diagnosing broker 407 errors can understand where the token originates.Source: packages/daemon/src/wiring/setup-broker-activation.ts:79
64-character hex string or base64-encoded 32 bytes
Default
Auto-generated on first boot and written to ~/.comis/.env (mode 0600)
The AES-256-GCM master encryption key used to encrypt and decrypt secrets stored in secrets.db. The key is auto-generated on first boot — you do not need to run comis secrets init for a fresh install. The daemon and CLI both resolve this key in the same order: first from the environment, then from ~/.comis/.env.Providing this variable explicitly overrides the auto-generated value.
Back up ~/.comis/.env. This file is the only copy of the auto-generated master key. Losing it makes secrets.db permanently unreadable — AES-256-GCM has no key escrow or recovery path.
# Auto-generated on first boot — back up ~/.comis/.env immediately# To override with a specific key:export SECRETS_MASTER_KEY="a1b2c3d4e5f6..."
To run without the encrypted store, set security.storage: env (or file) in
config.yaml. The daemon emits a startup WARN when a non-encrypted storage mode
is active.
Pre-seeds the OAuth credential store with a profile for openai-codex on the first daemon start when the store is empty. After bootstrap, the stored profile is the source of truth — subsequent daemon starts ignore this env var even if its value changes.
# Example: pre-seed via env var (CI / Docker)export OAUTH_OPENAI_CODEX='{"access":"EXAMPLE-access","refresh":"EXAMPLE-refresh","expires":1735689600000,"accountId":"EXAMPLE-acct","email":"user@example.com"}'
Bootstrap precedence:
Stored profile wins. If the OAuth credential store already has a profile for openai-codex, the daemon uses it and ignores OAUTH_OPENAI_CODEX entirely.
Env var is a one-time seed. When the store is empty for the provider, the daemon parses the env var and writes the profile. Subsequent token refreshes update the stored profile, not the env var.
WARN once on drift. If the env-var refresh token differs from the stored profile’s refresh token, the daemon emits one WARN per (provider, process) with errorKind: "config_drift" and hint: "env-override-ignored". Operators clear the drift by either:
Running comis auth logout --profile <id> then restarting the daemon to re-bootstrap from env, or
Deleting the env var if the stored profile is the intended source of truth.
This env var contains an OAuth refresh token. Treat it like a password. Use your CI / orchestrator’s secret-store integration; never paste it into config files or commit it to version control.
Standard Node.js environment variable. Affects behavior of some dependencies and may influence logging verbosity. Comis does not require this variable to be set.
These variables gate an optional developer regression suite. They are never
required for normal operation — when they are unset the suite self-skips, so a
default pnpm test / pnpm validate run makes no provider call and incurs no
cost. They are read only at the test boundary; provider keys live in a git-ignored
scripts/lcd-regression.env (the committed scripts/lcd-regression.env.example
documents them) and are never logged or committed.
The env-gated real-LLM regression driver (real-llm-regression.bench.test.ts)
Format
1 to enable, unset to skip
Default
(unset → the suite is skipped)
Master gate for the v2.12 “Lossless Context DAG” real-LLM regression driver. When
unset, the entire suite is skipped (no provider call, no network). When set, the
driver runs a tool-free baseline probe + a single-read probe and records the
stream:context cache-trace.
The answer-model lane for the regression driver. All three must be set for the
provider-backed probes to run; absent any one, the probes self-skip even when
COMIS_LCD_REGRESSION is set. The key is forwarded to the provider’s typed
apiKey option and is never stored, logged, or echoed.
Cost bound for the regression driver. Caps the number of real provider calls when
the suite is enabled; set to 0 for a record-only ($0) run that still executes
the structural stream:context / assembledShape assertions without a live call.
These variables gate the pnpm test:live real-provider test tier. They are never
required for normal operation — when COMIS_LIVE is unset the entire live tier
self-skips, so a default pnpm test / pnpm validate run makes no provider call
and incurs no cost.
Master gate for the real-provider live test tier. When unset, pnpm test:live exits 0
immediately with a “Live tier skipped” message — no provider call, no network, no cost.
When set to 1, the runner dispatches to the scenario specified by the mode argument.
Hard-stop ceiling for a single pnpm test:live run. The cost governor accumulates
per-call cost estimates and aborts the run with a non-zero exit when the running
total exceeds this value, preventing runaway spend. Set a lower value for exploratory
runs; raise it only for full suite sweeps.
export COMIS_LIVE_BUDGET_USD=5.00 # raise for a full suite sweepexport COMIS_LIVE_BUDGET_USD=0.50 # lower for a single scenario
The live-fire judge wrapper (test/live/judge.tsjudgeAnswer) for judged Stage-C scoring
Format
Provider name / pinned model snapshot id / API key (the rubric-judge model lane)
Default
unset — judged scenarios skip (skip is not fail)
The judge model lane for behavioral / answer-quality scoring (reuses the bench-memory
judge discipline). When all three are present, judgeAnswer invokes the real judge at
temperature 0 and returns a scored pass/fail; when absent, it returns a skip (judged
Stage-C scenarios then skip — never fail). For any published readiness claim, use
cross-judge ≥2 (a second judge model + agreement) to avoid self-preference bias. The
judge prompt, output, and key are never logged or written to a report (secret residency).
Filters which sweep probes run when executing pnpm test:live sweep. When unset, all probes
in PROBE_REGISTRY are executed. When set, only probes whose id or category matches one of
the comma-separated values are included.Parsed by parseProbeFilter() in test/live/sweep/sweep.ts.
# Run only LLM probesexport COMIS_LIVE_PROBES="llm-anthropic,llm-openai,llm-groq"# Run all search probesexport COMIS_LIVE_PROBES="search"
At least one provider key is required. Each provider is detected at startup; missing keys disable the matching provider gracefully. All keys can also be stored encrypted via comis secrets set instead of plaintext in .env.
Variable
Provider
Reference
ANTHROPIC_API_KEY
Anthropic (Claude family)
sk-ant-...
OPENAI_API_KEY
OpenAI (GPT family, Whisper, DALL-E, embeddings)
sk-...
GOOGLE_API_KEY
Google AI Studio (Gemini family)
AIza...
GROQ_API_KEY
Groq (Llama, Whisper)
gsk_...
MISTRAL_API_KEY
Mistral AI
—
DEEPSEEK_API_KEY
DeepSeek
sk-...
XAI_API_KEY
xAI (Grok, search)
xai-...
TOGETHER_API_KEY
Together AI
—
CEREBRAS_API_KEY
Cerebras
csk-...
OPENROUTER_API_KEY
OpenRouter (multi-provider proxy)
sk-or-...
# .env example: pick the providers you actually useANTHROPIC_API_KEY=sk-ant-...OPENAI_API_KEY=sk-...
Some providers reuse a parent key for sub-services: OpenAI Whisper STT and DALL-E image-gen use OPENAI_API_KEY; Groq Whisper uses GROQ_API_KEY; Grok search uses XAI_API_KEY. See Models for the wired catalog.
Optional. The agent picks an enabled provider when a web_search tool runs. Leave them all unset and the agent falls back to a no-op or the LLM’s own search capability.
WhatsApp, Signal, and iMessage use file-based credentials in their respective auth directories rather than environment variables. See Channels for setup.
Most users never edit .env by hand. The interactive flow:
comis init # First-time setupcomis configure # Add or rotate credentials later
Both commands write to ~/.comis/.env and (optionally) into secrets.db if a SECRETS_MASTER_KEY is configured. See comis configure for non-interactive flags.
Config YAML files support ${VAR_NAME} substitution for referencing environment variables and stored secrets. Any variable accessible via the SecretManager (including environment variables and values stored with comis secrets set) can be referenced this way.
Use $${VAR_NAME} (double dollar sign) to produce a literal ${VAR_NAME} in the output without substitution. The $include directive enables composing config from multiple files.
The COMIS_* prefix is reserved for operational variables. During comis secrets import, variables starting with COMIS_ are skipped (treated as infrastructure, not secrets).
When running qwen3.6 or other local models via Ollama, the runtime format affects
inference latency:
Platform
Recommended Runtime
Ollama Tag Example
Apple Silicon (M1/M2/M3/M4)
MLX
qwen3.6:35b-mlx
Linux / x86-64
GGUF (llama.cpp)
qwen3.6:35b
Why: MLX is optimized for the Apple Neural Engine and achieves significantly lower
inference latency on Apple Silicon. GGUF via llama.cpp is the standard format for
Linux deployments and cloud VPS instances.Comis does not distinguish between MLX and GGUF tags — both are treated as opaque
Ollama model IDs. Set the model ID in your config.yaml to the tag that matches
your hardware:
The report shows average latency per model section. MLX should be faster on Apple
Silicon; GGUF should be faster or equivalent on Linux. Performance numbers for the
full qwen3.6 matrix are recorded in .planning/phases/157-re-prove-ga/ after the
Phase 157 live re-prove.