Skip to main content
Glama

cross-yapper

A small personal bridge that lets Codex agents discover projects, read existing conversations, and send messages to specific conversations on trusted machines. Keep using ordinary Codex conversations. No dashboard, hosted service, separate agent framework, or cloud dependency.

Status: the macOS desktop adapter has passed local same-conversation and installed-MCP round trips. Linux's attached app-server adapter and actual cross-machine delivery still need qualification. Windows installation is also unverified. This is an experimental personal tool, not a hardened public service.

Download and check

Version 0.2 uses Rust for the service, CLI and MCP protocol. Desktop integration retains a tiny launcher running in Codex's bundled Node: the installed Mac app rejects an unsigned Rust process at its private pipe. Each desktop MCP client has a launcher; one elected launcher shares a persistent desktop connection. Linux owner mode needs no Node runtime.

Download the matching archive from Releases and extract it into a permanent directory. Keep the executable and both .mjs files together. No Rust compiler or npm installation is required for releases. On Windows run cross-yapper.exe; on Unix run ./cross-yapper.

For source development (Git and Rust 1.95):

git clone https://github.com/adrianvalentim/cross-yapper.git
cd cross-yapper
cargo test --locked
./scripts/build.sh
./bin/cross-yapper help

Source examples below use ./bin/cross-yapper. For a release installation, substitute the downloaded executable. See Agent setup.

Related MCP server: claude-intercom-mcp

How it connects

Codex conversation -> cross_yapper MCP -> local bridge service
                                            |
                                  SSH tunnel + peer token
                                            |
                                  remote bridge service
                                            |
                            remote conversation's actual owner

Only narrow bridge requests cross machines. Raw Codex endpoints stay local. Your OpenAI account supplies Codex access; separate random bridge tokens identify trusted machines and authorize specific logical projects.

On macOS the desktop app owns its conversations. The service handles HTTP, authentication and durable queues; a Codex-launched MCP process supplies the local desktop adapter. A standalone launchd process was rejected by the desktop pipe's signature authorization, even using the bundled runtime. Do not disable that check: keep the app and its MCP adapter running.

On Linux the optional owner adapter attaches to an existing app-server through codex app-server proxy. Its terminal client must connect to that same server. Launching another worker or resuming history in a different process does not prove communication with the original conversation.

Initial configuration

Run setup as the user who runs Codex. Choose a unique machine ID; mac is already used by the original installation. Examples: linux-lab, mac-studio.

./bin/cross-yapper init linux-lab
./bin/cross-yapper project-add cross-yapper "$PWD" "Codex conversation bridge"

On macOS, run init from an ordinary Codex desktop conversation so it can capture CODEX_APP_TOOLS_PIPE_PATH and CODEX_THREAD_ID. For Linux, follow the owner configuration below before starting the bridge.

Config: ~/.config/cross-yapper/config.json, or the absolute path specified by CROSS_YAPPER_CONFIG. Tokens and durable state live beside it. init refuses to overwrite an existing config. Set codex to the actual absolute CLI executable. Never commit or paste token values, account credentials, or conversation dumps.

macOS

Run from an ordinary Codex desktop conversation. Set codex in the private config to the installed absolute Codex CLI path. init captures the current pipe and conversation binding. For an existing config use bind-desktop.

./bin/cross-yapper install
./bin/cross-yapper start
./bin/cross-yapper status

install creates a user LaunchAgent, backs up its prior definition, and replaces only MCP cross_yapper, preserving unrelated Codex settings. It registers the bundled Node launcher with the native MCP child. Set CROSS_YAPPER_NODE to the actual bundled runtime when it is not at the default ChatGPT.app location. Keep Codex open with this MCP loaded. The service alone cannot access the app.

stop, start, and status control the service. After an app update/restart, if the pipe changes, run bind-desktop, restart the bridge and reload its MCP. adapter runs a foreground diagnostic worker through the source wrapper; it must be launched from Codex. Release equivalent: bundled Node with desktop-launcher.mjs --adapter-only.

