Skip to main content
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.

Comis Variables

COMIS_CONFIG_PATHS

PropertyValue
Used byDaemon, CLI
FormatColon-separated file paths
Default~/.comis/config.yaml:~/.comis/config.local.yaml
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.
export COMIS_CONFIG_PATHS="$HOME/.comis/config.yaml:$HOME/.comis/config.local.yaml"

COMIS_DATA_DIR

PropertyValue
Used byDaemon
FormatAbsolute directory path
Default~/.comis
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.
export COMIS_DATA_DIR="/var/lib/comis"

COMIS_GATEWAY_URL

PropertyValue
Used byCLI
FormatWebSocket URL
DefaultResolved 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.
export COMIS_GATEWAY_URL="ws://192.168.1.100:4766/ws"

COMIS_GATEWAY_TOKEN

PropertyValue
Used byCLI
FormatString (bearer token)
DefaultResolved 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.
export COMIS_GATEWAY_TOKEN="my-secret-token"

COMIS_GATEWAY_HOST

PropertyValue
Used byDaemon
FormatHostname or IP address
DefaultValue of gateway.host in config.yaml
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
export COMIS_GATEWAY_HOST=0.0.0.0

COMIS_GATEWAY_PORT

PropertyValue
Used byDaemon
FormatInteger 1–65535
DefaultValue of gateway.port in config.yaml
Overrides gateway.port. Must be a valid integer 1–65535; non-numeric values are dropped silently. Source: packages/core/src/config/env-layer.ts:28
export COMIS_GATEWAY_PORT=4766

COMIS_INSECURE

PropertyValue
Used byCLI
Format1 to enable, unset to disable
Default(unset)
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.
export COMIS_INSECURE=1

COMIS_LOG_PATH

PropertyValue
Used byCLI (daemon logs command)
FormatAbsolute file path
Default~/.comis/daemon.console.log
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.
export COMIS_LOG_PATH="/var/log/comis/daemon.console.log"

COMIS_OFFLINE

PropertyValue
Used byDaemon, CLI
Format1 to enable, unset to disable
Default(unset)
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.
export COMIS_OFFLINE=1

COMIS_TRAJECTORY_DIR

PropertyValue
Used byDaemon
FormatAbsolute directory path
DefaultValue 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
export COMIS_TRAJECTORY_DIR=/var/log/comis/traces

COMIS_DISABLE_RECALL_TRACE

PropertyValue
Used byDaemon
Format1 to disable, unset to use config
Default(unset)
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
export COMIS_DISABLE_RECALL_TRACE=1

COMIS_CONFIG_AUDIT_LOG

PropertyValue
Used byDaemon
FormatAbsolute file path
Default~/.comis/logs/config-audit.jsonl
Overrides the full file path of the config-audit JSONL log. Source: packages/observability/src/config-audit/log-path.ts:22
export COMIS_CONFIG_AUDIT_LOG=/var/log/comis/config-audit.jsonl

COMIS_BROKER_TOKEN

PropertyValue
Used byExec tool (daemon-spawned subprocess)
FormatOpaque bearer token string
Default(set internally by the daemon per-command)
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

Secret Variables

SECRETS_MASTER_KEY

PropertyValue
Used byDaemon, CLI
Format64-character hex string or base64-encoded 32 bytes
DefaultAuto-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.

OAuth Variables

OAUTH_OPENAI_CODEX

PropertyValue
Used byDaemon (one-time bootstrap when the OAuth credential store has no profile for openai-codex)
FormatJSON: {"access":"...","refresh":"...","expires":<epochMs>,"accountId":"...","email":"..."}
Default(none)
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:
  1. 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.
  2. 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.
  3. 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.
For the full bootstrap-precedence walkthrough including drift-handling examples, see OAuth concepts → Env-var bootstrap precedence.

Standard Variables

NODE_ENV

PropertyValue
Used byNode.js runtime
Formatdevelopment, production, test
Default(unset)
Standard Node.js environment variable. Affects behavior of some dependencies and may influence logging verbosity. Comis does not require this variable to be set.
export NODE_ENV=production

Development and Regression Variables

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.

COMIS_LCD_REGRESSION

PropertyValue
Used byThe env-gated real-LLM regression driver (real-llm-regression.bench.test.ts)
Format1 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.
export COMIS_LCD_REGRESSION=1

COMIS_LCD_ANSWER_PROVIDER / COMIS_LCD_ANSWER_MODEL / COMIS_LCD_ANSWER_API_KEY

PropertyValue
Used byThe env-gated real-LLM regression driver
FormatProvider id / model id / API key strings
Default(unset → the provider-backed probes self-skip)
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.

COMIS_LCD_LIMIT

PropertyValue
Used byThe env-gated real-LLM regression driver
FormatNon-negative integer
Default(unset → the default probe count)
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.

Live-fire testing (operator)

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.

COMIS_LIVE

PropertyValue
Used byLive-fire test runner (test/live/runner.ts)
Format1 to enable, unset to skip
Default(unset — the entire live tier is skipped)
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.
export COMIS_LIVE=1

COMIS_LIVE_BUDGET_USD

PropertyValue
Used byLive-fire cost governor (test/live/cost.ts)
FormatDecimal USD amount (e.g. 2.00)
Default2.00
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 sweep
export COMIS_LIVE_BUDGET_USD=0.50   # lower for a single scenario

