Skip to content
nicosuavePublic

About

Use your Claude Code subscription inside Codex app & cli

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

Claudex

A Rust facade that exposes the Codex app-server thread/turn protocol over Claude Code's bidirectional claude -p transport. Clients send Codex JSON-RPC messages; Claude does the inference and tool execution.

The implementation targets the generated Codex CLI 0.160.0 schema. The Claude transport was developed against Claude Code 2.1.288 and the official Claude Agent SDK's subprocess/control implementation. No Node or Python bridge is required.

This is a working core implementation, not complete Codex feature parity. Unsupported methods return -32601; unsupported non-null options return -32602. See the feature support matrix below for a summary and COMPATIBILITY.md for the exact surface and behavioral differences.

Feature support matrix

Status: Supported works through the Codex protocol; Partial works with the stated gap; Claude-native is provided by Claude's own runtime rather than the Codex feature; Unsupported is rejected or absent. Details are in COMPATIBILITY.md.

Area Feature Status Notes
Conversation Start, resume, list, archive, rename Supported Facade-owned records plus native Claude transcripts
Conversation Fork, revert, rollback Supported Exact native transcript prefix; files and external effects are not undone
Conversation Steer, queue, interrupt Supported One active turn per thread
Conversation Ephemeral threads Partial One turn only; cannot be forked
Conversation Model and effort selection Supported Claude CLI catalog; low through max
Conversation Context usage, compaction Supported Usage from latest top-level request; compaction is Claude's
Conversation Reasoning summaries Partial Exposed thinking only; concise/detailed lengths not enforced
Conversation Structured output (outputSchema) Supported Final assistant message containing JSON
Conversation Collaboration modes, plan mode Unsupported Default mode only
Conversation Review mode Unsupported
Subagents Claude subagents (Agent tool) Claude-native Run inside the turn; output folded into the parent tool result. No Codex child threads, so the desktop agent tree stays empty
Subagents Background agents and workflows Claude-native Turn stays open until Claude reports idle
Subagents Codex multi-agent (child thread spawn) Unsupported subAgentThreadSpawn lists return no threads
Subagents Guardian/auto approval reviewer Partial Mapped to Claude native auto review, not a Codex reviewer
Tools Shell Supported Bash → commandExecution; output arrives with the result, not streamed
Tools File edits Partial Write/Edit/MultiEdit → fileChange with best-effort diffs; edits made via shell commands produce no file-change item
Tools apply_patch Claude-native Claude edit tools instead
Tools Web search and fetch Claude-native Claude WebSearch/WebFetch as dynamicToolCall; no webSearch item
Tools Image viewing Claude-native Claude Read on image files; no image-view item
Tools Image generation Partial Only through an installed Codex plugin
Tools Plan/todo updates Supported TodoWrite → turn/plan/updated
Tools User questions Supported Single-select → requestUserInput; multi-select → desktop option picker
Tools Other Claude tools Partial dynamicToolCall in namespace claude; generic approval via question fallback
Tools Desktop dynamic tools Supported Reverse item/tool/call through the turn owner
Tools Multimodal tool results Partial Rendered as text; native MCP result metadata dropped
MCP Claude-configured MCP servers Claude-native Shown as mcpToolCall; outside the Bash sandbox
MCP Codex plugin MCP/app tools Supported Executed by genuine Codex; metadata preserved
MCP Interactive elicitation Unsupported Authenticate in Codex settings
Plugins, skills, hooks Codex plugin administration Supported Forwarded to genuine Codex when configured
Plugins, skills, hooks Codex plugin skills Supported Listed with real SKILL.md paths
Plugins, skills, hooks Standalone skills, Claude plugins Claude-native Loaded by Claude; skill input items unsupported
Plugins, skills, hooks Codex hooks Partial Manageable; not executed around Claude turns. Claude hooks run normally
Permissions Workspace-write, full access Supported Claude OS-enforced Bash sandbox and scoped file permissions
Permissions Read-only, external sandbox Unsupported
Permissions Command/file approvals, session grants Supported Session grants match exact tool input and cwd
Permissions never approval policy Partial Maps to dontAsk: denies, does not bypass
Input Text, images Supported Data/HTTP(S) URLs, local PNG/JPEG/GIF/WebP
Input Audio, video, file IDs, mentions, skill items Unsupported
Desktop host Filesystem, command/exec, process/* Supported Privileged; trusted local clients only
Desktop host Attachments, worktrees Partial Metadata stored; desktop Git worker owns checkouts; UI orchestration unverified
Desktop host SSH reconnect Supported Live turn survives; facade restart interrupts it
Account Login, quotas, account management Unsupported Claude's own authentication
Other Realtime voice, remote control, cloud tasks, transcript import Unsupported
Platform macOS / Windows Supported / Unsupported

macOS desktop installation

Install Codex desktop and Claude Code, run claude auth login, and enable System Settings > General > Sharing > Remote Login for your user first.

  1. Install the command-line tool:

    brew install nicosuave/tap/claudex
  2. Set up the desktop connection as your login user, without sudo:

    claudex install

    This copies the binary to a stable per-user location, creates its LaunchAgent and SSH connection, and checks service readiness. It also enables mixed GPT/Claude models for desktop SSH connections from another computer. Reconnect an existing remote connection after installation.

  3. Select claude-codex-local in Codex Settings > Connections.

To use Claude models beside Codex in the desktop's ordinary local window instead, without SSH, see One local window without SSH.

If you need to diagnose a connection problem, run claudex doctor. It checks the setup; it does not install or upgrade anything.

See DESKTOP.md for prerequisites, upgrades, service commands, uninstall behavior, and the precise local trust boundary.

Prebuilt macOS (Apple Silicon/Intel) and Linux (ARM64/x86-64) binaries and SHA-256 checksums are on GitHub Releases. macOS binaries are Developer ID signed and notarized. The desktop installer is macOS-only; Linux can run claudex app-server --stdio.

Upgrade

Wait for active chats to finish. Update the Homebrew binary, then copy that updated binary into the desktop service and restart it:

brew upgrade nicosuave/tap/claudex
claudex install

The second command refreshes an existing installation and preserves conversations and the SSH identity. It is currently required because the service runs its own stable copy of the binary; brew upgrade alone does not update that copy.

Build and run

Requires Rust with edition 2024 support and an installed, authenticated claude executable. Claude uses its normal configured authentication. The facade neither reads credentials nor changes login settings.

mbx build --locked --bin claude-codex-server
./target/debug/claude-codex-server app-server --stdio

Use cargo build if Boxington (mbx) is unavailable. The default model is sonnet; override it with --model opus or a Claude model identifier.

For a client that lets you configure its app-server command, set the executable to the built claude-codex-server binary and arguments to app-server --stdio. For a separate Codex desktop SSH connection, see DESKTOP.md. Desktop transport and startup compatibility are implemented; the actual desktop UI still needs a manual connection test.

Other transports:

./target/debug/claude-codex-server --listen ws://127.0.0.1:4510
./target/debug/claude-codex-server --listen unix:///tmp/claude-codex.sock

WebSockets accept loopback IP bindings only. All browser Origin headers are rejected. unix:// carries WebSockets as Codex desktop expects; the previous newline JSON framing is available as unix-lines:///absolute/path. Unix sockets use mode 0600; only stale sockets owned by the current user may be removed; live sockets, files, and symlinks are retained. All transports are intended for trusted local clients, with no network authentication layer. Logs go to stderr; stdout carries only protocol frames in stdio mode.

Useful options:

Option Purpose
--claude /absolute/path/to/claude Backend executable; also CLAUDE_CODE_EXECUTABLE
--state-dir /absolute/path Facade persistence; also CLAUDE_CODEX_HOME
--model sonnet Default model alias or identifier
--claude-arg=--safe-mode Forward an administrator-selected argument; repeat as needed
--initialize-timeout-seconds 60 Claude control handshake deadline
--approval-timeout-seconds 300 Deny unanswered permission requests after this much connected time
--acp-agent opencode Serve an Agent Client Protocol agent instead of Claude (see below)
--acp-arg=acp Forward an argument to the ACP agent; repeat as needed
--provider-id, --provider-name Model provider reported to Codex for an ACP agent (default: the executable name)
--auto-review-model sonnet Claude model that reviews an ACP agent's permission requests when a thread selects automatic review
--idle-session-timeout-seconds 3600 Keep a thread's Claude process between turns so its prompt cache stays valid; 0 starts a process per turn
--max-idle-sessions 8 Idle Claude processes kept across threads; the oldest closes first

State defaults to ~/.local/state/claude-codex-server (claude-codex-server-<provider-id> for an ACP agent), independently of CODEX_HOME. Only one facade process may use a state directory. The facade stores its own thread/item history there, while Claude retains its own native session transcripts. Both are needed for durable conversation recall. Deleting facade metadata does not delete Claude's transcripts.

Other agents over ACP

The same facade can put any Agent Client Protocol v1 agent behind Codex desktop instead of Claude: OpenCode, Gemini CLI, Goose, Claude Code's ACP adapter, and others. Each agent runs as its own facade with its own threads:

claudex app-server --stdio --acp-agent opencode --acp-arg=acp --provider-name OpenCode
claudex app-server --stdio --acp-agent gemini --acp-arg=--experimental-acp --provider-name Gemini

For the desktop, install one connection per agent. Each gets its own LaunchAgent, state, SSH key and host, claude-codex-<provider-id>, next to the Claude connection:

claudex install --acp-agent opencode --acp-arg=acp --provider-name OpenCode
# then select claude-codex-opencode in Codex Settings > Connections

doctor, service and uninstall take the same --acp-agent/--provider-id flags to select the instance. Sign in with the agent's own CLI first; a turn that needs authentication fails with the sign-in methods the agent advertises.

The agent runs its own tools, so threads use full access and the agent's permission requests become Codex approvals. Models and reasoning effort come from the agent's session config options, and desktop dynamic tools reach the agent as a stdio MCP server. Fork works only at the latest turn and only for agents that support it; rollback, workspace sandboxing and structured output are refused. Automatic approval review works for ACP agents too: Claude reviews each agent permission request against the Codex guardian policy (--auto-review-model, default sonnet). See COMPATIBILITY.md for the full mapping.

Minimal client exchange

Stdio and unix-lines:// use one JSON object per line. TCP and Unix WebSockets use one JSON object per text frame. As with Codex, outgoing messages omit jsonrpc. String and integer request IDs are preserved.

Send initialize, await its response, then send initialized:

{"id":1,"method":"initialize","params":{"clientInfo":{"name":"my-client","version":"1"},"capabilities":{"experimentalApi":true}}}
{"method":"initialized"}

Start a thread, read result.thread.id, then substitute that ID into the turn request:

{"id":2,"method":"thread/start","params":{"model":"sonnet","sandbox":"danger-full-access","approvalPolicy":"on-request"}}
{"id":3,"method":"turn/start","params":{"threadId":"<thread-id>","input":[{"type":"text","text":"Hello","text_elements":[]}]}}

The client receives turn/started, item start/delta/completion events, and exactly one turn/completed for an accepted turn. Responses and notifications can interleave. Wait for turn/completed before starting another turn on that thread; separate threads may run concurrently.

A permission request is a server-initiated request with its own ID. For commands and file changes, respond using the exact ID:

{"id":"<approval-request-id>","result":{"decision":"accept"}}

The supported decisions are accept, acceptForSession, decline, and cancel. Session grants apply only to identical tool input and cwd within the same thread; broader permission amendments are rejected. Multi-select native questions use the installed desktop option-picker extension. See COMPATIBILITY.md for request and recovery semantics.

Workspace-write uses Claude's OS-enforced Bash sandbox and scoped file permissions; startup verifies the resolved native restrictions before sending user input. Desktop Approve for me selects native Claude auto review. Manual review remains supported. Full access (danger-full-access with never) selects Claude's bypassPermissions; never inside the workspace sandbox selects dontAsk. Eligible unsandboxed retries use the selected reviewer: native automatic review under Approve for me, or desktop approval under manual review. Explicit native ask/deny rules remain authoritative. MCP integrations and hooks remain trusted services outside the Bash sandbox. Read-only/external profiles are rejected. The generated desktop launcher also enables genuine Codex plugin services using the existing plugin registry and authentication; see plugin integration.

Verification

mbx test --locked --all-targets --features test-backend
mbx clippy --locked --all-targets --features test-backend -- -D warnings
cargo fmt --all -- --check

The deterministic suite drives the real facade executable with a fake Claude subprocess. It checks emitted responses, notifications, and approval requests against the vendored upstream schema, plus stream reconciliation, approvals, interruption, background continuations, restart, fork metadata, history pagination, and socket transports. The fake backend is available only with the test-backend feature.

Current verification results and live transport evidence are recorded in the desktop integration audit.

On a heavily loaded host, use RUST_TEST_THREADS=1 TOKIO_WORKER_THREADS=2. If the local mbx test launcher stalls, compile with mbx test --no-run --all-targets --features test-backend, then run the reported test executables directly; this preserves compiler caching.

The live smoke example exercises inference, recall after restarting the facade process, and a fork that remains anchored while the source conversation advances:

mbx build --locked --bin claude-codex-server --example smoke
./target/debug/examples/smoke ./target/debug/claude-codex-server

To also verify a real command approval, add --exercise-approval. The example approves only the exact command printf FACADE_TOOL_OK, denies other tool requests, and uses a temporary workspace with Claude safe mode. It makes real model calls and leaves native Claude session records in Claude's normal storage.

Live verification status (October 8, 2026): inference, recall after a server restart, fork snapshot isolation, and a real command approval all passed. The smoke example adds an explicit Bash ask rule so its harmless printf command requires a callback. The previous expired-OAuth blocker is resolved. Desktop UI behavior remains unverified because the computer-use tool does not allow access to the Codex app.

Design and references

transport.rs owns framing and connections; server.rs owns RPC ordering, subscriptions, turns, and approvals; backend.rs owns Claude subprocess/control I/O; translate.rs owns item lifecycles; store.rs owns atomic facade persistence. A completed turn is published only after backend cleanup and process reaping. A Claude background-agent continuation is kept within its initiating Codex turn until Claude reports idle. subagents.rs maps Claude subagents to Codex child threads.

Primary references:

The checked-in schema was generated with codex app-server generate-json-schema --experimental from the installed version, rather than fetched from a moving branch. See NOTICE for attribution.

CI runs formatting, Clippy, and deterministic tests on Linux and macOS. See releasing for the tagged Linux workflow, local macOS signing, and Homebrew update process.

About

Use your Claude Code subscription inside Codex app & cli

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages