Runner environment variables
A runner installed with the one-line installer needs none of these: it is configured by pairing, and the service definition it writes carries no secrets. They are here for the cases where you run the program yourself.
Every variable on this page is read by the runner’s own process. None of them is handed to a coding agent, with one deliberate exception described at the bottom.
Connection
Section titled “Connection”| Variable | Default | Does |
|---|---|---|
COMMANDCHAIN_URL | http://localhost:7000 | Base URL of the CommandChain instance. Used as the default for connect, start, and every creds subcommand |
COMMANDCHAIN_TENANT_ID | none | Workspace this runner serves. Used by start only. connect learns it from pairing |
COMMANDCHAIN_RUNNER_CREDENTIAL | none | Bootstrap credential used to register. Used by start only |
COMMANDCHAIN_RUNNER_NAME | none | Display name. Used by start only. connect defaults to <user>@<hostname> |
COMMANDCHAIN_RUNNER_CREDENTIALS_FILE | ~/.commandchain/runner.json | Where the pairing credential is stored. Intended for scripts and test harnesses that need a throwaway file |
Execution
Section titled “Execution”| Variable | Default | Does |
|---|---|---|
COMMANDCHAIN_WORKSPACE_ROOT | ~/.commandchain/workspaces | Root directory for repository checkouts. One long-lived directory per repository |
COMMANDCHAIN_POLL_INTERVAL_MS | 2000 | Heartbeat interval, in milliseconds |
COMMANDCHAIN_CALLBACK_PORT | 0 | Port for the local callback API. 0 picks a free one |
COMMANDCHAIN_TUNNEL_MAX_SESSIONS | 5 | Concurrent live-app tunnel sessions. A value that is not a positive integer is ignored with a warning |
TENANT_CONCURRENCY_CAP | 5 | Runs this process will execute at once for one workspace |
CHAT_CONCURRENCY | 3 | Concurrent meeting turns this process will handle at once |
LOG_LEVEL | info | debug when you are diagnosing something. The log is at ~/.local/state/commandchain-runner/ on Linux and ~/Library/Logs/commandchain-runner/ on macOS |
Adapter paths
Section titled “Adapter paths”Each coding agent is found on PATH by default. Set these when the binary lives somewhere else.
| Variable | Default | Adapter |
|---|---|---|
COMMANDCHAIN_AGENT_PATH | commandchain-agent | The built-in agent (commandchain-agent-cli) |
CLAUDE_PATH | claude | Claude Code (claude-code-cli) |
CODEX_PATH | codex | Codex (openai-codex-cli) |
GEMINI_PATH | gemini | Gemini (gemini-cli) |
Adapter default models
Section titled “Adapter default models”Used only when the control plane has not resolved a model for the run. A model from the wrong provider family fails loudly rather than being quietly swapped.
| Variable | Default | Adapter |
|---|---|---|
COMMANDCHAIN_DEFAULT_MODEL | claude-sonnet-4-6 | The built-in agent |
CLAUDE_DEFAULT_MODEL | sonnet | Claude Code |
CODEX_DEFAULT_MODEL | gpt-5.4 | Codex |
GEMINI_DEFAULT_MODEL | the CLI’s own default | Gemini |
The shared secret
Section titled “The shared secret”| Variable | Default | Does |
|---|---|---|
JWT_SECRET | falls back to DEV_JWT_SECRET, then a known local development value | Verifies the callback tokens the control plane issues to this runner |
The runner and the platform must hold the same JWT_SECRET. A runner paired by the installer receives what it needs and you never set this; it matters only when you start the program by hand. A mismatch shows up as callbacks being rejected once a run starts, not at pairing time.
Credentials the runner reads from this machine
Section titled “Credentials the runner reads from this machine”creds push reads the coding CLIs’ own logins where those tools keep them. These variables move where it looks, or supply a key directly.
| Variable | Default | Read for |
|---|---|---|
CLAUDE_CONFIG_DIR | ~/.claude | Where Claude Code’s credential file is looked for |
CODEX_HOME | ~/.codex | Where Codex’s auth.json is looked for |
ANTHROPIC_API_KEY / CLAUDE_API_KEY | none | An Anthropic key, when there is no Claude Code login on the machine |
OPENAI_API_KEY | none | An OpenAI key, read from Codex’s auth.json or the environment |
GEMINI_API_KEY / GOOGLE_API_KEY | none | A Google key, when there is no Gemini login on the machine |
An API key is preferred over a subscription login when both are present, because a key is revocable and avoids the provider’s terms-of-service question.
What reaches a coding agent
Section titled “What reaches a coding agent”A coding agent does not inherit the runner’s environment. Each agent process is built from an allowlist, because a coding agent has a shell and network access, so anything in its environment is one request away from leaving the machine.
An agent child gets exactly three things:
- An execution baseline.
PATH,HOME,USER,LOGNAME,SHELL,TMPDIR,LANGandLC_*,TZ,TERM, and certificate-bundle paths. Paths and locale, no credentials. - The run’s selected environment. The project’s own values, released for that attempt only, injected into the process and never written into the workspace.
- That adapter’s own credential, and only its own. The attempt-scoped credential the platform released, staged into a synthetic home for that attempt. Where the runner’s own environment happens to carry that adapter’s key or base-URL settings (
ANTHROPIC_API_KEYfor Claude,OPENAI_API_KEYfor Codex,GEMINI_API_KEYfor Gemini) they are merged in first and the released credential overrides them, so no adapter ever receives another adapter’s key and the run always executes as the identity the platform released.
Everything else is dropped: the runner’s own control-plane credential, its workspace identifiers, GITHUB_TOKEN, and any unrelated key you happen to have exported.
Next steps
Section titled “Next steps”- Runner CLI: the flags these variables back.
- The runner security model: the boundary these rules sit inside.
- Agent credentials: capture, storage, and one-time release.