Skip to content

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.

VariableDefaultDoes
COMMANDCHAIN_URLhttp://localhost:7000Base URL of the CommandChain instance. Used as the default for connect, start, and every creds subcommand
COMMANDCHAIN_TENANT_IDnoneWorkspace this runner serves. Used by start only. connect learns it from pairing
COMMANDCHAIN_RUNNER_CREDENTIALnoneBootstrap credential used to register. Used by start only
COMMANDCHAIN_RUNNER_NAMEnoneDisplay name. Used by start only. connect defaults to <user>@<hostname>
COMMANDCHAIN_RUNNER_CREDENTIALS_FILE~/.commandchain/runner.jsonWhere the pairing credential is stored. Intended for scripts and test harnesses that need a throwaway file
VariableDefaultDoes
COMMANDCHAIN_WORKSPACE_ROOT~/.commandchain/workspacesRoot directory for repository checkouts. One long-lived directory per repository
COMMANDCHAIN_POLL_INTERVAL_MS2000Heartbeat interval, in milliseconds
COMMANDCHAIN_CALLBACK_PORT0Port for the local callback API. 0 picks a free one
COMMANDCHAIN_TUNNEL_MAX_SESSIONS5Concurrent live-app tunnel sessions. A value that is not a positive integer is ignored with a warning
TENANT_CONCURRENCY_CAP5Runs this process will execute at once for one workspace
CHAT_CONCURRENCY3Concurrent meeting turns this process will handle at once
LOG_LEVELinfodebug when you are diagnosing something. The log is at ~/.local/state/commandchain-runner/ on Linux and ~/Library/Logs/commandchain-runner/ on macOS

Each coding agent is found on PATH by default. Set these when the binary lives somewhere else.

VariableDefaultAdapter
COMMANDCHAIN_AGENT_PATHcommandchain-agentThe built-in agent (commandchain-agent-cli)
CLAUDE_PATHclaudeClaude Code (claude-code-cli)
CODEX_PATHcodexCodex (openai-codex-cli)
GEMINI_PATHgeminiGemini (gemini-cli)

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.

VariableDefaultAdapter
COMMANDCHAIN_DEFAULT_MODELclaude-sonnet-4-6The built-in agent
CLAUDE_DEFAULT_MODELsonnetClaude Code
CODEX_DEFAULT_MODELgpt-5.4Codex
GEMINI_DEFAULT_MODELthe CLI’s own defaultGemini
VariableDefaultDoes
JWT_SECRETfalls back to DEV_JWT_SECRET, then a known local development valueVerifies 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.

VariableDefaultRead for
CLAUDE_CONFIG_DIR~/.claudeWhere Claude Code’s credential file is looked for
CODEX_HOME~/.codexWhere Codex’s auth.json is looked for
ANTHROPIC_API_KEY / CLAUDE_API_KEYnoneAn Anthropic key, when there is no Claude Code login on the machine
OPENAI_API_KEYnoneAn OpenAI key, read from Codex’s auth.json or the environment
GEMINI_API_KEY / GOOGLE_API_KEYnoneA 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.

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:

  1. An execution baseline. PATH, HOME, USER, LOGNAME, SHELL, TMPDIR, LANG and LC_*, TZ, TERM, and certificate-bundle paths. Paths and locale, no credentials.
  2. 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.
  3. 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_KEY for Claude, OPENAI_API_KEY for Codex, GEMINI_API_KEY for 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.