Linux: attach to the same owner

Inspect the installed Codex help/schema before relying on these experimental commands. No existing conversation should be moved or resumed behind its UI.

# Terminal 1: local control endpoint only.
codex app-server --listen unix://
# Terminal 2: ordinary terminal client connected to that exact owner.
codex --remote unix://

Keep both running. In the bridge config, set codex to the absolute Codex path and add owner with the same executable:

"owner": {
  "command": "/absolute/path/to/codex",
  "args": ["app-server", "proxy"]
}

This overrides the desktop adapter; desktop can remain unused. The bridge does not launch or resume target conversations. Open a disposable conversation in that attached client; it must be loaded in that owner.

Register MCP before creating the test conversation:

./bin/cross-yapper install
./bin/cross-yapper start

On Linux install creates a systemd user service; start/stop use systemctl. For machines without systemd, register codex mcp add cross_yapper -- /absolute/path/to/cross-yapper mcp and run cross-yapper serve in the foreground. Keep the owner process running separately. The adapter requires thread/turns/list; missing capabilities fail explicitly. Linux live-owner integration remains unverified.

Windows

Use the native Windows executable and Codex installation, never WSL for native work. Set CROSS_YAPPER_NODE to Codex's bundled Windows Node, then run install for MCP registration and serve in the logged-in user's session. Windows does not yet have automatic service lifecycle setup; a user Task Scheduler entry can run serve. Protect config/token files with the user's Windows ACL. Native Windows desktop pipe compatibility and installation remain unverified.

Projects and conversations

Each machine has a small explicit registry. The same logical project id, such as porto, maps to different local paths. Display names do not establish identity. nativeProjectId can record a desktop project ID for reference.

All reads and sends check the target thread's exact normalized cwd against the selected project's paths, including another check before queued delivery. Register each relevant worktree and session subdirectory explicitly. Inspect git worktree list --porcelain; do not automatically authorize every descendant folder. Symlinks resolve where possible; Windows comparisons ignore case.

When Codex supplies sender thread metadata, its cwd resolves the local logical project. That same ID is the default project on a selected remote machine. CLI callers outside Codex must specify a project and are labeled as CLI senders.

Some agent-created desktop conversations were omitted by native thread listing on the tested version. Known IDs may be registered in the project's threads array; they appear as configuredThreads after a membership check. Native lists remain bounded and paginated. Metadata-reader notLoaded describes that reader process, not the desktop's live status; use read_thread for live context.

MCP and CLI

MCP server name: cross_yapper.

Tool

Purpose

list_machines()

Configured machines, reachability, actual OS/architecture and WSL flag

list_projects(machine?)

Explicit logical project mappings

read_project(machine?, project?)

Mapping and short thread overview

list_threads(machine?, project?, cursor?, limit?)

Up to 50 metadata summaries; continuation cursor

read_thread(machine?, project?, thread, cursor?, limit?)

Bounded history; default 3 turns, maximum 10

send_message(machine?, project?, thread, text, correlationId, mode?, requirePlatform?, replyTo?)

Durable exact-thread queue; only mode="queue"

read_receipt(machine?, project?, correlationId, senderMachine?)

State and associated reply

Machine defaults to local; project defaults to the sender's mapped project when available. Text is bounded; desktop reads exclude tool outputs. Example:

./bin/cross-yapper status
./bin/cross-yapper call list_projects '{}'
./bin/cross-yapper call list_threads '{"project":"cross-yapper","limit":10}'

Select a real test ID from your own installation. Read it, send a unique correlation ID, then poll read_receipt with the same project and ID. Reuse that ID and identical content when retrying; changed content is rejected.

accepted means durably queued; delivered means the owner acknowledged the send; completed means the observed associated turn finished. failed, interrupted, and uncertain are distinct. Crashes/timeouts during dispatch become uncertain and are never automatically resent. Inspect the target before using a fresh ID.

Messages preserve sender machine/project/thread and correlation ID. The service never sends automatic replies. An explicitly requested reply is a new send to the recorded origin, with a fresh ID and replyTo naming the original ID.

