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_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. |
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_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 behind several gates. Two of those gates are environment variables that no config value can supply, which is what makes the kill-switch real:
| Variable | Default | Description |
|---|---|---|
CONTEXTRELAY_WRITE_MODE_ENABLED | unset | Hard env kill-switch for act:write. Must be 1/true/yes/on before any contained writable worker can run; no config can supply it, so a config alone never enables writes. |
CONTEXTRELAY_WRITE_DAILY_CAP_USD | unset | Required per-day USD cap for act:write. A missing or invalid cap fails the contained writable worker closed. |
CONTEXTRELAY_IDLE_WRITE_TIMEOUT_MS | 180000 | Wall-clock timeout for one contained act:write worker before it is force-killed. |
Setting both variables does not turn writing on. act:write also requires autonomy enabled, write-mode set to act, positive budgets, owner/kind allowlists, the strict dual-idle gate, and worktree containment - every gate must pass. Even then, a contained worker edits only inside an ephemeral git worktree and never commits, merges, or pushes. See Enabling act:write safely.
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 supplied by Claude 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.