COMIS_LIVE_JUDGE_PROVIDER / COMIS_LIVE_JUDGE_MODEL / COMIS_LIVE_JUDGE_API_KEY

PropertyValue
Used byThe live-fire judge wrapper (test/live/judge.ts judgeAnswer) for judged Stage-C scoring
FormatProvider name / pinned model snapshot id / API key (the rubric-judge model lane)
Defaultunset — 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).
export COMIS_LIVE_JUDGE_PROVIDER=anthropic
export COMIS_LIVE_JUDGE_MODEL=claude-3-5-haiku-20241022
export COMIS_LIVE_JUDGE_API_KEY=sk-ant-...

COMIS_LIVE_PROBES

PropertyValue
Used byLive-fire test runner (pnpm test:live sweep)
FormatComma-separated probe IDs or category prefixes
Default(unset — all probes run)
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 probes
export COMIS_LIVE_PROBES="llm-anthropic,llm-openai,llm-groq"

# Run all search probes
export COMIS_LIVE_PROBES="search"

LLM Provider Keys

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.
VariableProviderReference
ANTHROPIC_API_KEYAnthropic (Claude family)sk-ant-...
OPENAI_API_KEYOpenAI (GPT family, Whisper, DALL-E, embeddings)sk-...
GOOGLE_API_KEYGoogle AI Studio (Gemini family)AIza...
GROQ_API_KEYGroq (Llama, Whisper)gsk_...
MISTRAL_API_KEYMistral AI
DEEPSEEK_API_KEYDeepSeeksk-...
XAI_API_KEYxAI (Grok, search)xai-...
TOGETHER_API_KEYTogether AI
CEREBRAS_API_KEYCerebrascsk-...
OPENROUTER_API_KEYOpenRouter (multi-provider proxy)sk-or-...
# .env example: pick the providers you actually use
ANTHROPIC_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.

Voice and Media

Optional. When unset, the matching feature falls back to the provider keys above (e.g. OpenAI for TTS) or is disabled.
VariableUsed For
ELEVENLABS_API_KEYElevenLabs premium TTS voices
DEEPGRAM_API_KEYDeepgram Nova-3 speech-to-text
ELEVENLABS_API_KEY=sk_...
DEEPGRAM_API_KEY=dg-...

Web Search Providers

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.
VariableProvider
SEARCH_API_KEYBrave Search (BSA...)
PERPLEXITY_API_KEYPerplexity AI (pplx-...)
TAVILY_API_KEYTavily AI (tvly-...)
EXA_API_KEYExa neural search
JINA_API_KEYJina reader/search (jina_...)

Channel Credentials

Required only for channels you enable in config.yaml. Each value can also be stored as a SecretRef and referenced via ${VAR_NAME} substitution.

Telegram

VariablePurpose
TELEGRAM_BOT_TOKENBot token from BotFather (e.g. 123456:ABC-...)
TELEGRAM_WEBHOOK_SECRETOptional webhook signature verification secret

Discord

VariablePurpose
DISCORD_BOT_TOKENBot token from the Discord developer portal (MTIz...)

Slack

VariablePurpose
SLACK_BOT_TOKENOAuth bot token (xoxb-...)
SLACK_APP_TOKENApp-level token for Socket Mode (xapp-...)
SLACK_SIGNING_SECRETWebhook signature verification (HTTP mode)

LINE

VariablePurpose
LINE_CHANNEL_ACCESS_TOKENLong-lived channel access token
LINE_CHANNEL_SECRETChannel secret for HMAC verification

IRC

VariablePurpose
IRC_NICKSERV_PASSWORDNickServ password for nickname identification

Email

VariablePurpose
EMAIL_PASSWORDIMAP password (basic auth)
EMAIL_OAUTH_CLIENT_IDOAuth2 alternative to password
EMAIL_OAUTH_CLIENT_SECRETOAuth2 client secret
EMAIL_REFRESH_TOKENOAuth2 refresh token
WhatsApp, Signal, and iMessage use file-based credentials in their respective auth directories rather than environment variables. See Channels for setup.

Quick Setup with comis configure

Most users never edit .env by hand. The interactive flow:
comis init                  # First-time setup
comis 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 Variable Substitution

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.
gateway:
  tokens:
    - id: default
      secret: "${COMIS_GATEWAY_TOKEN}"
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).

Local Model Runtime Selection (MLX vs GGUF)

When running qwen3.6 or other local models via Ollama, the runtime format affects inference latency:
PlatformRecommended RuntimeOllama Tag Example
Apple Silicon (M1/M2/M3/M4)MLXqwen3.6:35b-mlx
Linux / x86-64GGUF (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:
providers:
  entries:
    local:
      type: ollama
      models:
        - id: qwen3.6:35b-mlx  # Apple Silicon (MLX runtime)
        # - id: qwen3.6:35b    # Linux / x86-64 (GGUF / llama.cpp)
To measure the latency difference between runtimes on your hardware, run the bench harness with both tags:
BENCH_MODELS=qwen3.6:35b-mlx,qwen3.6:35b \
  node scripts/bench-small-model/comprehension.mjs
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.

Config YAML

Full configuration file reference

Secret Manager

Encrypted secret storage

CLI Reference

Command-line interface reference

Installation

Initial setup and configuration