Pair machines over SSH

Use a suitable key-authenticated SSH connection into the recipient's native user environment. Verify host keys; do not disable checking. Do not modify an unrelated restricted compute/WSL endpoint to make it fit this bridge.

On the receiving bridge, authorize only the required logical projects:

./bin/cross-yapper allow-peer mac cross-yapper porto

This prints a newly generated credential file path, never its secret. Securely transfer the token file to the sender using SSH/SCP. On Unix, keep the credential directory at 0700 and tokens at 0600. Restart the receiver after changing config. On the sender:

ssh -NT -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=yes \
  -L 127.0.0.1:47832:127.0.0.1:47831 receiver-ssh-alias
./bin/cross-yapper peer-add linux-lab 47832 /absolute/path/to/received.token

Replace the SSH alias, machine ID and token path with verified local values. Restart the sender bridge. Forward only bridge port 47831; raw Codex endpoints stay local. Configure the reverse direction separately if explicit replies are needed. The bridge rejects peer transit and remote adapter-control requests.

For Windows-native work, send requirePlatform: "win32"; WSL does not satisfy that requirement. The platform label is not a substitute for a real native reproduction test.

Tests, limitations and troubleshooting

cargo test --locked covers membership/cursor rejection, busy/idle queueing, retry idempotency, uncertain dispatch across restart, and native-platform/steering rejection. Local tests do not establish remote delivery.

On the original Mac, app-owned reads/sends, installed MCP delivery, actual busy queueing, service restart/deduplication and HTTP authentication/project ACL checks passed. Private evidence and machine-specific installation records stay out of this public repository. No screenshot-level verification is claimed.

The desktop adapter uses the installed app's private app-tools pipe and catalog. It is version-sensitive. Its send operation has no atomic idle precondition or native turn ID in the acknowledgment. The bridge serializes its own traffic; simultaneous human/other-client sends can still race it and make attribution uncertain. Avoid concurrent manual sends during delivery. Steering is not exposed. No model, permissions, approvals or sandbox overrides are sent.

A separate app-server was able to read metadata but could not start/steer the existing desktop test thread; resume returned already has an active writer. The bridge never injects messages by editing Codex databases or transcripts.

If the adapter is offline, check the desktop app, MCP loading, bundled runtime, and current pipe binding. If a peer is unreachable, check its service and SSH tunnel; retry ambiguous sends only with their original correlation ID.

Performance and migration

See benchmark results and reproduction. The benchmark compares the complete old Node and Rust process trees, including every desktop launcher. It uses disposable synthetic endpoints and never sends real messages.

Existing JSON config, project IDs, tool arguments, cursor handling and receipt fingerprints remain compatible. Stop the old service, back up the config/state, build or extract the release, run install, then start. Reload MCP in Codex; already running old MCP processes keep their old code until reloaded. The old implementation remains available at Git commit f9d1f04 for rollback and benchmarks. No Codex transcript or internal database is changed.

Protocol references: Codex app-server and Remote connections. The initial Mac inspection used CLI 0.153.4. Generate version-matched schemas locally with codex app-server generate-ts --out /temporary/schema-directory.

To uninstall, stop only this service, run codex mcp remove cross_yapper, and remove its service definition. Optionally archive its private config directory. Never restore a whole old Codex configuration over later unrelated changes.

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Connects AI assistants to a local Codex engine for performing deep, project-level code reviews and automated refactoring. It enables context-aware bug fixes and multi-file analysis through a standardized bridge between modern AI clients and local development environments.
    4
    2
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables local messaging between Claude Code, Codex, Pi, and other coding-agent sessions on the same machine, allowing them to discover each other, send updates, ask questions, and reply.
    8
    9 npm
    2
    AGPL 3.0
  • A
    license
    A
    quality
    B
    maintenance
    A project-local MCP bridge that allows Codex Desktop to plan tasks and OpenCode to execute them within the current project directory, with session reuse and native OpenCode background subagents.
    4
    1
    MIT