Languages: English (this file) · 한국어
A Codex plugin and worker runtime that lets one interactive Codex session
coordinate with named headless Codex workers. The interactive session sends
tasks; workers process them with codex exec, can delegate to other workers,
and send replies back through the local CCP mesh.
Each peer runs a local MCP inbox server (ccp-inbox). Peers discover each other
through ~/.ccp/registry/. Interactive Codex sessions fetch their messages
manually. Headless workers poll their inboxes and reply automatically.
The original Claude-oriented version could use Claude Code channel notifications to push a message into another interactive session and wake a new model turn automatically. Codex CLI does not currently expose an equivalent supported surface for arbitrary MCP server notifications to wake an existing interactive session.
CCP therefore uses headless workers for automation. Your interactive Codex
session stays in control, while named workers run codex exec in the
background, process tasks, optionally delegate to other workers, and send
replies back to your inbox.
- macOS or Linux on
darwin-arm64,darwin-x64,linux-x64, orlinux-arm64 - Codex with MCP, plugin, skill, and hook support
- Either a prebuilt
ccp-inboxbinary or Bun 1.x on PATH
This repository is now a Codex plugin root:
codex plugin marketplace add /absolute/path/to/ccpThen enable the plugin in ~/.codex/config.toml:
[plugins."ccp@ccp-local"]
enabled = trueRestart the Codex CLI session after enabling the plugin so plugin MCP servers are reloaded.
The Codex plugin files are:
.codex-plugin/plugin.json.mcp.jsonhooks.jsonskills/ccp-protocol/SKILL.md
Add this to ~/.codex/config.toml or a trusted project .codex/config.toml:
[mcp_servers.ccp-inbox]
command = "/absolute/path/to/ccp/server/start.sh"
enabled = trueOr use the CLI:
codex mcp add ccp-inbox -- /absolute/path/to/ccp/server/start.shIn Codex CLI v0.130, plugin commands/ are not exposed as top-level slash
commands. Use natural language prompts such as "list CCP peers" or "fetch CCP
messages" instead of /ccp-* slash commands.
server/start.sh resolves the server binary in this order:
$CCP_BINif setserver/dist/ccp-inbox-<os>-<arch>server/dist/ccp-inbox- If
bunis on PATH, compileserver/inbox.tsonce - Otherwise, print a release download command
Build locally:
cd server
bun install
bun run build
bun run build:workerBuild all release targets:
cd server
bun run build:allStart your interactive Codex session as alice:
codex -C /absolute/path/to/ccp \
-c 'mcp_servers.ccp-inbox.env.CCP_NAME="alice"'Start any named worker you want:
cd /absolute/path/to/ccp/server
bun run worker.ts \
--name daniel \
--workspace /absolute/path/to/ccp \
--role "senior engineer, concise, implementation-focused"Add more workers with any names and roles:
bun run worker.ts --name tester --workspace /absolute/path/to/ccp --role "test engineer"
bun run worker.ts --name reviewer --workspace /absolute/path/to/ccp --role "code reviewer"Each peer writes a registry record such as ~/.ccp/registry/daniel.json.
Note: setting CCP_NAME=alice codex in the shell may not propagate to Codex
MCP servers. Prefer the -c mcp_servers.ccp-inbox.env.CCP_NAME=... override
for interactive CLI testing. Workers set CCP_NAME internally from --name.
List peers:
Use ccp-inbox list_peers and show me the CCP peer list.
Delegate work:
Use ccp-inbox send_to_peer to send daniel a task: find the 3 most recently modified files and report their names and mtimes.
The worker automatically polls its inbox, runs codex exec, and sends a reply.
In the interactive alice session, fetch replies:
Use ccp-inbox fetch_messages and show me CCP replies.
Workers can also delegate to other workers. The model running inside a worker
may return a structured delegation request; the worker supervisor sends that
task to another peer, waits for its reply, then produces the final answer to
the original sender.
cd /absolute/path/to/ccp/server
bun run worker.ts --name <worker-name> --workspace <workspace> [options]Useful options:
| Option | Purpose |
|---|---|
--name <name> |
Required worker peer name, for example daniel or tester. |
--workspace <path> |
Workspace passed to codex exec -C. |
--role <text> |
Role/personality hint included in the worker prompt. |
--persona <file> |
Extra instruction file for the worker. |
--model <model> |
Model passed to codex exec. |
--interval-ms <n> |
Inbox poll interval. Defaults to 2000. |
--once |
Process one task and exit. Useful for smoke tests. |
--max-delegations <n> |
Delegations allowed per task. Defaults to 1. |
--reply-timeout-ms <n> |
Max wait for delegated worker replies. |
--codex-cmd <cmd> |
Codex command to run. Defaults to codex. |
Example with a persona file:
bun run worker.ts \
--name daniel \
--workspace /absolute/path/to/ccp \
--persona ./workers/daniel.mdOne-shot smoke test worker:
bun run worker.ts \
--name daniel \
--workspace /absolute/path/to/ccp \
--once| Variable | Purpose |
|---|---|
CCP_NAME |
Name of this instance. Defaults to <hostname>-<pid>. |
CCP_PORT |
Inbox HTTP port. Defaults to an OS-assigned free port. |
CCP_SUPERVISOR |
Peer name to relay Codex PermissionRequest hooks to. |
CCP_NOTIFY_ON_STOP |
Peer name to notify when this session stops. |
CCP_PERMISSION_TIMEOUT_SEC |
Seconds for the permission hook to wait for a supervisor verdict. Defaults to 120. |
CCP_HOME |
Registry root. Defaults to ~/.ccp. Mostly useful for tests. |
Start a supervisor:
codex -C /absolute/path/to/ccp \
-c 'mcp_servers.ccp-inbox.env.CCP_NAME="alice"'Start a supervised session:
codex -C /absolute/path/to/ccp \
-c 'mcp_servers.ccp-inbox.env.CCP_NAME="bob"' \
-c 'mcp_servers.ccp-inbox.env.CCP_SUPERVISOR="alice"'When Codex in bob raises a permission request, hooks/permission-request.sh
posts a perm-request message to alice. Alice fetches messages, decides, and
calls:
respond_permission({ "peer": "bob", "request_id": "...", "behavior": "allow" })The verdict is written back for Bob's hook to consume.
fetch_messages({ clear? })send_to_peer({ to, content, kind?, task_id? })respond_to_peer({ task_id, content })list_peers()whoami()register({ name })respond_permission({ peer, request_id, behavior })
Message kinds:
task: the peer should perform real work and answer withrespond_to_peerreply: answer to a delegated tasknote: passive informationperm-request: permission request from a supervised peerpermission-verdict: visibility note for a permission verdict
| Path | Payload |
|---|---|
POST /msg |
{ from, content, kind, task_id? } |
POST /permission/request |
{ from, request_id, tool_name, description, input_preview } |
POST /permission/verdict |
{ from, request_id, behavior } |
GET /info |
this instance's metadata |
GET /peers |
discovered peers |
Every POST requires from to match a currently alive registered peer, except
loopback from the same instance.
cd server
bun testThe tests cover peer discovery, sender gating, queued inbox delivery, register renames, worker replies, and the permission relay path.
- Same machine only. Discovery is filesystem-based and HTTP binds to
127.0.0.1. - Codex does not receive arbitrary MCP server notifications as new model turns.
Peers must fetch messages with
fetch_messages. - Headless workers automate task processing, but the interactive
alicesession still fetches replies manually. - Permission relay depends on Codex hook support and a waiting hook process.