@proofofwork-agency/contextrelay
v3.3.0
Published
ContextRelay: local multi-agent coding orchestration for Claude Code and Codex
Maintainers
Readme
ContextRelay
Run Claude Code and Codex as one auditable local coding team.
ContextRelay wires Claude Code and Codex into one repository through a loopback daemon, so they exchange live messages, hand off work, and debate decisions — with every message, handoff, note, and decision written to a shared, auditable ledger. You get a pair that reviews its own work, second opinions on risky calls, and a durable record of what the agents did before you ship.
Unlike single-vendor orchestration, ContextRelay is the provider-neutral
control-plane that coordinates two different products — Claude Code and Codex
— under one git owner, one human-in-the-loop policy, and one shared record. It
adds a native terminal control deck, a browser viewer, structured handoffs,
bounded deliberation, release evidence, named runtime pairs, opt-in read-only
autonomy, and — new in 3.0 — contained, default-off act:write.
Use it when one agent should implement while the other reviews, when a risky decision needs a second opinion, or when you want an auditable record of what the agents did before you ship.
ContextRelay is local developer tooling. It is not a hosted service, not endorsed by OpenAI or Anthropic, and not a security sandbox between tools you do not trust.
📖 Read the full documentation → — concepts & principles, getting started, tutorials, best practices, and the complete CLI, MCP-tools, config, and environment reference.
What You Get
| Capability | What it does |
| --- | --- |
| Claude + Codex pair | Starts both tools around the same project daemon so they can exchange live messages without copy-paste. |
| Shared ledger | Records messages, handoffs, notes, artifacts, test reports, runtime events, release gates, and finality proposals. |
| Native TUI | Shows daemon health, agents, runtime sessions, queue state, handoffs, scanner mode, autonomy, finality, and launch controls; press h/H for in-dashboard help. |
| Browser Command Deck | Opens a token-authenticated local viewer for task lanes, artifacts, policy, status, and timeline inspection. |
| Structured collaboration | Provides MCP tools, Claude slash commands, Codex MCP tools, fallback markers, and bounded deliberation flows. |
| Default noise reduction | Collapses Codex progress chatter into one digest per turn and keeps routine turn pings out of Claude's context; decisions, handoffs, @claude, and [IMPORTANT] still arrive live, [HUMAN] stays human-only, and the behavior is reversible via CONTEXTRELAY_* env/config. |
| Named runtime sessions | Lets one project daemon host explicit extra Claude+Codex pairs for review or debugging lanes. |
| Read-only autonomy | The idle scanner can suggest, ask, or dispatch bounded read-only workers when autonomy is enabled. |
| Contained act:write (3.0, opt-in) | Optional autonomous edits run only inside an ephemeral git worktree; ContextRelay captures the diff and never commits, merges, or pushes. Default-off behind a hard env switch, per-task budgets, allowlists, and dual-idle + containment gates that all must pass. |
| Release evidence | ctxrelay release-gate records build, package, and optional smoke evidence as a durable artifact. |
ContextRelay and Claude Code Workflows
Claude Code's native Workflows orchestrate Claude sub-agents within one Claude session — parallel fan-out, typed returns, git-worktree isolation, budgets, resume. ContextRelay solves a different problem: coordinating two separate products — Claude Code and Codex — as one team, with a durable cross-agent ledger, coordinator-owned git policy, human-in-the-loop control, and contained act:write.
They are complementary, not competing. ContextRelay is the provider-neutral
governance, audit, and coordination control-plane around native Workflows + Codex
— not a replacement for them and not "a better Workflow." Reach for a Workflow to fan
out Claude sub-agents on one task; reach for ContextRelay when Claude and Codex should
collaborate with a shared auditable record and a single git owner. Two modes are
intended for that coexistence: bypass — a repo drives Workflows directly and
ContextRelay is not the git owner for that run and
governed — a Workflow records to the ledger and hands git/release to the coordinator
(the planned integration, tracked in agent-roadmap.md). ContextRelay does not try to
block bypass.
Install
Prerequisites
| 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 daemon and Claude plugin server run on Bun.
First Setup
npm install -g @proofofwork-agency/contextrelay
ctxrelay init --instructions project
ctxrelay codex-mcp install
contextrelaycontextrelay, ctxrelay, and context-relay are the same CLI.
The setup commands:
- create
.contextrelay/config.json; - install the Claude Code plugin;
- write managed ContextRelay guidance into
AGENTS.mdandCLAUDE.md; - register the ContextRelay MCP server with Codex;
- open the native terminal dashboard.
Check the installation:
ctxrelay doctor
ctxrelay status
ctxrelay instancesStop the current project daemon:
ctxrelay killUse It
Launch the Pair
From the TUI, press p.
From a shell:
ctxrelay pairOr start each side manually:
ctxrelay claude
ctxrelay codexThe default launch creates one Claude foreground connection and one Codex TUI for the current project instance. If that pair is already active, the TUI keeps the current pair and offers a named runtime pair instead.
Ask the Agents to Coordinate
Claude gets ContextRelay MCP tools through the installed Claude Code plugin.
Codex gets ContextRelay MCP tools after ctxrelay codex-mcp install.
That Codex MCP registration is global to Codex, not limited to Codex sessions
launched by ContextRelay. After registration, a normal codex window opened in
this project can load the ContextRelay tools, attach to or start the project
daemon, and communicate with an attached Claude session. Use
ctxrelay codex-mcp remove if you only want Codex to participate when launched
through ctxrelay codex.
Typical agent-level moves:
/contextrelay:handoff review the auth boundary
/contextrelay:deliberate should this be a protocol change or display-only?
/contextrelay:finalizeCodex can use MCP tools such as handoff_to_claude,
deliberate_with_claude, read_context, record_artifact, and
propose_final. Claude has matching tools such as handoff,
deliberate_with_codex, read_context, record_artifact, and
propose_final.
Agents share ledger entries and messages. They do not share hidden reasoning.
Inspect the Work
ctxrelay status
ctxrelay viewer
ctxrelay session list
ctxrelay release-gate --jsonThe viewer is local and token-authenticated. It can inspect status, task lanes, artifacts, policy, and timeline. It cannot send agent messages, approve tool calls, publish, or mutate git state.
Run Named Runtime Pairs
Named sessions are explicit and experimental. They let one daemon host extra Claude+Codex runtime pairs for a review lane, debug lane, or alternate checkout.
From the TUI:
- Press
ponce when the default pair is active. - Read the named-pair prompt.
- Press
pagain within the confirmation window.
From a shell:
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay pair --session reviewOr launch each side:
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay claude --session review
CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1 ctxrelay codex --session reviewNamed sessions isolate live routing for that runtime pair. Transcript ledger, viewer, backup, and finality state are still mostly global/default-biased in this line.
Autonomy
Autonomy is off by default.
The idle scanner itself is deterministic: it reads the ledger and daemon state and only emits concrete opportunities. It is not an LLM loop.
Scanner modes:
| Mode | Behavior |
| --- | --- |
| off | Scanner disabled. |
| suggest | Records a pull-visible idle_opportunity task lane (discovered via task_state). No prompt, worker, or model call. |
| ask | Records the same pull-visible idle_opportunity lane as suggest. No live prompt is pushed — the live-push path was removed in 2.7.0; both agents discover the lane via task_state. |
| act | Records the lane and, with autonomy on, may dispatch bounded read-only worker(s) or a contained act:write worker under strict dual-idle and authorization gates. This can spend tokens. |
Configure it from the TUI with i:
off -> suggest -> ask -> act -> offEntering act requires a second i press. ask and act only become active
when autonomy is on:
ctxrelay autonomy on
ctxrelay idle-scanner actSet CONTEXTRELAY_IDLE_SCANNER=0 to hard-disable the scanner regardless of the
configured mode. The TUI Controls panel shows disabled (env) when this override
is active.
autonomy.idleScanner may also be a structured config object. Legacy string
values such as "act" still load as { "mode": "act" }. The object form keeps
the same modes while allowing debounceMs, dryScanBudget, disabledKinds,
quiescentClaudeStates, and quiescentCodexStates tuning.
Read-only act workers are launched through the same backup-agent substrate:
- Codex worker:
codex exec --sandbox read-only - Claude worker:
claude -p --allowedTools Read,Grep,Glob,LS
They can inspect, analyze, and record artifacts. Read-only workers cannot
intentionally edit files, run git writes, publish, kill daemons, or execute the
suggested work. Contained act:write workers are default-off and require
autonomy.writableAction.mode="act", autonomy on, CONTEXTRELAY_WRITE_MODE_ENABLED,
CONTEXTRELAY_WRITE_DAILY_CAP_USD, positive budgets, matching allowlists, strict
dual-idle quiescence, and containment checks before they can edit inside an
ephemeral worktree.
ContextRelay also sets CONTEXTRELAY_WORKER=1 and isolates Codex worker config
so worker processes do not recursively start ContextRelay inside themselves.
Safety Model
ContextRelay is designed for one trusted operator on one workstation.
Defaults:
- loopback-only daemon and proxy listeners;
- local control, proxy, and viewer tokens;
- browser-origin rejection on privileged control paths;
- project identity checks before daemon reuse;
- autonomy off;
- auto-finality off;
- read-only backup and act workers;
- coordinator-owned git-write policy;
- release and publish actions left to the human.
Non-goals:
- remote collaboration server;
- multi-user RBAC;
- protection from malware or another same-user process;
- OS sandbox for Claude Code, Codex, tests, or shell commands;
- proof that multi-agent deliberation is correct.
Read the full threat model before treating ContextRelay as anything stronger than local developer tooling.
Architecture
Claude Code
-> ContextRelay Claude plugin / MCP stdio
-> ContextRelay daemon
-> Codex app-server proxy
-> Codex TUI
Codex MCP stdio server
-> ContextRelay daemon
Browser viewer
-> loopback HTTP viewer endpointsThe daemon stores project state under .contextrelay/, uses project-scoped port
groups, and writes the shared ledger as JSONL. Claude and Codex communicate
through the daemon's local control plane, not through a hosted service.
ctxrelay codex launches a managed Codex TUI, while ctxrelay codex-mcp
install registers a stdio MCP server that any later Codex session in this
project may load.
Default first port group:
4500 Codex app-server
4501 ContextRelay Codex proxy
4502 ContextRelay daemon controlAdditional projects increment by 10: 4510/4511/4512,
4520/4521/4522, and so on.
Documentation
- Docs index
- Reference
- Operator runbook
- Runtime and adapter architecture
- Session lifecycle
- Threat model
- Roadmap and architecture
Develop From Source
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 pairRun the gate:
bun run checkBefore release:
ctxrelay release-gate --jsonAdd --smoke when a daemon is already running and you want extra
observation-only runtime evidence in the release artifact. Smoke checks are
timeboxed and recorded as passed or skipped; they never make the release
gate fail.
Reference
The complete command, tool, and environment surface is kept in docs/REFERENCE.md. A condensed copy is below so the npm and GitHub front page remains searchable.
Use contextrelay, context-relay, or ctxrelay; all point to the same CLI.
| Command | Purpose |
| --- | --- |
| contextrelay | Open the native ContextRelay TUI. |
| ctxrelay tui [--no-start] [--force] | Open the native terminal dashboard. |
| ctxrelay init [--instructions project|global|both|skip] | Check dependencies, create config, install the Claude plugin, and optionally write instruction blocks. |
| ctxrelay upgrade [--dry-run] [--no-plugin] [--instructions refresh\|project\|global\|both\|skip] | Reconcile an installed ContextRelay to the current package version after npm i -g @proofofwork-agency/contextrelay@latest: migrate config, refresh instruction blocks, update the bare command, and reinstall the plugin. |
| 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. |
| ctxrelay codex [--session <id>] [args...] | Start Codex TUI connected to the ContextRelay daemon and proxy. |
| ctxrelay codex-mcp install|remove|status|server | Manage Codex MCP registration. Installed registration is available to normal codex sessions in this project, not only ctxrelay codex. |
| ctxrelay pair [--dry-run] [--no-tui] [--port-base <port>] [--session <id>] | Start Claude and Codex in separate terminal sessions. |
| ctxrelay doctor [--no-auth] | Diagnose binaries, auth, state, plugin registration, daemon health, tokens, and stale locks. |
| ctxrelay instructions status|install|remove [--scope project|global|both] | Manage ContextRelay blocks in project/global instruction files. |
| ctxrelay coordinator [status|claude|codex|human] [--scope project|global|both] | Set the manual coordinator and rewrite managed instruction blocks. |
| ctxrelay permissions status|readonly on|off|allow <capability>|deny <capability>|reset [--agent <agentId>] | Configure mediated permission policy. |
| ctxrelay detach-claude | Clear the active Claude foreground connection. |
| 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] | Manage registry-backed runtime sessions. |
| ctxrelay recover [--json] | Summarize crash recovery context and recent failures. |
| ctxrelay instances | List known project instances and assigned ports. |
| ctxrelay viewer [--no-open] | Open the local browser Command Deck. |
| ctxrelay autonomy on|off|status | Control whether explicit read-only backup-agent requests may run. |
| ctxrelay idle-scanner off|suggest|ask|act|status | Configure the idle opportunity scanner. |
| ctxrelay idle-budget status|reset | Show resolved read-only idle-action budgets or reset live usage counters with reset --confirm. |
| ctxrelay idle-eval status|compare | Manually plan or run human-approved single-vs-fleet value-probe evaluations with deterministic threshold scoring. |
| ctxrelay write-mode off|suggest|ask|act|status | Configure default-off act:write mode (autonomy.writableAction.mode). Config alone cannot write; hard env, budget, allowlist, idle, and containment gates must pass. |
| ctxrelay finalize auto|manual|status | Control whether finality can be recorded automatically. |
| ctxrelay usage status|off|lean|strict | Configure token/context usage presets across shared-context tool output and Claude hook injection. |
| ctxrelay usage hook status|verbose|compact|count|set | Advanced hook token mode controls. ctxrelay hook-compaction ... remains as a compatibility alias. |
| ctxrelay usage context off|lean|strict|status | Advanced ContextRelay MCP shared-context output controls. ctxrelay usage-control ... remains as a compatibility alias. |
| ctxrelay usage ledger compact [--dry-run|--apply] [--session <id>] [--recent <count>] [--preview-chars <count>] | Deterministically compact old ledger entries into hash-backed summaries. ctxrelay ledger compact ... remains as a compatibility alias. |
| ctxrelay usage ledger clear [--dry-run|--apply] [--session <id>] | Archive the ledger and replace it with a fresh session_started entry. Dry-run is the default. |
| ctxrelay hook-compaction status|verbose|compact|count|set | Compatibility alias for ctxrelay usage hook .... |
| ctxrelay usage-control off|lean|strict|status | Compatibility alias for ctxrelay usage context .... |
| ctxrelay ledger compact [--dry-run|--apply] | Compatibility alias for ctxrelay usage ledger compact .... |
| ctxrelay ledger clear [--dry-run|--apply] | Compatibility alias for ctxrelay usage ledger clear .... |
| ctxrelay messages status\|drain [--dry-run\|--apply] [--chat <id>] [--json] | Inspect or drain pending Codex→Claude messages. Reads the durable bridge queue (queue.db) plus the live daemon's volatile buffer; drain is dry-run by default and marks rows drained without deleting them. Stays read-only while ContextRelay is killed. |
| ctxrelay release-gate [--json] [--smoke] | Run and record release readiness. |
| ctxrelay kill [--all|--session <id>] | Stop this project, every known instance, or one named session's Codex runtime. |
| ctxrelay standalone on|off|status [--scope project|global|both] [--path <file>] | Per-user dormant-by-default control: set the activation flag, slim always-on CLAUDE.md/AGENTS.md copies, and install the bare /contextrelay command. |
| ctxrelay attach [session-name] | Opt the current workspace into ContextRelay in-session (writes the activation marker, prints the ruleset and the peer on-ramp). |
| ctxrelay detach | Opt the current workspace out of ContextRelay (removes the activation marker). |
| ctxrelay gate-check [--status|--json|--why] | Resolve whether ContextRelay is active for this session (exit 0 active / 1 dormant). |
Claude MCP tools:
reply
get_messages
wait_for_messages
handoff
deliberate_with_codex
append_note
read_context
session_info
create_session
select_session
archive_session
rebind_session
task_state
record_artifact
ask_codex_backup
backup_status
propose_finalCodex MCP tools:
send_to_claude
handoff_to_claude
deliberate_with_claude
read_context
wait_for_claude
append_note
session_info
create_session
select_session
archive_session
rebind_session
task_state
record_artifact
ask_claude_backup
backup_status
propose_finalAfter ctxrelay codex-mcp install, these Codex MCP tools may be available in a
plain codex window opened in the project. That window can reach or start the
same project ContextRelay daemon and attached Claude session as a managed
ctxrelay codex launch.
Claude slash commands:
/contextrelay:init
/contextrelay:status
/contextrelay:handoff
/contextrelay:review
/contextrelay:deliberate
/contextrelay:finalize
/contextrelay:on
/contextrelay:offArtifact kinds:
patch_summary
release_gate
test_report
command_log
escalation_suggestion
idle_opportunity
idle_action_result
idle_fleet_result
idle_evaluation_resultArtifact statuses:
passed
failed
blocked
unknown
skipped
timed_outCodex fallback markers:
[IMPORTANT] CONTEXTRELAY_READ_CONTEXT: <optional focus>
[IMPORTANT] CONTEXTRELAY_TASK_STATE
[IMPORTANT] CONTEXTRELAY_NOTE: <note>
[IMPORTANT] CONTEXTRELAY_ARTIFACT:
[IMPORTANT] CONTEXTRELAY_HANDOFF_TO_CLAUDE: <ask>
[IMPORTANT] CONTEXTRELAY_PROPOSE_FINAL:
[IMPORTANT] DONE: <summary>
[HUMAN] <human-directed side note that should not be delivered as Claude-actionable context>
[IMPORTANT] ASK_CLAUDE_BACKUP: <read-only help request>
[IMPORTANT] ASK_CODEX_BACKUP: <read-only help request>Most users do not need to set any of these. The CLI exports project instance
values automatically, and almost everything else lives in
.contextrelay/config.json. These are the core variables you might reach for;
the full tuning table (timeouts, idle scanner, hook, and install knobs) is in
docs/REFERENCE.md and the
environment variables reference.
# Ports, state, and identity
CONTEXTRELAY_STATE_DIR # Runtime state directory.
CONTEXTRELAY_CONTROL_PORT # Control port between the plugin/frontend and the daemon.
CODEX_WS_PORT # Codex app-server WebSocket port.
CODEX_PROXY_PORT # ContextRelay proxy port for the Codex TUI.
CONTEXTRELAY_PORT_BASE # Starting point for automatic port allocation.
CONTEXTRELAY_PROJECT_ROOT # Project root exported by the CLI.
CONTEXTRELAY_INSTANCE_ID # Stable project instance id exported by the CLI.
# Activation and routing
CONTEXTRELAY_AUTO_CONNECT # Highest-precedence activation override (1 = active, 0 = dormant).
CONTEXTRELAY_MODE # Message delivery mode: push, pull, or auto.
CONTEXTRELAY_MCP_TOOLS # Optional comma/space-separated MCP tool allowlist.
CONTEXTRELAY_ALLOW_NAMED_SESSIONS # Set 1 to enable opt-in named runtime sessions.
CONTEXTRELAY_MAX_BUFFERED_MESSAGES # Maximum undrained Claude-bound Codex messages per chat.
# Autonomy gates (off by default)
CONTEXTRELAY_IDLE_SCANNER # Set 0 to hard-disable the idle-opportunity scanner.
CONTEXTRELAY_WRITE_MODE_ENABLED # Hard env kill-switch for act:write; no config can supply it.
CONTEXTRELAY_WRITE_DAILY_CAP_USD # Required per-day USD cap for act:write.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.
ContextRelay also reads the Claude Code host variables CLAUDE_PLUGIN_ROOT and
CLAUDE_PROJECT_DIR (supplied by Claude Code to the bundled hooks). For every
other variable - turn coordination, reliability timeouts, the full idle scanner
and act:write surface, and the npm install/hook knobs - see
docs/REFERENCE.md.
Examples
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.jsTroubleshooting
Common checks:
ctxrelay doctor
ctxrelay status
ctxrelay instances
ctxrelay detach-claude
ctxrelay kill
ctxrelay kill --session <id>If 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.cjsLicense
MIT. See LICENSE. ContextRelay preserves the original AgentBridge MIT copyright notice and adds the ProofOfWork / Danillo Felixdaal copyright notice for this fork's changes.
Credit
ContextRelay was originally forked from AgentBridge, now canonical at
quilin-ai/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.
