Environment variables reference
ContextRelay is configured almost entirely through .contextrelay/config.json and the CLI. Environment variables exist as a thin override layer on top of that: they let you point a single invocation at a different port group, force activation on or off, tune a timeout, or arm one of the explicit autonomy gates.
The CLI exports the right project instance values automatically when you run ctxrelay claude, ctxrelay codex, or ctxrelay pair. You only reach for an environment variable when you need to override the automatic behavior - for example, to run a second ContextRelay on a non-default port group, or to force a session active or dormant for a one-off command.
The tables below mirror the canonical list. Each variable name, default, and behavior is verified against the source. They are split into two groups: a small Core set most people ever touch, and an Advanced tuning set of timing, autonomy, and install knobs that exist mainly for diagnostics and CI. The same split is reflected in the README (core only) and the full tuning table.
Core variables
These are the handful of variables you might actually set: activation, the port group, and runtime state. Everything else is in Advanced tuning below.
Activation: the variables most users touch
These control whether ContextRelay is active for a session and how Codex messages reach Claude. They sit on top of .contextrelay/config.json and the global activation flag - see Activation: auto-connect vs dormant for the full picture.
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_AUTO_CONNECT | unset | Highest-precedence activation override. 1/true/yes/on forces ContextRelay active for the session; 0/false/no/off forces it dormant. Overrides the attach marker and both the project and global activation.autoConnect flags. |
CONTEXTRELAY_MODE | push via ctxrelay claude, auto otherwise | Message delivery mode: push, pull, or auto. push lets the daemon deliver Codex messages into Claude's context live; pull makes Claude drain them with get_messages / wait_for_messages. |
CONTEXTRELAY_ALLOW_NAMED_SESSIONS | unset | Set 1 to enable opt-in named runtime launch (ctxrelay claude --session <id>, ctxrelay codex --session <id>) and non-default live routing. Named runtime sessions are experimental and stay off until this is set. |
The resolver checks sources in this order and stops at the first match: CONTEXTRELAY_AUTO_CONNECT → per-session attach marker → project activation.autoConnect → global activation.autoConnect → shipped default on. The environment variable always wins, which makes it the right tool for a single forced-active or forced-dormant command without changing any saved state.
Ports, state, and identity
ContextRelay assigns each project a stable instance ID and a three-port group automatically. You normally never set these; override them only to run multiple ContextRelay projects side by side, or to relocate runtime state.
| Variable | Default | Description |
|---|---|---|
CODEX_WS_PORT | auto group start 4500 | Codex app-server WebSocket port. |
CODEX_PROXY_PORT | auto group start 4501 | ContextRelay proxy port for the Codex TUI. |
CONTEXTRELAY_CONTROL_PORT | auto group start 4502 | Control port between the plugin/frontend and the daemon. |
CONTEXTRELAY_PORT_BASE | 4500 | Starting point for automatic project port allocation. |
CONTEXTRELAY_STATE_DIR | .contextrelay/state during CLI launches | Runtime state directory. |
CONTEXTRELAY_REGISTRY_DIR | platform app-state directory | Global instance registry directory. |
XDG_STATE_HOME | ~/.local/state on Linux | Linux base directory for the global registry and direct/internal defaults. |
CONTEXTRELAY_INSTANCE_ID | generated | Stable project instance id exported by the CLI. |
CONTEXTRELAY_PROJECT_ROOT | current project root | Project root exported by the CLI. |
CONTEXTRELAY_RUNTIME_SESSION_ID | unset | Runtime session attached by ctxrelay claude --session <id>. |
Set all three of CODEX_WS_PORT, CODEX_PROXY_PORT, and CONTEXTRELAY_CONTROL_PORT, or set none of them. A partial override is rejected with an explicit error rather than silently guessing the missing ports. This guards against half-configured port groups that would route Claude and Codex to mismatched daemons.
# Correct: a full, self-consistent port group for a second project
CODEX_WS_PORT=4600 \
CODEX_PROXY_PORT=4601 \
CONTEXTRELAY_CONTROL_PORT=4602 \
ctxrelay pair
# Easier alternative - let the CLI pick a free group from a new base
ctxrelay pair --port-base 4600
Advanced tuning
Everything below is opt-in tuning. The shipped defaults are the supported configuration; reach for these only to debug a specific behavior, run in CI, or arm one of the explicit autonomy gates. None of these belong in the README, and none of them turn autonomy on by itself.
Message and turn coordination
These tune how Codex narration and turn lifecycle pings reach Claude. The shipped defaults implement the quiet, digest-based experience; override them to make the live channel more (or less) verbose.
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_USAGE_MODE | unset | Per-invocation usage-preset override (off, lean, strict); highest precedence, never persisted. Covers shared-context tool shaping, headless output caps, and the bridge contract reminder cadence. For CI/automation. |
CONTEXTRELAY_TURN_DIGEST | 1 | Set 0 to disable turn-scoped digest buffering for Codex transcript messages. |
CONTEXTRELAY_DIGEST_UNTAGGED | 1 | Set 0 to keep untagged Codex narration pushed live instead of buffering it into the turn digest. |
CONTEXTRELAY_RESPECT_TARGET | 0 | Set 1 to suppress live Claude delivery for Codex messages whose explicit target is not claude; the ledger audit trail remains intact. |
CONTEXTRELAY_QUIET_TURN_PINGS | 1 | Set 0 to push routine ⏳/✅ Codex turn-lifecycle pings into Claude's live context. |
CONTEXTRELAY_FILTER_MODE | filtered | Message-routing filter mode. Set full for full routing payloads. |
CONTEXTRELAY_MAX_BUFFERED_MESSAGES | 100 | Maximum undrained Claude-bound Codex messages per chat. |
CONTEXTRELAY_MCP_TOOLS | unset | Optional comma/space-separated MCP tool allowlist. |
CONTEXTRELAY_ATTENTION_WINDOW_MS | 15000 | Coordination window used while waiting for a Codex turn to settle. |
CONTEXTRELAY_PAIR_BIN | contextrelay | CLI binary used by ctxrelay pair. |
CONTEXTRELAY_CLAUDE_DEVELOPMENT_CHANNELS | 1 | Set 0 to use Claude's approved channel path. |
CONTEXTRELAY_NAMED_CODEX_RUNTIME_START_ATTEMPTS | 3 | Maximum daemon-side launch attempts for named Codex runtime ports. |
Timeouts and reliability bounds
ContextRelay applies several wall-clock budgets so a stuck agent, a dropped TUI, or a hung turn cannot wedge a session. These are the knobs you adjust when a long legitimate turn keeps getting force-cleared.
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_TURN_MAX_MS | 300000 | Wall-clock budget for one Codex turn. Set 0 to disable. |
CONTEXTRELAY_CODEX_TURN_IDLE_TIMEOUT_MS | 300000 | Codex silence window before a stuck turn is force-cleared. |
CONTEXTRELAY_CLAUDE_RESPONSE_TIMEOUT_MS | 300000 | Timeout before a Claude-owned active task lane is considered stale. |
CONTEXTRELAY_CLAUDE_PROBE_TIMEOUT_MS | 3000 | Liveness probe timeout before stale Claude eviction. Set 0 to disable. |
CONTEXTRELAY_CLAUDE_STALE_REAP_MS | 90000 | Minimum Claude attachment age before status broadcasts may reap it. |
CONTEXTRELAY_CLAUDE_STALE_REAP_COOLDOWN_MS | 60000 | Cooldown between stale Claude attachment probes. |
CONTEXTRELAY_IDLE_SHUTDOWN_MS | 30000 | Idle daemon shutdown window. |
TUI_DISCONNECT_GRACE_MS | 2500 | Grace after a Codex TUI disconnect before treating it as gone. |
CONTEXTRELAY_MAX_DEPTH | 3 | Maximum relay recursion depth. |
CONTEXTRELAY_DAEMON_SHUTDOWN_STEP_TIMEOUT_MS | 4000 | Per-step daemon shutdown cleanup deadline. |
CONTEXTRELAY_DISABLED_RECOVERY_INTERVAL_MS | 5000 | Poll interval for the bridge's dormant-state recovery loop while ContextRelay is disabled for the session. |
CONTEXTRELAY_MAX_CONTROL_MESSAGE_BYTES | 1000000 | Maximum accepted control WebSocket message size. |
CONTEXTRELAY_MAX_CONTROL_MESSAGES_PER_MINUTE | 120 | Per-control-connection rate limit. |
CONTEXTRELAY_RATE_LIMIT_RESUME | (config) | Override the rate-limit auto-resume mode for this run: off, notify, or resume. See rateLimitResume in config.json. |
CONTEXTRELAY_RATE_LIMIT_RESUME_POLL_MS | 30000 | Poll cadence while a captured rate-limited message waits for its reset time. |
CONTEXTRELAY_RATE_LIMIT_RESUME_EXPIRY_MS | 172800000 | Hard TTL after which a persisted capture is discarded (48 h). |
A "daemon disconnected" message in the middle of a genuinely long turn is often the CONTEXTRELAY_TURN_MAX_MS watchdog firing at 5 minutes, not a real crash. Check ctxrelay status before restarting anything. If you routinely run long turns, raise the budget (for example CONTEXTRELAY_TURN_MAX_MS=900000) rather than fighting the reset. See Troubleshooting.
Autonomy, idle scanner, and backup agents
The idle scanner, read-only backup agents, and the idle worker fleet are opt-in. The variables below tune or hard-disable those features; none of them turns autonomy on by itself - the autonomy.* config and the ctxrelay autonomy / ctxrelay idle-scanner commands gate the actual behavior. See Autonomy and safe automation.
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_IDLE_SCANNER | 1 | Set 0 to hard-disable the idle-opportunity scanner scheduler regardless of the configured mode. |
CONTEXTRELAY_IDLE_ACTION_TIMEOUT_MS | 120000 | Timeout for one idle-scanner act read-only worker. |
CONTEXTRELAY_IDLE_ACTION_TOKEN_BUDGET | 120000 | Env override for autonomy.idleActionBudgets.tokenBudget, the per-daemon-session token budget for idle-scanner act workers. |
CONTEXTRELAY_IDLE_ACTION_COST_BUDGET_USD | 1 | Env override for autonomy.idleActionBudgets.costBudgetUsd, the per-daemon-session cost budget in USD for idle-scanner act workers. |
CONTEXTRELAY_IDLE_ACTION_BUDGET_WARNING_PCT | 80 | Env override for autonomy.idleActionBudgets.warningPct, the budget-pressure percentage that surfaces warnings. |
CONTEXTRELAY_IDLE_ACTION_COMPARISON_EXTRA_BUDGET_USD | 0 | Env override for autonomy.idleActionBudgets.comparisonExtraBudgetUsd, extra per-session USD headroom for manual idle-evaluation compare estimates before the nightly cap is checked. |
CONTEXTRELAY_IDLE_FLEET_MAX_WORKERS | 3 | Maximum read-only leaf workers for one high-confidence act fleet. |
CONTEXTRELAY_IDLE_DEFERRED_DISPATCH_TTL_MS | 900000 | Hard TTL for an act-mode dispatch deferred while awaiting strict quiescence. |
CONTEXTRELAY_IDLE_DEFERRED_DISPATCH_POLL_MS | 20000 | Poll interval while an act-mode dispatch is deferred awaiting quiescence. |
CONTEXTRELAY_IDLE_EVAL_ENABLED | unset | Required explicit opt-in for real-token idle-evaluation probes; unset keeps probe dispatch fail-closed. |
CONTEXTRELAY_IDLE_EVAL_NIGHTLY_CAP_USD | unset | Required nightly USD cap for real-token idle-evaluation probes, enforced above per-session budgets when evaluation is enabled. |
CONTEXTRELAY_BACKUP_THROTTLE_MS | 60000 | Minimum delay between backup starts for the same target. |
CONTEXTRELAY_BACKUP_KILL_GRACE_MS | 2000 | Grace between a backup-timeout SIGTERM and SIGKILL. |
CONTEXTRELAY_WORKER | unset | Internal worker-mode signal for read-only act and backup workers. Set to 1 by the daemon when it spawns a worker process; it prevents the worker from recursively starting another ContextRelay. Do not set this yourself. |
act:write (autonomous edits)
Enabling act:write - letting an idle worker make contained file edits - is off by default and stays fail-closed. It has no environment variables of its own: you arm it entirely through config (autonomy.writableAction.enabled plus a positive autonomy.writableAction.budgetUsd). The contained worker always runs inside Codex's workspace-write OS sandbox, which confines writes to the worktree + system temp; your project and its .contextrelay/config.json live outside those, and act:write refuses if the project is under system temp - so the worker cannot re-arm itself. The only env knob is the worker's wall-clock timeout:
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_IDLE_WRITE_TIMEOUT_MS | 180000 | Wall-clock timeout for one contained act:write worker before it is force-killed. |
Setting enabled: true and a positive budgetUsd does not let act:write escape its bounds. The contained worker still runs only when the strict dual-idle and single-flight gates pass and the daily budget check holds, and it always executes inside Codex's workspace-write OS sandbox on an ephemeral git worktree - it never commits, merges, or pushes. That sandbox confines writes to the worktree and the system temp area; your primary tree and config live outside those, and act:write refuses to run if the project is itself under a system-temp directory - so the worker cannot escalate or re-arm itself. (Live-verified on macOS; the Codex sandbox is expected to behave the same on other platforms but is not yet separately verified.) See Enabling act:write safely.
Headless reviewers
On-demand headless reviewers (contained_run / ctxrelay headless run) fire one read-only job through a registered contained adapter (codex, claude, and conditionally opencode) for a fresh-context second opinion. The daemon pools and budgets these jobs; headless.enabled defaults to true and is independent of the autonomy config — asking for a one-shot review is normal collaboration, not an autonomous action.
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_HEADLESS_ENABLED | 1 | Master kill switch for the whole headless surface. Set 0 to disable contained_run regardless of config. |
CONTEXTRELAY_HEADLESS_MAX_CONCURRENCY | 4 | Maximum concurrent headless jobs the daemon pool will admit. |
CONTEXTRELAY_HEADLESS_MAX_QUEUE | 64 | Maximum jobs queued waiting for a pool slot; excess requests are rejected. |
CONTEXTRELAY_HEADLESS_BUDGET_USD | 0 | Optional per-session post-hoc USD spend cap (0 = uncapped). |
CONTEXTRELAY_HEADLESS_TIMEOUT_MS | 180000 | Per-job wall-clock timeout before the headless worker is force-killed. |
CONTEXTRELAY_OPENCODE_ENABLED | 1 | Opencode-adapter kill switch. Set 0/false/off to hide only the opencode headless adapter even when the CLI and macOS sandbox probe are available. |
CONTEXTRELAY_OPENCODE_MODEL | unset | Optional model for the read-only opencode headless adapter. When unset (and OPENCODE_MODEL is also unset), the adapter passes no --model and lets opencode use its own default. |
CONTEXTRELAY_OPENCODE_AUTH_JSON | unset | Optional path to an opencode auth.json file copied into the adapter's isolated sandbox HOME for a single job. Provider API key env vars are not forwarded to opencode. |
CONTEXTRELAY_OPENCODE_USE_STORED_AUTH | unset | Set 1 to copy ${HOME}/.local/share/opencode/auth.json into the adapter's isolated sandbox HOME. Leave unset to require explicit CONTEXTRELAY_OPENCODE_AUTH_JSON or another OPENCODE_* auth mechanism. |
Install, hooks, and host integration
These cover the npm install/uninstall lifecycle, the bundled Claude Code hook scripts, and a few internal overrides. They are mostly relevant to CI, packaging, and local development.
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_AUTO_REGISTER | unset | Opt into automatic Claude plugin registration during npm install. |
CONTEXTRELAY_AUTO_UNREGISTER | unset | Opt into removing Claude plugin registration during uninstall. |
CONTEXTRELAY_POSTINSTALL_DRY_RUN | unset | Print postinstall/preuninstall actions without changing registration. |
CONTEXTRELAY_POSTINSTALL_STRICT | unset | Make optional postinstall registration failures exit non-zero. |
CONTEXTRELAY_DAEMON_ENTRY | bundled daemon | Plugin daemon entry override. |
CONTEXTRELAY_ALLOW_DAEMON_ENTRY_OVERRIDE | unset | Set 1 only for local development/tests. |
CONTEXTRELAY_HEALTH_HOOK_COOLDOWN_SECONDS | 120 | Cooldown for bundled Claude health-check hook reminders. |
CONTEXTRELAY_HOOK_STATE_DIR | ${TMPDIR:-/tmp}/contextrelay-hooks | State directory for bundled hook scripts. |
CONTEXTRELAY_HOOK_COMPACT | unset | Set 1 to force compact UserPromptSubmit hook output. |
CONTEXTRELAY_HOOK_PREVIEW_LIMIT | mode preset | Override the pending-message preview count. |
CONTEXTRELAY_HOOK_PREVIEW_CHARS | mode preset | Override the pending-message preview character cap. |
CONTEXTRELAY_HOOK_DEDUPE_SECONDS | mode preset | Override the identical-hook-output suppression window. |
CONTEXTRELAY_CODEX_PROXY_TOKEN | generated | Internal Codex remote-auth token. |
CONTEXTRELAY_CODEX_APP_SERVER_TRANSPORT | auto | Internal Codex app-server transport override. |
CONTEXTRELAY_LOG_MAX_BYTES | 52428800 | Maximum size of a ContextRelay process log file before it is truncated. 0 disables the cap. |
Claude Code host variables
These are supplied by Claude Code itself to the bundled hooks; ContextRelay reads them but does not own them.
| Variable | Purpose |
|---|---|
CLAUDE_PLUGIN_ROOT | Bundled hook-script root. Expanded by Claude Code from ${CLAUDE_PLUGIN_ROOT} in hooks.json/.mcp.json; not read from process.env by ContextRelay's own code. |
CLAUDE_PROJECT_DIR | Claude project directory when supplied by Claude Code. ContextRelay falls back to PWD. |
The partial-override rule, restated
Because it is the one rule that bites people, it is worth repeating on its own:
Environment overrides that come in groups must be set as a complete group. The clearest example is the port trio - set all of
CODEX_WS_PORT,CODEX_PROXY_PORT, andCONTEXTRELAY_CONTROL_PORT, or none. A partial set is rejected, not patched.
If you only need a different port group, prefer ctxrelay pair --port-base <port> (or ctxrelay claude / ctxrelay codex with the same flag) and let the CLI export a consistent group for you.
Next steps
- config.json reference - the durable home for almost every setting these variables override.
- CLI command reference - the commands that read and export these values.
- Activation: auto-connect vs dormant - how
CONTEXTRELAY_AUTO_CONNECTfits the full precedence chain.