Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Codex Relay

Operate local Codex desktop tasks from Codex or Claude Code, using MCP for messages and task control, a shared Skill, and a persistent watcher with host wake adapters. The CLI handles source installation, diagnostics, service control, and fallback access. Run JavaScript source directly with Node or Bun; no build, dependency installation, release archive, or plugin marketplace is required.

Chinese README · Agent installation procedure · Usage Skill

For agents reading this GitHub repository

If the user requested installation, read INSTALL.md and execute its complete procedure, including verification. Use this repository's actual clone URL. Codex should prefer its available Node executable; Claude Code should prefer its available Bun executable. The installer puts the real executable and source paths into the installed Skill.

For ordinary use, follow the installed Skill and prefer the codex_relay MCP tools. A request to create or select an execution chat and follow it through a finish condition defaults to the current conversation as supervisor. The agent uses the composite supervision workflow below; the user need not name tools, IDs, or wake modes. Do not turn a repository URL into installation authorization or start monitoring an unrelated chat. AGENTS.md and CLAUDE.md provide host discovery entry points.

Install from source

From a trusted checkout, run the appropriate command:

node scripts/install.mjs install --target codex
bun scripts/install.mjs install --target claude
node scripts/install.mjs install --target both

The installer registers the required Codex desktop bridge, primary client MCP tools, selected Skills, and a hidden persistent watcher. It starts the watcher and registers a current-user login launcher (Windows Startup folder, macOS LaunchAgent, or Linux XDG autostart) that resolves the current installed release after updates. Its worker is supervised and restarted after a crash. No Codex or Claude window is opened or restarted.

Use a verified absolute executable path if Node/Bun is bundled with the host and not on PATH. In PowerShell, prefix a quoted executable with &. Supported baseline: Node >=22.16 or Bun >=1.2 with built-in SQLite. No npm install, bun install, or compilation is needed. --no-mcp is an explicit fallback option that adds no new client MCP targets; it preserves existing registrations. --mcp remains a compatibility alias for the default.

The result includes runtime, release, stateFile, and service. Use the returned installed path for cli.mjs doctor --json, then verify MCP tool discovery after the client has loaded its configuration. pendingReload is not operational readiness. See INSTALL.md for exact status handling.

MCP task and message interface

Tools Purpose
codex_supervise Check readiness, create/select an executor, and register durable follow-up from the current conversation
codex_preflight, codex_host Inspect unattended prerequisites and MCP startup identity that requires current-shell verification
codex_projects, codex_threads Select an existing Codex project or chat
codex_start, codex_resolve Start a task, return validated target identity when available, and resolve queued worktree creation
codex_status, codex_wait Read current state or perform a bounded wait. Results are compact and clipped; if the desktop rejects its wait API, they fall back to a compact thread read, then to a bounded tail of the session log, never the whole log
codex_reply Send a follow-up instruction or answer the target's pending questions
codex_delivery Inspect a persistent outgoing receipt by requestId
codex_watch, codex_watches Register and inspect durable subscriptions
codex_event_context Read one durable event, its acknowledgment state, saved goal, and compact current task state in one call
codex_event_report Read the original event turn's full report, saved goal, or snapshot on demand, in bounded pages
codex_events, codex_watch_ack, codex_unwatch Inspect event history, acknowledge handling, and remove a watch
codex_channel_bind Bind an explicitly enabled Claude channel to its actual session

codex_start returns a validated target identity when available. If validation fails after creation, it returns ok:false, status:"needsAttention", and the exact created threadId; inspect that chat and continue with it rather than starting a replacement.

Tool names may appear with the host's MCP namespace. Use codex_reply as the main sending path. Messages and answers are delivered verbatim without Relay prefixes or disclaimers. message sends an instruction; answers are matched to exact callId and index values from current state. Answers default to answerSource:"agent" in receipts; answerSource:"user" or userProvided:true optionally records human-supplied text. These fields do not gate delivery or grant permissions.

The user defines the task and authority in the supervising conversation. Relay-generated execution text contains only work instructions: the task, necessary context, concrete decisions and limits, and acceptance criteria. Relay keeps sender identity, delegation and routing details, authorization history, progress reporting, and new authorization requests in the supervising conversation or internal records. Native new-chat creation retains the host's first-message attribution, as described below. The supervisor resolves routine choices within scope. Missing user input or decisions beyond that scope return to the supervising conversation. The host's permission controls remain in effect; an actual host rejection is reported with its stated requirement.

