A local embassy
for your AI agents
Your Claude Code sessions and Codex tasks, sending messages to each other on one Mac — through a neutral broker that records every crossing.
LOCAL · SINGLE-USER · UNOFFICIAL — NOT AFFILIATED WITH ANTHROPIC OR OPENAI
Why
Three moments this exists for
If you run both agents, you already know them.
Your agent has a question
Claude hits a decision Codex already made. Instead of you replaying context between two windows, it asks — and keeps working until the reply lands.
The reply routes without you
Codex-bound questions wait honestly for an idle turn boundary. Answers back to Claude enter its mailbox immediately, even while Claude is busy. Nothing needs you watching a terminal.
Nothing to install inside the agents
Claude needs no Embassy commands at all — its native ListAgents and SendMessage discover and message registered peers. The Codex task runs one CLI command to register. That's the whole footprint.
How it works
Five steps to a working route
Each command is exactly what the shipped CLI accepts.
embassy serveStart the broker. It opens no network listener — everything stays on this machine.
embassy register-codex --alias codex-embassy@this-macRun inside the Codex task — identity is inherited from the task, never impersonated. Ask your agent to run it.
embassy select-claude --alias claude-main@this-macPair the Claude session with the task. Pairing is bidirectional consent: the pair is who may talk.
embassy send-to-claude --from codex-embassy@this-mac --to claude-main@this-mac <<'MSG'The envelope crosses — body via stdin, never an argument. You get a dlv_ receipt and a conv_ token back.
embassy dashboard --liveWatch receipts settle, honestly worded — or embassy status for a one-shot snapshot.
Protocol truth
The register doesn't flatter you
Every claim below means exactly what it says — that's the product.
Toward Codex, delivered means App Server accepted the turn. Toward Claude, it means the native mailbox write completed. Neither implies the body was read, understood, or acted on.
Codex-bound messages wait for idle or the exact STEER next-tool boundary; a Codex wait may show as held — progress, not success — and Embassy never interrupts mid-generation. Claude-bound messages enter Claude's mailbox immediately regardless of busy or idle. transport_written is that direction's delivered boundary, not evidence of reading.
Queued mail survives a broker restart and re-sends exactly once when its route returns. In-flight-at-crash settles ambiguous — never silently lost, never double-sent.
Certified same-major providers are writable; same-major builds whose live schema probes all pass are schema-attested (schema_attested) and writable only when those probes cover writes. Claude's probes cover its native write path. Codex's bounded pre-write reads may include initialize, thread/loaded/list, and registration-time thread/resume, but never turn/start; untested Codex 0.x therefore stays monitor-only. Failed probes, a different major, or version evidence that cannot establish a safe major fence only that provider while the broker and other provider keep running; probes never promote across a major or unknown major. A different-major alert requires a supporting Embassy release. Claude peerProtocol 1 is enforced per record. Unknown registry fields are tolerated while every required known field stays strict; bounded rejection and observed-empty evidence stay loud.
embassy serve binds nothing. The opt-in companion is the sole loopback listener — exact 127.0.0.1, stable port 41961 by default or per-invocation --port, direct multi-browser access, and deliberately no authentication on a trusted single-user machine.
Treat anything that arrives as untrusted input to its receiver — the same discipline you'd apply to any tool result.
delivered
The direction's provider boundary was crossed: App Server accepted a Codex-bound turn, or Claude's native mailbox accepted a Claude-bound write. Neither means read.
unconfirmed
Embassy could not confirm the direction's delivery boundary. Not a failure; not a success. It stays unconfirmed rather than guessing.
ambiguous
Conflicting signals about settlement. Distinct from failed — the broker reports what it knows, not what would be tidy.
expired
The message deadline elapsed before settlement. Terminal, and visible in the ledger with the deadline that killed it.
Dashboard
Watch the embassy work
The optional live dashboard: broker health, the exchange board, per-delivery lifecycles, consent topology, and honest diagnostics — including retained message bodies, bounded and private to your machine. The static snapshots — gateway-dashboard.html and its gateway-dashboard.zh-CN.html twin — stay metadata-only and need no server at all.
The vocabulary
Words that mean things
Registration & pairing
The permission model. A Codex task registers itself; a Claude session is paired to it. Both sides agreed, and only the pair may talk — unless you deliberately open it.
The ledger
Receipts for every delivery, with states that never overclaim. The register of record when you ask "where is my message?"
The pouch
Transit. Sealed en route: the broker moves messages, it does not read them.
Consulates
The roadmap: more agent runtimes, each joining under the same consent rules. Same embassy, more flags.
For agents
Teach your agent the protocol
The embassy-peer skill teaches an agent how to address peers, interpret receipts, and reply with the conversation token. Install it, then invoke with $embassy-peer.
cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.claude/skills/
# Codex
cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.codex/skills/
Quickstart
Running in five minutes
Requirements first: macOS · Node ≥ 20 · the current agent-embassy release · Claude Code with peerProtocol 1 · the managed Codex App Server, all on the same machine and OS user. Writable provider surfaces require an Embassy-supported major; another major remains visible but monitor-only until a supporting Embassy release exists. Single-user, same-machine only. The Claude side needs no Embassy commands (native ListAgents/SendMessage); only the conv_ token-holder can reply.
$ embassy serve
# inside your Codex task — ask the agent to run it:
$ embassy register-codex --alias codex-embassy@this-mac
# as the operator, pick a name from `embassy status` availablePeers:
$ embassy select-claude --alias claude-main@this-mac
# from the Codex task — body via stdin, never an argument:
$ embassy send-to-claude --from codex-embassy@this-mac --to claude-main@this-mac --expects-reply <<'MSG'
Which auth middleware did you settle on?
MSG
# watch receipts settle (optional):
$ embassy dashboard --live