Run Claude Code and Codex as one local coding team.
ContextRelay is a local multi-agent coding orchestrator for Claude Code and Codex. It gives your repo a loopback daemon, native terminal dashboard, provider adapters, shared ledger, structured handoffs, review loops, backup-agent requests, and opt-in multi-session routing.
Use it when you want one model to plan or review while another implements, tests, debugs, or gives an independent second opinion. Everything runs around your local project: local daemon, local state, token-protected endpoints, project-scoped ports, and human-controlled autonomy defaults. ContextRelay is not a provider product, not endorsed by OpenAI or Anthropic, and not an OS sandbox.
Coding with multiple AI assistants is increasingly common, but moving between them is usually copy-paste and lost context. One assistant may be better at architecture review, another may be better at fast implementation, and the human still needs a clear control plane for what happened, who owns the next step, and when the work is actually done.
ContextRelay turns that into a local workflow instead of a copy-paste ritual:
- Pair Claude Code and Codex in the same repo with live, token-protected relay paths.
- Ask for structured handoffs instead of vague chat messages.
- Run bounded deliberations when a design choice needs a second opinion.
- Keep a durable ledger of notes, artifacts, test reports, decisions, runtime events, and finality proposals.
- Launch separate named pairs for implementation, review, or debugging lanes from the same project daemon.
- Inspect everything from a native terminal dashboard or a local browser Command Deck.
Agents share ledger entries and messages, not hidden reasoning.
| Dependency | Version | Install |
|---|---|---|
| Bun | v1.0+ | curl -fsSL https://bun.sh/install | bash |
| Claude Code | v2.1.80+ | npm install -g @anthropic-ai/claude-code |
| Codex CLI | latest | npm install -g @openai/codex |
Bun is required because the ContextRelay daemon and plugin server run on Bun.
npm install -g @proofofwork-agency/contextrelay
ctxrelay init --instructions project
ctxrelay codex-mcp install
contextrelayWhat this does:
ctxrelay init --instructions projectcreates.contextrelay/config.json, installs the Claude Code plugin, and writes managed ContextRelay guidance intoAGENTS.mdandCLAUDE.md.ctxrelay codex-mcp installregisters the ContextRelay MCP server with Codex.contextrelayopens the native ContextRelay terminal dashboard. From there you can launch the Claude+Codex pair, open the browser Command Deck, or inspect agents and session health.
Check the session:
ctxrelay status
ctxrelay instancesStop the project daemon or a named runtime session:
ctxrelay kill
ctxrelay kill --all
ctxrelay kill --session <id>git clone https://github.com/proofofwork-agency/contextrelay.git
cd contextrelay
bun install
bun run build:cli
bun run build:plugin
bun link
bun link @proofofwork-agency/contextrelay
ctxrelay init --instructions project
ctxrelay codex-mcp install
ctxrelay pairUse ContextRelay for workflows that get awkward in one chat window:
| Workflow | What happens |
|---|---|
| Planner + builder | Claude can shape the task, Codex can implement, and both can leave durable notes in one ledger. |
| Independent review | One agent can make a change while the other reviews the risk, tests, or architecture with a bounded handoff. |
| Debug lane | Keep the main pair focused while a named session investigates a failure in another checkout folder. |
| Release gate | Record build, test, package, and finality evidence before publishing. |
| Human-controlled autonomy | Read-only backup agents and auto-finality stay off unless explicitly enabled. |
- Native ContextRelay TUI for agents, session health, launch controls, and fixed hotkeys.
- Live Claude Code <-> Codex routing in the same local repo.
- Structured handoffs with reason, ask, context refs, next speaker, and handled state.
- Shared JSONL ledger for messages, notes, artifacts, backup results, runtime events, and finality.
- Codex MCP tools, Claude MCP tools, Claude slash commands, and Codex fallback markers.
- Local browser Command Deck for status, task lanes, artifacts, policy, and timeline.
- Project-scoped daemon instances and port groups so multiple repos can run at once.
- Read-only backup agents gated by explicit autonomy settings.
- Manual coordinator policy for git ownership: Claude, Codex, or human.
Claude Code
-> ContextRelay Claude plugin / MCP stdio
-> ContextRelay daemon
-> Codex app-server proxy
-> Codex TUI
Claude gets ContextRelay MCP tools through the Claude Code plugin installed by ctxrelay init. Codex gets ContextRelay MCP tools only after ctxrelay codex-mcp install, because that command writes to Codex's MCP configuration.
Codex-to-Claude MCP messages use the daemon's live relay path and are recorded in the shared ledger. Claude-to-Codex delivery uses the Codex injection path so reply-required turns and busy-state handling are preserved. If Claude sends while Codex is already in a turn, the daemon queues up to 50 pending Claude-to-Codex injections and flushes them when the current Codex turn completes. Separately, undrained Claude-bound Codex messages use CONTEXTRELAY_MAX_BUFFERED_MESSAGES, which defaults to 100.
The daemon writes session data to:
.contextrelay/sessions.json
.contextrelay/sessions/<sessionId>.jsonl
Codex TUI flags are owned by ContextRelay when using ctxrelay codex: --remote and --enable tui_app_server. Claude channel flags are owned by ContextRelay when using ctxrelay claude: --channels and --dangerously-load-development-channels.
ctxrelay claude and ctxrelay pair use Claude's development channel path by default because ContextRelay is a custom channel during Claude Code's channel research preview. Normal local installs do not need to set any channel environment variable. Set CONTEXTRELAY_CLAUDE_DEVELOPMENT_CHANNELS=0 only if plugin:contextrelay@contextrelay is available through an approved channel allowlist in your environment.
Experimental named sessions let one project daemon host more than one Claude+Codex pair. Use them for a main implementation lane plus a review or debugging lane, or to point independent agent conversations at different checkout folders without starting separate ContextRelay daemons.
The default pair stays simple:
ctxrelay claude
ctxrelay codexAdditional pairs are explicit. The first --session <id> launch creates the session if it does not exist, remembers the current folder as that session's operation path, starts the daemon-side named runtime/proxy, and tells you how to start the other side.
Codex-first:
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay codex --session review
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay claude --session reviewClaude-first:
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay claude --session review
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay codex --session reviewPre-create a session when you want a label or explicit folder:
ctxrelay session create review --worktree ../repo-review
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay claude --session review
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay codex --session reviewctxrelay status --json, the TUI Runtime Sessions panel, and ctxrelay session list show each runtime session's operation path. The stored "worktree" is that folder of operation. It is usually a git checkout or git worktree, but ContextRelay only remembers and validates the path; it does not create git worktrees. Use separate folders for sessions that can write files.
ContextRelay prevents two launched named Codex runtimes from sharing the same bound folder; the compatibility default session is not part of that guard. Named runtime sessions isolate live Claude/Codex routing when opted in, but transcript ledger, viewer, backup, and finality state remain mostly global/default-biased until the next architecture line.
ContextRelay is local developer tooling, not a security boundary between tools you do not trust. It defaults to loopback-only endpoints, local auth tokens, browser origin rejection, autonomy off, auto-finality off, read-only backup agents, and coordinator-owned git-write policy.
Provider-native Claude Code and Codex approval systems still apply inside those tools. ContextRelay records mediated permission decisions and runtime events, but it does not replace the provider approval model.
- v2.2.0 adds TUI status observability for the reliability primitives shipped in
v2.1.0: the daemon now precomputes cheap
status.observabilityfields for same-project peer count, resolution-mismatch warnings, and the current active handoff state, and the native TUI renders them as quiet one-line badges. - The idle opportunity scanner remains evidence-gated rather than enabled by default. Current measurements lean toward dropping it unless organic v2.1 runtime usage shows persistent idle/status noise.
- Agents are now explicitly taught to call
read_contextwithhandoff_idwhen reconciling a late reply after a live wait expires. - v2.1.0 added reliability primitives for long-running Claude + Codex work:
live waits now expire as "still active" instead of implying failure, handoffs
carry a derived state (
pending,expired_live_wait,handoff_still_active, ormatched), and late replies reconcile by handoff id throughwait_for_messages,wait_for_claude, andread_context. - Connection and recovery status are more truthful: doctor and status expose the instance, state directory, and ports they reflect; resolution-mismatch warnings call out same-project daemons on different port groups; and disabled-bridge recovery is identity-aware with daemon-token re-read after relaunch.
- ContextRelay now writes an advisory CoordinationCheckpoint from derived ledger, policy, runtime, and git state, then reads it fail-closed on startup so stale or dirty worktrees are summarized as advisory instead of auto-resumed.
- The native TUI shows the ContextRelay version in the header and the current instance id in the Status panel, alongside clearer kill scope and deferred dev-bundle restart messaging.
- v2.0.0 remains the streamlined major release baseline: a focused Claude Code + Codex coordination core with a state-scoped session registry, archived-session reactivation, plugin-status diagnostics, hardened CLI passthrough, watchdog stability, occupied-port preservation, managed-Codex descendant reaping, and guarded stale app-server cleanup.
ctxrelay codex-mcp install|remove|status|servermanages Codex MCP registration explicitly.- Codex has typed MCP tools for live messages, handoffs, context reads, notes, artifacts, backup requests, status, and finality.
ctxrelay coordinator claude|codex|humanrewrites coordinator policy in config and managed instruction blocks.AGENTS.mdandCLAUDE.mdmanaged blocks are audience-specific: Codex files describe Codex tools and fallback markers; Claude files describe Claude plugin tools.- Claude-to-Codex messages sent while Codex is busy are queued instead of failing immediately.
ctxrelay statusreuses the live daemon port group recorded in local state even when public health omits private daemon details.- v1.1.4 ships explicit first-use named runtime sessions behind
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1:ctxrelay codex --session <id>orctxrelay claude --session <id>can create a named pair inside the same daemon. - v1.1.4 shows each named session's operation path in status, session list, and the native TUI, and documents the Claude-first and Codex-first launch flows.
- v1.1.3 added opt-in hook compaction controls through
ctxrelay hook-compactionand the TUIToken modetoggle;verboseremains the default and preserves legacy hook output. - Named sessions remember their folder of operation, show that path in runtime status, can be archived, rebound, stopped with
ctxrelay kill --session <id>, guarded against launching two named Codex runtimes on the same bound folder, and keep runtime identity across Codex MCP relay paths and bridge recovery. - Named runtime sessions isolate live Claude/Codex routing when opted in, but transcript ledger, viewer, backup, and finality state remain mostly global/default-biased until the next architecture line.
The sections below keep the full command, tool, state, and environment surface searchable from the README.
All ContextRelay tool calls exposed by the current codebase are listed here.
Claude receives these tools from the ContextRelay Claude Code plugin.
| Tool | Purpose | Inputs |
|---|---|---|
reply |
Send a message to Codex as a new Codex turn. | text required; optional chat_id, require_reply, handles_handoff_id, runtimeSessionId |
get_messages |
Drain queued Codex messages in pull/fallback mode. | none |
wait_for_messages |
Long-poll for Codex messages, then return the same payload as get_messages. |
optional timeout_s, handoff_id; timeout clamped to 1..60 seconds |
handoff |
Record a structured handoff to Codex and deliver it live. | reason, ask required; optional context_refs, handles_handoff_id, timeout_policy, runtimeSessionId |
deliberate_with_codex |
Run one bounded Claude-to-Codex deliberation and return Codex's reply for synthesis. | question required; optional opening_position, context_refs, handles_handoff_id, timeout_s, timeout_policy, runtimeSessionId |
append_note |
Add a durable Claude note to the shared ledger. | text required; optional handles_handoff_id, runtimeSessionId |
read_context |
Read recent ledger entries and latest active handoff for Claude. | optional limit, handoff_id; limit clamped to 1..200 |
session_info |
Return session summary, runtime session inspection, ledger counts, active handoff, autonomy, finality, and backup state. | none |
create_session |
Create a registry-backed runtime session. Metadata only; runtime routing is unchanged. | id required; optional label, worktreePath |
select_session |
Select the registry-active runtime session for inspection. Runtime routing is unchanged. | id required |
archive_session |
Archive a registry-backed runtime session. Metadata only; launched runtimes must be exited first. | id required |
rebind_session |
Rebind a registry-backed runtime session to an existing worktree path. Metadata only; launched runtimes must be exited first. | id required; optional worktreePath |
task_state |
Return task lanes, policy state, artifacts, and finality blockers. | none |
record_artifact |
Store a structured patch, test, command, release-gate, or escalation artifact. | kind, title, summary required; optional status, evidence, runtimeSessionId |
ask_codex_backup |
Ask a read-only headless Codex backup agent for analysis. Requires autonomy enabled. | ask required; optional reason, context_refs, runtimeSessionId |
backup_status |
Return current backup-agent state and latest backup metadata. | none |
propose_final |
Record a finality proposal, or an auto-final decision when enabled and unblocked. | summary, evidence required; optional remaining_risk, handles_handoff_id, runtimeSessionId |
Codex receives these tools after:
ctxrelay codex-mcp install| Tool | Purpose | Inputs |
|---|---|---|
send_to_claude |
Send a live message to Claude and record it in the ledger. | text required; optional handles_handoff_id |
handoff_to_claude |
Record a structured handoff to Claude and deliver it live. | reason, ask required; optional context_refs, handles_handoff_id, wait_for_reply, timeout_seconds, poll_interval_ms, timeout_policy, runtimeSessionId |
deliberate_with_claude |
Run one bounded Codex-to-Claude deliberation and return Claude's reply for synthesis. | question required; optional opening_position, context_refs, handles_handoff_id, timeout_seconds, poll_interval_ms, timeout_policy, runtimeSessionId |
read_context |
Read recent ledger entries and latest active handoff for Codex. | optional limit, handoff_id; limit clamped to 1..200 |
wait_for_claude |
Wait for a Claude ledger reply, optionally scoped to a handoff. | optional handoff_id, after_entry_id, timeout_seconds, poll_interval_ms, limit |
append_note |
Add a durable Codex note to the shared ledger. | text required; optional handles_handoff_id, runtimeSessionId |
session_info |
Return session summary, runtime session inspection, active handoff, and ledger counts. | none |
create_session |
Create a registry-backed runtime session. Metadata only; runtime routing is unchanged. | id required; optional label, worktreePath |
select_session |
Select the registry-active runtime session for inspection. Runtime routing is unchanged. | id required |
archive_session |
Archive a registry-backed runtime session. Metadata only; launched runtimes must be exited first. | id required |
rebind_session |
Rebind a registry-backed runtime session to an existing worktree path. Metadata only; launched runtimes must be exited first. | id required; optional worktreePath |
task_state |
Return task lanes, policy state, artifacts, and finality blockers. | none |
record_artifact |
Store a structured patch, test, command, release-gate, or escalation artifact. | kind, title, summary required; optional status, evidence, runtimeSessionId |
ask_claude_backup |
Ask a read-only headless Claude backup agent for analysis. Requires autonomy enabled. | ask required; optional reason, context_refs, handles_handoff_id, runtimeSessionId |
backup_status |
Return current backup-agent state and latest backup metadata. | none |
propose_final |
Record a Codex finality proposal. | summary, evidence required; optional remaining_risk, handles_handoff_id, runtimeSessionId |
For validation handoffs, use handoff_to_claude with wait_for_reply: true; the tool waits for Claude to post a handled ledger reply before returning or timing out.
For deliberation, use deliberate_with_codex, deliberate_with_claude, or Claude's /contextrelay:deliberate <question> shortcut. Deliberation is intentionally bounded: one structured request, one peer response, then the calling agent synthesizes current consensus, remaining disagreement, and the next action. It is a coordination aid, not an automatic correctness guarantee.
When autonomy is enabled, ContextRelay's generated instructions tell Claude and Codex to ask each other for a bounded deliberation before asking the human about answerable planning, design, risk, or next-step questions. They still ask the human for authority, credentials, external business judgment, spending, destructive actions, and coordinator or git-policy changes.
Artifact kinds:
patch_summary
release_gate
test_report
command_log
escalation_suggestion
Artifact statuses:
passed
failed
blocked
unknown
ContextRelay also ships Claude Code slash commands. They are wrappers around the MCP tools above.
| Command | Purpose |
|---|---|
/contextrelay:init |
Create or update project-local .contextrelay/config.json and .contextrelay/collaboration.md. |
/contextrelay:status |
Show session, connection, ledger, handoff, autonomy, finality, and backup state. |
/contextrelay:handoff <task> |
Ask Codex to take the next concrete task. |
/contextrelay:review <focus> |
Ask Codex for a focused read-only review. |
/contextrelay:deliberate <question> |
Run one bounded Claude-Codex deliberation and synthesize consensus, disagreement, and next action. |
/contextrelay:finalize |
Prepare a finality proposal from current ledger evidence. |
When Codex MCP tools are unavailable, Codex can still use exact marker commands at the start of a message:
[IMPORTANT] CONTEXTRELAY_READ_CONTEXT: <optional focus>
[IMPORTANT] CONTEXTRELAY_TASK_STATE
[IMPORTANT] CONTEXTRELAY_NOTE: <note>
[IMPORTANT] CONTEXTRELAY_ARTIFACT:
kind: patch_summary|release_gate|test_report|command_log|escalation_suggestion
title: <short title>
summary: <what happened>
status: passed|failed|blocked|unknown
evidence:
- <optional evidence>
[IMPORTANT] CONTEXTRELAY_HANDOFF_TO_CLAUDE: <ask>
[IMPORTANT] CONTEXTRELAY_PROPOSE_FINAL:
summary: <what is complete>
evidence: <why it is complete>
remaining_risk: <optional risk>
handles_handoff_id: <optional handoff id or comma-separated ids>
[IMPORTANT] DONE: <summary>
Codex messages should put routing markers at the very start of the message. Use [IMPORTANT] for decisions, reviews, completions, and blockers; [STATUS] for progress updates; and [FYI] for background context. In filtered mode, [FYI] messages are dropped, [STATUS] messages may be buffered during busy turns, and [IMPORTANT] messages are forwarded.
Read-only backup triggers are explicit and separate:
[IMPORTANT] ASK_CLAUDE_BACKUP: <read-only help request>
[IMPORTANT] ASK_CODEX_BACKUP: <read-only help request>
Backup triggers only run when autonomy is enabled.
Use contextrelay, context-relay, or ctxrelay; all point to the same CLI.
| Command | Purpose |
|---|---|
contextrelay |
Open the full-screen native ContextRelay TUI with no subcommand. |
ctxrelay tui [--no-start] [--force] |
Open the full-screen native terminal dashboard. --force renders even when stdin is not detected as an interactive TTY. |
| `ctxrelay init [--instructions project | global |
ctxrelay dev |
Register the local plugin marketplace and sync the local plugin for development. |
ctxrelay claude [--session <id>] [args...] |
Start Claude Code with the ContextRelay plugin channel enabled. Explicit named sessions require CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1; a missing session is created and bound to the current folder on first use. |
ctxrelay codex [--session <id>] [args...] |
Start Codex TUI connected to the ContextRelay daemon and proxy. Explicit named sessions require CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1; a missing session is created and bound to the current folder on first use. |
| `ctxrelay codex-mcp install | remove |
ctxrelay pair [--dry-run] [--no-tui] [--port-base <port>] |
Start Claude and Codex in separate terminal sessions, then keep the ContextRelay control TUI open. Use --no-tui when launching from an existing dashboard. |
ctxrelay doctor [--no-auth] |
Diagnose binaries, auth, state, plugin registration, daemon health, tokens, and stale locks. |
| `ctxrelay instructions status | install |
| `ctxrelay coordinator [status | claude |
| `ctxrelay permissions status | readonly on |
ctxrelay detach-claude |
Clear the active Claude foreground connection without killing Codex or the daemon. |
ctxrelay status [--json] |
Print daemon, session, connection, ledger, task, autonomy, finality, and backup state. |
ctxrelay session list [--archived] | create <id> [--label <text>] [--worktree <path>] | select <id> | archive <id> | rebind <id> [--worktree <path>] [--json] |
List, create, select, archive, and rebind registry-backed runtime sessions. session create and session rebind bind named sessions to the current worktree by default; use --worktree <path> to bind a different checkout. |
ctxrelay recover [--json] |
Summarize crash recovery context, recent failures, interrupted commands, git status, and a resume prompt. |
ctxrelay instances |
List known project instances and assigned ports. |
ctxrelay viewer [--no-open] |
Open the local Command Deck for status, task lanes, artifacts, policy, and timeline. |
| `ctxrelay autonomy on | off |
| `ctxrelay finalize auto | manual |
| `ctxrelay hook-compaction status | verbose |
ctxrelay release-gate [--json] |
Run build/check release readiness and record a release_gate artifact. |
| `ctxrelay kill [--all | --session ]` |
The native TUI uses the full terminal window and keeps the common control-plane actions in one place. The top header shows the ContextRelay version and bridge readiness. The Status panel shows transcript id, daemon pid, instance id, port group, ledger count, queue depth, same-project peer count, and any resolution warning surfaced by daemon status. The Runtime Sessions panel lists named runtime sessions when present. The Agents panel shows Claude and Codex connection state and role. The Controls panel shows coordinator, autonomy, finality, readonly policy state, and token mode. The Activity panel shows current handoff state, agent attachment state, the active handoff's derived state when available, and a width-aware capped strip of recent redacted handoffs and blocked or failed runtime events. The live status bar above the footer summarizes readiness, uptime, relay state, agent state, and the latest activity. The footer lists hotkeys as (r)efresh, (p)air, (v)iewer, (a)uto, (f)inal, (c)oord, (x)readonly, (t)token, and (q)uit.
Use p to launch the Claude + Codex pair, v to open the browser Command Deck, a to toggle autonomy, f to toggle auto-finality, c to cycle the coordinator, x to toggle readonly permission mode, and t to switch token mode between verbose and compact. Use v or ctxrelay viewer for the full timeline.
Hook compaction controls the pending-message context injected by the Claude UserPromptSubmit hook. The default token mode is verbose, which preserves the existing five-preview hook output. compact is opt-in and uses one preview, 200 preview characters, and a 60-second dedupe window for identical rendered hook output. Advanced users can keep a mode preset but override individual values:
ctxrelay hook-compaction status
ctxrelay hook-compaction compact
ctxrelay hook-compaction set --preview-limit 2 --preview-chars 240 --dedupe-seconds 45
ctxrelay hook-compaction verboseThe config shape is turnCoordination.hookCompaction = { mode, previewLimit, previewChars, dedupeSeconds } in .contextrelay/config.json. Precedence is environment variable, explicit config field, mode preset, then built-in default.
contextrelay and ctxrelay tui require an interactive terminal and start the project daemon unless --no-start is passed. Use ctxrelay status --json for scripts and CI. Use ctxrelay tui --force only when you intentionally want to render despite TTY detection.
By default, ContextRelay starts one Claude + Codex pair per project instance. If a pair is already active, p and ctxrelay pair skip the duplicate launch and record a pair-launch runtime event in the ledger.
The coordinator owns planning, task routing, and git-write responsibility. Default:
{
"collaboration": {
"coordinator": "claude",
"gitWrites": "coordinator"
}
}Allowed coordinators:
claude: Claude coordinates planning and git; Codex handles delegated implementation, debugging, tests, and review.codex: Codex coordinates planning and git when runtime permissions allow it and the human has approved that repo policy; Claude supports review, risk analysis, and delegated tasks.human: the human coordinates and owns git; both agents execute delegated work and ask before git writes.
Change it manually:
ctxrelay coordinator status
ctxrelay coordinator claude
ctxrelay coordinator codex
ctxrelay coordinator humanRestart active Claude/Codex sessions after changing coordinator so startup instructions refresh.
ContextRelay models mediated actions as:
read | write | shell | network | git | secrets | browser | external_api
The policy lives in .contextrelay/config.json. It applies to actions ContextRelay mediates directly; provider-native Claude Code and Codex approvals still run inside those tools. The external_api capability is reserved for future API-backed workers.
Add --agent <agentId> to apply readonly, allow, deny, or reset to one agent override instead of the global policy.
ctxrelay permissions status
ctxrelay permissions readonly on
ctxrelay permissions deny external_api
ctxrelay permissions allow external_api --agent reviewer
ctxrelay permissions resetPermission decisions are recorded as runtime events in the shared ledger when mediated commands run.
- Loopback-only daemon endpoints.
- Local auth tokens for control APIs and viewer bootstrap.
- Authenticated daemon status includes
instanceId,projectRoot,stateDir, andcontrolPort; clients refuse to reuse a daemon when those fields do not match the current project. - Browser origin rejection.
- Codex proxy auth passed through environment, not in the
--remoteURL. - Autonomy off by default.
- Auto-finality off by default.
- Backup agents are read-only.
- Git writes should be performed only by the coordinator or the human.
- Agents share ledger entries and messages, not hidden reasoning.
Project-local state:
.contextrelay/
├── config.json
├── sessions.json
├── state/
│ ├── daemon.pid
│ ├── daemon-identity
│ ├── codex-tui.pid
│ ├── codex-tui.json
│ ├── codex-app-server.pid
│ ├── daemon.lock
│ ├── status.json
│ ├── ports.json
│ ├── contextrelay.log
│ ├── killed
│ ├── token
│ ├── proxy-token
│ ├── viewer-token
│ ├── queue.db
│ ├── transcript.jsonl
│ └── runtime-sessions/
│ └── <runtimeSessionId>/
│ ├── codex-tui.pid
│ └── codex-tui.json
├── current
└── sessions/
└── <sessionId>.jsonl
Global instance registry on macOS:
~/Library/Application Support/ContextRelay/instances.json
Default first port group:
4500 Codex app-server
4501 ContextRelay Codex proxy
4502 ContextRelay daemon control
Additional projects increment by 10: 4510/4511/4512, 4520/4521/4522, and so on. Use ctxrelay pair --port-base 4700 to request a specific group.
Most users do not need to set these. The CLI exports project instance values automatically.
| 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 Codex TUI. |
CONTEXTRELAY_CONTROL_PORT |
auto group start 4502 |
Control port between plugin/frontend and 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 state-dir defaults. Project CLI launches normally pass CONTEXTRELAY_STATE_DIR explicitly. |
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_ALLOW_NAMED_SESSIONS |
unset | Set to 1 to enable opt-in named Codex runtime launch and non-default live routing. Session registry metadata is visible without this flag. |
CONTEXTRELAY_NAMED_CODEX_RUNTIME_START_ATTEMPTS |
3 |
Maximum daemon-side launch attempts when allocating concrete ports for a named Codex runtime. |
CONTEXTRELAY_MODE |
push via ctxrelay claude, auto otherwise |
Message delivery mode: push, pull, or auto. |
CONTEXTRELAY_RUNTIME_SESSION_ID |
unset | Runtime session attached by ctxrelay claude --session <id>; replies default to this session when live multi-session is enabled. |
CONTEXTRELAY_FILTER_MODE |
filtered |
Message-routing filter mode. Set to full to send full routing payloads. |
CONTEXTRELAY_PAIR_BIN |
contextrelay |
CLI binary used by ctxrelay pair. Useful for local dist/cli.js testing. |
CONTEXTRELAY_CLAUDE_DEVELOPMENT_CHANNELS |
1 |
Set to 0 to use Claude's approved --channels path instead of development channel loading. |
CONTEXTRELAY_MAX_BUFFERED_MESSAGES |
100 |
Maximum undrained Claude-bound Codex messages kept per chat. |
CONTEXTRELAY_MCP_TOOLS |
unset | Optional comma/space-separated MCP tool allowlist. Unset or * exposes all tools. |
CONTEXTRELAY_IDLE_SHUTDOWN_MS |
30000 |
Idle daemon shutdown window. |
CONTEXTRELAY_ATTENTION_WINDOW_MS |
15000 |
Coordination window used while waiting for Codex turn settling. |
CONTEXTRELAY_CLAUDE_PROBE_TIMEOUT_MS |
3000 |
Liveness probe timeout before evicting a stale Claude frontend. Set 0 to disable probe eviction. |
CONTEXTRELAY_CLAUDE_RESPONSE_TIMEOUT_MS |
300000 |
Timeout before a Claude-owned active task lane is marked stale. |
CONTEXTRELAY_CODEX_TURN_IDLE_TIMEOUT_MS |
300000 |
Codex silence window before a stuck turn is force-cleared. |
CONTEXTRELAY_TURN_MAX_MS |
300000 |
Wall-clock budget for one Codex turn. Set 0 to disable. |
TUI_DISCONNECT_GRACE_MS |
2500 |
Grace period after Codex TUI disconnect before treating it as gone. |
CONTEXTRELAY_MAX_DEPTH |
3 |
Maximum relay recursion depth. |
CONTEXTRELAY_BACKUP_THROTTLE_MS |
60000 |
Minimum delay between backup starts for the same target. |
CONTEXTRELAY_BACKUP_KILL_GRACE_MS |
2000 |
Grace between backup timeout SIGTERM and SIGKILL. |
CONTEXTRELAY_DAEMON_SHUTDOWN_STEP_TIMEOUT_MS |
4000 |
Per-step daemon shutdown cleanup deadline. |
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_DAEMON_ENTRY |
bundled daemon | Plugin daemon entry override. Requires CONTEXTRELAY_ALLOW_DAEMON_ENTRY_OVERRIDE=1. |
CONTEXTRELAY_ALLOW_DAEMON_ENTRY_OVERRIDE |
unset | Set to 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 to 1 to force the compact UserPromptSubmit hook preset for automation. |
CONTEXTRELAY_HOOK_PREVIEW_LIMIT |
mode preset | Override pending-message preview count for the UserPromptSubmit hook. Range: 1-20. |
CONTEXTRELAY_HOOK_PREVIEW_CHARS |
mode preset | Override pending-message preview character cap for the UserPromptSubmit hook. Range: 40-4000. |
CONTEXTRELAY_HOOK_DEDUPE_SECONDS |
mode preset | Override identical hook-output suppression window. Set 0 to disable dedupe. |
CONTEXTRELAY_AUTO_REGISTER |
unset | Set to 1 during npm install/postinstall to opt into automatic Claude plugin registration. |
CONTEXTRELAY_AUTO_UNREGISTER |
unset | Set to 1 during uninstall/preuninstall to remove Claude plugin registration. |
CONTEXTRELAY_POSTINSTALL_DRY_RUN |
unset | Set to 1 to print postinstall/preuninstall actions without changing plugin registration. |
CONTEXTRELAY_POSTINSTALL_STRICT |
unset | Set to 1 to make optional postinstall registration failures exit non-zero. Useful for CI install verification. |
CONTEXTRELAY_CODEX_PROXY_TOKEN |
generated | Internal Codex remote-auth token. The CLI sets it for Codex. |
CONTEXTRELAY_CODEX_APP_SERVER_TRANSPORT |
auto | Internal Codex app-server transport override. Used for compatibility testing and diagnostics. |
Manual port override rule: set all three port variables (CODEX_WS_PORT, CODEX_PROXY_PORT, CONTEXTRELAY_CONTROL_PORT) or set none. Partial overrides are rejected.
Claude Code supplies CLAUDE_PLUGIN_ROOT for bundled hook script paths and may supply CLAUDE_PROJECT_DIR for project scoping. ContextRelay's health-check hook falls back to PWD when CLAUDE_PROJECT_DIR is unset.
Test harnesses use CONTEXTRELAY_FAKE_DAEMON_LAUNCH_LOG, CONTEXTRELAY_FAKE_DAEMON_DELAY_MS, CONTEXTRELAY_SHIM_LOG_DIR, and CONTEXTRELAY_CODEX_SHIM_HOLD_MS internally. They are not runtime configuration knobs.
ctxrelay viewer opens the Command Deck, a token-authenticated local browser view for the current project instance. It shows connection health, agent idle/busy/stale/offline state, task lanes, artifacts, policy, and a latest-first timeline. It cannot send messages, approve work, or mutate git state, but it can clear the current shared session history through its authenticated history endpoint.
Authenticated local endpoints:
/viewer
/api/viewer/status
/api/viewer/context
/api/viewer/history
/api/viewer/events
/metrics
Scrape metrics:
TOKEN=$(cat "$(ctxrelay status --json | jq -r .stateDir)/token")
PORT=$(ctxrelay status --json | jq -r .controlPort)
curl -H "Authorization: Bearer $TOKEN" "http://127.0.0.1:$PORT/metrics"The examples/ directory contains small projects for local smoke tests:
examples/pair-counter/: minimal HTML/JS counter.examples/shopping-basket/: browser shopping basket with pure ESM state and Bun tests.
Run the basket tests:
bun test ./examples/shopping-basket/basket.test.jsRun either UI with a static file server:
python3 -m http.server --bind 127.0.0.1 8765 --directory examples/pair-counter
python3 -m http.server --bind 127.0.0.1 8765 --directory examples/shopping-basketIf the npm install hook fails in a sandboxed shell, air-gapped CI runner, or container without Claude Code on the PATH, run the postinstall script in dry-run mode:
CONTEXTRELAY_POSTINSTALL_DRY_RUN=1 node node_modules/@proofofwork-agency/contextrelay/scripts/postinstall.cjs
CONTEXTRELAY_POSTINSTALL_DRY_RUN=1 CONTEXTRELAY_AUTO_REGISTER=1 node node_modules/@proofofwork-agency/contextrelay/scripts/postinstall.cjs
CONTEXTRELAY_POSTINSTALL_DRY_RUN=1 CONTEXTRELAY_AUTO_UNREGISTER=1 node node_modules/@proofofwork-agency/contextrelay/scripts/preuninstall.cjsCommon checks:
ctxrelay doctor
ctxrelay status
ctxrelay instances
ctxrelay detach-claude
ctxrelay kill
ctxrelay kill --session <id>Run the full local check:
bun run checkRun focused tests:
bun test src/unit-test/instructions.test.ts src/e2e-cli.test.tsBuild bundles:
bun run build:cli
bun run build:pluginAfter changing plugin code:
ctxrelay dev
/reload-pluginsBefore release:
ctxrelay release-gate --jsonrelease-gate first runs the full check against existing artifacts so stale bundles fail before any rebuild can hide them. It then rebuilds the CLI and plugin bundles, reruns the full check, generates build metadata, runs the npm package smoke (bun run verify:package), and records a release_gate artifact in the shared ledger.
- ContextRelay depends on Claude Code plugin/channel behavior and Codex app-server behavior.
- One default Codex TUI and one default Claude foreground connection are expected per project instance unless named sessions are explicitly enabled.
- Named sessions are opt-in runtime pairs, not separate transcript ledgers or multi-agent orchestration.
- Backup agents are read-only and intended for analysis, not implementation.
- ContextRelay is local developer tooling, not a security boundary between tools you do not trust.
- Git writes should be handled only by the configured coordinator or the human.
MIT. See LICENSE. ContextRelay preserves the original AgentBridge MIT copyright notice and adds the ProofOfWork / Danillo Felix copyright notice for this fork's changes.
ContextRelay is forked from raysonmeng/agent-bridge. AgentBridge demonstrated that Claude Code and Codex could communicate through the tool they were building together. ContextRelay keeps that foundation and adds shared context, explicit handoffs, backup agents, finality controls, setup diagnostics, and project-owned packaging.