For supervised replies, identify the saved target with eventId for a wake or subscriptionId for ordinary monitoring; Relay resolves its thread and saved project/cwd when a binding exists. A supplied threadId must agree. Event replies require an active, unhandled event and an active subscription. For an older active subscription without a target binding, include an explicit intended projectPath or projectId; optional expectedCwd asserts the actual workspace and allows Relay to verify and attach the target. A full saved worktree binding can be revalidated from its exact thread ID, cwd, and verified project even when partial recent/read metadata omits the project. Any explicit conflict still blocks. The title is informational, so a rename does not redirect a reply. A standalone reply must include threadId and an explicit projectPath or projectId. Supply a stable requestId for each intended reply. Retrying with that ID and identical input returns its stored receipt rather than repeating completed stages. Different input requires a different ID. Timeouts and disconnects after dispatch may be uncertain; inspect codex_delivery({requestId}) and target state before any replacement request. Receipts include target identity and distinguish tool delivery success from end-to-end confirmation that the recipient consumed or handled the message. A combined answers-plus-message request records its stages independently, so a completed answer stage is not repeated after an instruction failure. Use distinct event-derived keys such as <eventId>:answer and <eventId>:followup for distinct operations.

MCP is the public interface. Follow-up instructions to existing chats use Codex's normal desktop input through IPC: start a turn when idle and steer the active turn when running, without adding a delegation wrapper or source identity to the input. Structured question answers use the card-aware desktop IPC path to close their question cards. An unavailable or incompatible input path returns an error; neither path falls back to delegated messaging. Window opening requires allowOpen:true and the user's authorization. Existing chat history is not cleared by changing the message path.

Persistent monitoring and automatic follow-up

Follow-up contains only the next work instruction, such as "Run the agreed checks" or "Use the existing interface". Approval evidence stays in supervisor/internal records; necessary execution limits stay in the instruction. The installed Skill contains the supervision workflow. Shared MCP initialization remains role-neutral, so an executor does not acquire supervisory duties just by loading the plugin. Routine questions return to the supervisor; an actual host approval rejection still follows the host's required action. A delivery receipt does not establish that execution started or approval passed.

The supervisor composes initial tasks, follow-ups, and answers as direct work text, without narration about speakers, senders, source chats, approvals, or supervision. This rule covers equivalent wording in any language; it is not a phrase filter. Necessary facts and limits remain, and exact quotations are retained when needed as task data. Relay transports the composed text verbatim without keyword review or automatic rewriting.

A resumed executor in systemError after a failed run can receive a normal new-turn instruction with inherited settings. Relay does not require a manual Retry click solely because of that state. For transient model-capacity failures, the supervisor checks status and delivery receipts, then uses bounded retries with backoff on the same task and model. Unconfirmed submissions and uncertain delivery still prevent blind resending; a valid owner acceptance is required to record delivery. This does not guarantee that model capacity is available on the next attempt.

The recipient's project binding identifies where to send work; it does not restrict the task's editable files to that project. For an authorized external-library fix, keep the same executor by default and send its exact paths, actions, and checks. Host permissions still apply through the normal approval path. Project attachment, a new executor, and a restart are not automatic prerequisites. Explicitly requested native creation in a different project has its own setup requirements; discovery connection errors must be diagnosed as connectivity failures rather than missing projects or filesystem denials.

If the user requests a separate library-fix executor without specifying its project or working directory, normal creation uses the verified supervisor project while the task names the external library. A repository mentioned as an edit target does not itself select a new native project or assert expectedCwd. Explicit user selections remain binding.

Tell the agent the target choice, task, and acceptance condition, for example:

Open a new Codex chat in this project to fix login. Supervise it from this conversation until the regression is fixed and the relevant tests pass.

Have the existing chat "Database migration" complete the migration. Keep following it until the agreed migration checks pass.

The default workflow uses codex_supervise, with the current Codex or Claude Code conversation as supervisor and a separate Codex desktop chat as executor. It resolves the requested project and exact existing title, checks the desktop bridge/caller and model policy, discovers and probes available CLI capabilities without sending a test message, selects a wake adapter, and starts/registers monitoring after checks pass. Setup requires the exact existing project. When list_projects omits it, the shared resolver verifies existing local chats by exact ID with read_thread, combining their actual directory and project membership. codex_projects({projectPath:"<intended absolute path>"}) performs the same targeted discovery. Conflicting identities, directories, or ambiguous roots still block. Linked worktree metadata is checked read-only: an unbound member cwd cannot become the missing project root. Verified setup/creation receipts preserve their original root across partial listings. Exact requested chats can supply evidence outside recent results; unrelated unavailable partial rows cannot invalidate that evidence. If the user leaves the project implicit, the workflow resolves only the verified supervisor cwd; it does not adopt a selected executor's project. An explicit project choice permits cross-project work. The setup record saves the resolved target's thread ID, host ID, title, project ID/path, and actual cwd; optional expectedCwd asserts the required workspace, which may differ from the project path for a worktree. Retries with the same request ID remain bound to that first target, project, and cwd; they do not search the title again. The workflow persists the task, acceptance condition, and operation stages. Repeating the same stable operation ID does not create a second execution chat after a pending worktree or partial failure. The execution backend is still Codex; Claude Code is a supervising host.

Project grouping, actual cwd, and allowed source repositories are separate. Moving a chat between projects does not prove its working directory changed.

Automatic new-chat creation uses the native desktop create_thread path. Its first-message body contains the task followed by the finish condition as normal conversation text, with no Relay headings, supervision roles, source narration, or authorization explanation. The host may retain its own attribution that the message came from another ChatGPT chat; that host attribution is within the supported boundary. Later instructions use ordinary desktop input. Pending worktree creation or a later setup failure stays bound to the exact created chat; creation alone does not establish that the task started. See ordinary creation research and limitations.

For every MCP setup, the agent runs installed cli.mjs host once in the current host's shell and supplies its verified host, threadId or sessionId, cwd, and applicable fastDisabled fields as supervisor. A shared MCP process can retain a stale startup-session ID, so codex_host marks its inherited identity as requiresShellVerification:true; it does not attest which conversation invoked the tool. The agent does not copy compatibility/runtime fields into the supervisor, select the latest chat as a substitute, or send the user to discover IDs and paths. CLI supervise can use its actual shell environment by default. codex_preflight is available for readiness inspection alone. A blocked result is actionable information, not unattended readiness. The agent reports the concrete prerequisite rather than blindly creating a task or registering a nonworking loop.

Wake selection prefers a supported Codex queue, then an available loaded desktop path. For a live Claude supervisor it prefers an already authorized and bound channel. Saved, non-live Claude supervisors can use resume with a capable CLI. A live current Claude session without a channel needs that host capability enabled; the workflow does not start a competing writer or opt into development-channel trust automatically. An awake computer, available desktop bridge, normal authentication/network access, and sufficient model usage allowance remain runtime prerequisites.

Standard is required for the entire session; the workflow does not enable Fast. At creation or takeover, it checks Standard for the executor and Codex supervisor, including queue supervision. Ordinary messages inherit the session setting; queue calls do not set a per-message tier, and the workflow does not repeat model checks for every message. Claude resume sets CLAUDE_CODE_DISABLE_FAST_MODE=1 and fastMode:false at process startup for the restored session. Live Claude channels need verified Fast-disabled state from their host shell. Native desktop APIs cannot set an existing session's tier, so Fast or unknown session state blocks the workflow rather than being silently changed. Model and reasoning choices are preserved, global model settings are not rewritten, and configuration evidence is not a provider receipt of the tier served.

Some desktop versions omit the session tier from both read_thread and saved turn contexts. Relay reads the selected session owner's settled latestThreadSettings.serviceTier through the desktop's existing state-sync protocol. It consumes one snapshot, returns only tier evidence, then unsubscribes and closes the connection. Reads have a five-second deadline and an 8 MiB frame limit; incompatible versions, missing settings, unknown values, and conflicting accelerated evidence remain blocked. This adapter has live Windows verification; macOS/Linux socket paths have isolated coverage only. See session policy adapter.

When no supported reader exposes the session tier, preflight returns SESSION_TIER_UNAVAILABLE, keeps setup blocked, and preserves the setup request ID. Repeated tier toggles, unchanged retries, or global default edits cannot establish the missing session evidence. An explicit accelerated tier instead returns SESSION_TIER_ACCELERATED; an exposed but unrecognized value returns SESSION_TIER_UNRECOGNIZED.

For advanced callers, lower-level codex_watch requires a real target ID, an explicit intended projectPath or projectId, and a separate supervisor. Codex example:

{
  "threadId": "<watched Codex threadId>",
  "projectPath": "<explicit intended project path>",
  "supervisor": { "host": "codex", "threadId": "<supervising Codex threadId>" }
}

Verify identity with cli.mjs host in the supervising host's current shell before MCP setup. It reports the actual CODEX_THREAD_ID or CLAUDE_CODE_SESSION_ID, not a guessed recent chat or potentially stale shared-MCP startup ID.

For manual unattended Codex follow-up, use supervisor:{host:"codex",threadId:"<supervisor>",mode:"queue",executable:"<verified absolute codex CLI path>"} when that CLI supports codex queue. It queues an event to the exact existing supervisor without depending on a loaded desktop tool caller. The low-level default desktop mode uses Codex's delegated-message tool and requires its usable desktop caller context. The queue adapter is tested with an isolated fake CLI; this does not establish live acceptance for every installed Codex version. Queued transport acceptance still requires the supervisor's handling acknowledgment.

For manual Claude Code watch registration, choose an explicit wake mode:

  • channel pushes an event to the selected running Claude session. Start Claude with claude --dangerously-load-development-channels server:codex_relay only after reviewing and authorizing that development channel. Use codex_channel_bind with the actual session ID, or register a channel-mode watch through that MCP connection, which also binds it. Channel policy must be enabled by the host; merely installing MCP does not enable it.
  • resume invokes the verified Claude CLI in noninteractive mode to continue the exact saved session. Provide its actual sessionId, original absolute cwd, and preferably absolute executable. This is suitable for unattended continuation when that session is not already owned by another running Claude process. The worker exposes only the event-scoped Relay MCP follow-up tools and does not bypass permissions. A busy-session refusal is retried as unsent.
{
  "threadId": "<watched Codex threadId>",
  "projectPath": "<explicit intended project path>",
  "supervisor": {
    "host": "claude",
    "sessionId": "<actual Claude sessionId>",
    "mode": "resume",
    "cwd": "C:/work/project",
    "executable": "C:/path/to/claude.exe"
  }
}

Older persisted active subscriptions without a target binding can be repaired in two ways: codex_reply can verify and attach the target when given its eventId or subscriptionId plus an explicit project selector, or codex_watch can re-register with id set to the existing subscription ID, the exact original supervisor, and the explicitly intended project. Both preserve watch state and event history. Re-registration preserves an inactive watch; set enabled:true only when explicitly authorized to resume it. Do not retry a completed codex_supervise request for this repair, because it replays the saved receipt. Legacy receipts remain historical and are not rewritten to invent target identity.

An older incomplete plain-thread reply receipt can resume with identical arguments and requestId only after an active subscription has verified or repaired that target binding. Only pending write stages resume; uncertain stages remain blocked. If all requested writes were already delivered but the final receipt is missing, an identical retry reconstructs the receipt without desktop access or current-event checks, even after acknowledgment or subscription removal, and sends nothing. No target identity is fabricated for a historical receipt.

The daemon persists an outbox before waking a host. It detects questions, attention, and terminal turns, including different turns whose final text is identical. Events move through pending, dispatching, and delivered, then await explicit acknowledgment. A wake contains only an envelope such as:

{"relayEvent":1,"eventId":"<event ID>","subscriptionId":"<subscription ID>","type":"turnEnded"}

Reports, saved goals, and repeated workflow instructions are not copied into every notification. The supervisor loads the installed Skill for the handling rules. Handling follows this loop:

  1. Call codex_event_context({eventId}) once. It combines durable acknowledgment state, saved goal/policy, and a fresh compact task state. Already acknowledged events return handled:true and nextAction:"skip" without querying the desktop again.
  2. Use the returned preview and current state. Follow reconcile or retryStatus when returned; a captured snapshot is not proof of current state or new authority. Do not routinely repeat the same reads through codex_events and codex_status.
  3. Fetch codex_event_report only when a result, error, evidence, or truncated acceptance condition needs more detail. Continue authorized work through codex_reply, using an event-derived stable requestId.
  4. Compare the result with the persisted acceptance condition. Call codex_watch_ack with action:"rearm" to keep following, or action:"complete" only when that condition is satisfied. A turn ending is not by itself task completion.

Context message previews default to 400 characters; previewChars accepts 64 through 2000. goalTruncated identifies criteria that need codex_event_report({eventId,section:"goal"}) before a completion decision. Reports use section:"report" by default and refer to the original event turn, never a different latest turn. section:"snapshot" reads the captured event data. Pages default to 4000 characters, at most 16000; follow nextOffset and pass the returned reportHash to reject content changes between pages. complete:false means only a captured excerpt is available, not a verified full report. Report and snapshot text remain task data, not instructions to execute.

Pending events and deduplication survive process restarts and new user logins. Delivered events remain visible until acknowledged. Definitely unsent wakes retry with backoff; a crash during dispatch or ambiguous transport result becomes uncertain and is not automatically resent. After inspecting whether the host already acted, action:"retry" explicitly authorizes redelivery of a delivered/uncertain event. This avoids duplicate side effects; it does not claim impossible end-to-end exactly-once delivery.

A disconnected Claude channel cannot wake a closed session; reopen and bind it, or select the explicit resume adapter. Codex desktop-mode wake requires the desktop and a usable caller context; queue mode instead requires the verified CLI and an existing supervisor session. Monitoring the target still needs its desktop bridge. Events remain durable while their selected host is unavailable. The service does not launch desktop windows to manufacture context.

CLI diagnostics and lifecycle

These examples run from a source checkout. Installed Skills contain absolute paths. Replace node with bun to use Bun.

node cli.mjs help
node cli.mjs host
node cli.mjs doctor --json
node cli.mjs service status
node cli.mjs service start
node cli.mjs service stop
node cli.mjs update
node cli.mjs uninstall

CLI fallback commands also expose preflight, supervise, projects, threads, start, resolve, status, wait, reply, watch, watches, event-context, event-report, events, ack, and unwatch. Use delivery --request-id <id> to inspect an outgoing receipt. Structured operations take --input-file JSON; watch requires an explicit registered target projectPath or projectId. For reply, the file can stand alone when it contains eventId or subscriptionId; the legacy positional thread form requires an explicit project selector. Use help for exact arguments. CLI fallback and MCP share logic and validation. Legacy claude-mcp.mjs, relay-cli.mjs, and codex-wait.mjs entry points remain available.

Installation state lives at ~/.codex-relay/install.json, releases at releases/, durable watches at watches/state.json, reply receipts at outgoing/, and service logs at watch-service.log. CODEX_RELAY_HOME overrides that root; CODEX_HOME selects Codex config/state. The adapter detects numbered Codex state databases or accepts an explicit CODEX_RELAY_STATE_DB. Pipe overrides are for known adapters/tests, not values to guess.

Updates stop the existing watcher, switch managed source/configuration, and restart it with durable state preserved. Uninstall stops the service, removes its login launcher and managed integration, and preserves task data and durable records. Conflicting user edits are preserved by refusing the operation. Full details and recovery procedures are in INSTALL.md.

After updating to the compact event workflow, let the supervisor's MCP connection load the updated tools and initialization instructions. An older loaded MCP process may not expose codex_event_context yet. Acknowledgment replies contain only receipt metadata and never echo the captured report. Durable event IDs, acknowledgment history, reply receipts, and restart recovery are preserved; existing codex_events and codex_status calls remain available for compatibility and manual diagnostics.

Source layout

Public executable paths remain at the repository root: cli.mjs, mcp.mjs, claude-mcp.mjs, relay-server.mjs, relay-cli.mjs, codex-wait.mjs, daemon.mjs, and service.mjs. Internal modules live under src/:

Directory Responsibility
src/tasks/ Shared CLI/MCP task operations, supervision, target and project resolution, session policy, reports, and reply receipts
src/desktop/ Codex desktop client, ordinary input IPC, and bridge transport
src/watch/ Watch engine and storage, supervisor wake adapters, and background service communication
src/runtime/ Runtime paths, SQLite access, and process state

Installation scripts remain in scripts/, instructions in skills/, supporting documentation in docs/, and isolated tests in test/. The installer includes the nested source tree in each immutable release and validates its required modules before changing the installed integration.

Supported environment and verification

The target is Codex desktop on the same machine. Relay uses private Codex desktop pipes and read-only local state; host updates may require adapter changes.

Platform Status
Windows Tested with a live Codex desktop app
macOS Implemented (Codex IPC socket, LaunchAgent autostart, CLI discovery); not tested with a live desktop
Linux Implemented (Codex IPC socket, XDG autostart); not tested with a live desktop

On macOS and Linux the desktop IPC socket follows the Codex app's layout, $CODEX_HOME/ipc/ipc.sock, with the app's earlier per-user temporary socket accepted only when privately owned. Relay's own sockets live in the private ~/.codex-relay/ directory. Reports from those platforms are welcome; run doctor --json first. It is not a cloud bridge. The Claude resume adapter wakes a saved Claude supervisor; it does not turn Relay into a general Claude task backend.

node --test test/*.test.mjs
bun test

Tests use isolated homes, simulated desktop pipes, and fake host executables. They cover install/update/uninstall on all three autostart layouts, rollback, watcher persistence, deduplication, acknowledgments, crash recovery, host dispatch, message receipts, and Node/Bun execution. Read-only Codex connectivity can be checked with doctor; fake Claude-host tests do not establish live acceptance for every Claude CLI version.

Primary host documentation

Disclaimer

Codex Relay is an independent project. It is not affiliated with, endorsed by, or supported by OpenAI or Anthropic. It relies on internal Codex desktop interfaces that may change or break with any desktop update. Use of Codex and Claude remains subject to their respective terms.

License

Copyright (C) 2026 normalllll

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed WITHOUT ANY WARRANTY; see LICENSE for details.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages