Let coding agents on one machine message and wake each other. Run `harness-summit install` first.
Let your coding agents talk to each other.
harness-summit lets agent sessions on one machine send messages to each other, across different harnesses: Claude Code, Codex, OpenCode, pi and OMP (oh-my-pi). When a message arrives, the receiver wakes up by itself, even when it sits idle at its prompt. It reads the mail, does the work, and replies.

Claude Code (top left), Codex (bottom left) and OMP (right) join one group with /sj / $sj, then message each other. Each receiver wakes up by itself and answers. Sped up 1.5x.
It is an MCP server plus a small wake adapter per harness. All state is plain files under
~/.harness-summit. There is no daemon, no network and no account.
Claude Code (cc): /summit-send @cx Review the diff in src/auth and tell me what breaks.
Codex (cx): wakes up, reads the message, reviews, then:
summit_send to cc (replyTo ...): "Two problems: ..."
Claude Code (cc): wakes up with the reply.
| Harness | Tested version | How you type a command | How an idle session is woken |
|---|---|---|---|
| Claude Code | 2.1.296 | /sj (plugin skill) | plugin hooks: SessionStart + FileChanged rewake |
| Codex CLI | 0.162.1 | $sj (skill) | codex queue --thread <id> |
| OpenCode | 2.0.24 | /sj | opencode api session.prompt with delivery: "queue" |
| pi | 1.0.4 | /sj | extension: sendMessage / sendUserMessage |
| OMP | 18.8.7 | /sj | the same extension file |
Every wake path was tested live on these versions, with idle receivers and no manual nudge. Other versions may work; the hook and extension APIs these paths use are young and change often.
You can use any subset of the five harnesses above. install sets up only the ones you name.
Verified live on Linux (every wake path above) and on macOS (Claude Code to Claude Code). Windows is
verified by CI only (build, typecheck and the full test suite on windows-latest, Node 22 and 24); no
harness session has run on it yet. On Windows, the Claude hooks use the exec form and the Codex and
OpenCode wakes run their .cmd shims through cmd.exe; both follow the docs and the tests, not a
live run.
Node.js 22 or later must be on PATH. In Claude Code:
/plugin marketplace add anthonyleung-dev/harness-summit
/plugin install harness-summit@harness-summit
Then restart Claude Code. This needs no global npm install.
If node on your PATH is a shim that starts node as a child process (Volta does this), this route
cannot work: the plugin starts node from PATH, and every tool fails with SUMMIT_NO_HOST_KEY.
Use the global install below with --harness claude instead; it writes the absolute path of node.
Claude Code keeps one marketplace per name, and both routes name theirs harness-summit:
harness-summit install --harness claude before: run
harness-summit uninstall --harness claude first, then add the plugin as above./plugin before and now want the global install for Claude Code: in
Claude Code run /plugin uninstall harness-summit@harness-summit, then
/plugin marketplace remove harness-summit. install checks this and stops with these steps. To
keep the plugin, install the other harnesses only: --harness codex,pi,omp,opencode.Codex, OpenCode, pi and OMP need the global install:
npm install -g harness-summit
harness-summit install --harness all --dry-run # print the plan; writes nothing
harness-summit install --harness all # or: --harness claude,codex
harness-summit doctor # check what is registered
doctor shows the Claude Code route that install set up (route=install). It does not detect a
/plugin install of the public plugin (route=unknown). When a registration starts another node or CLI
than the one you run doctor with, it adds a warn line that names both and the install command that
fixes it (the exit code stays 0).
Install it globally, not with npx: the registrations point at the absolute path of the installed
CLI, and an npx cache can be cleared under them. To run from a checkout instead, see
Development.
Restart the harness sessions that are already open; they load the new configuration only at start. Then, in two sessions in the same git project:
session A: /sj alice
session B: /sj bob
session A: /summit-send @bob Run the tests and tell me which ones fail.
Session B wakes up, reads the message and answers alice.
To remove everything that install added:
harness-summit uninstall --harness all
| What | Claude Code / pi / OMP / OpenCode | Codex |
|---|---|---|
| join, with an optional name | /sj [name] | $sj [name] |
| list the members of my group | /sl | $sl |
| set my display name | /sr <name> [--force] | $sr <name> [--force] |
| move to a named group | /sg <group> [--force] | $sg <group> [--force] |
| send a message | /summit-send @<name> <text> | $summit-send @<name> <text> |
| leave | /summit-bye | $summit-bye |
The long forms summit-join, summit-list, summit-rename and summit-group also exist. In Claude
Code the menu shows the plugin prefix (/harness-summit:sj), but typing /sj works. Codex 0.162.1
has no custom slash commands, so the commands are skills, typed with $.
Names ignore letter case. Taking a name from an agent that is not active needs --force. A resumed
session always gets its agent and mail back, but its name may have been taken meanwhile.
Agents in the same git project join the same group automatically. To talk across projects, every
agent runs /sg <same-name>.
The model uses eight MCP tools: summit_join, summit_send, summit_read, summit_members,
summit_whoami, summit_rename, summit_group and summit_bye.
summit_send takes to (@name, name or a uuid), the text in message, and replyTo (the id of
the message it answers) when it is a reply. body is an alias of message, because summit_read
returns each message's text in body. Give exactly one of the two.
sequenceDiagram
participant A as alice (any harness)
participant FS as ~/.harness-summit
participant W as wake path
participant B as bob (any harness)
A->>FS: summit_send: append one record to bob's inbox
A->>W: wake bob, using the wake action bob recorded when he joined
Note over W: Claude/pi/OMP: write bob's signal file<br/>Codex: codex queue<br/>OpenCode: opencode api session.prompt
W->>B: "[harness-summit] 1 unread message(s) from alice. Call the summit_read tool."
B->>FS: summit_read: records past bob's cursor, then move the cursor
B->>FS: summit_send to alice with replyTo
summit_read.--force meanwhile), and /clear or /new starts a new agent while the
old one waits to be resumed.sent, skipped (a wake is already pending),
failed (with the reason), or queued when the receiver may not be active (after /clear, /new or
an exit): it sees the message when its session is active again./sj gives the agent these rules in your words, and every summit_read result repeats them:
summit_send({ to: "<sender uuid>", replyTo: "<message id>", message: "<your answer>" }). A reply
needs no answer, so two agents never answer each other in a loop.replyTo only to answer a message. Send a new request or a forwarded message without it.An agent does not know it can talk to other agents until you tell it. The commands are for you; the
agent can call the MCP tools itself. Add a note like this to your instructions file: CLAUDE.md for
Claude Code, AGENTS.md for the other harnesses (global or per project):
## Talk to other agents (harness-summit)
To ask an agent in another session or harness for help, use the harness-summit MCP tools, not its
terminal:
- Join with `summit_join`, then set a clear name with `summit_rename`.
- See who is there with `summit_members`.
- Send with `summit_send` (`to` = name or uuid, `message` = the text).
- Read with `summit_read` when a notice says mail is waiting. Follow the `guidance` it returns.
You do not need to copy the mail rules: summit_join and every summit_read return them.
install changes| Harness | Registration | Commands | Wake adapter |
|---|---|---|---|
| Claude Code | a generated plugin in ~/.local/share/harness-summit/claude-marketplace, added with claude plugin | plugin skills | plugin hooks |
| Codex | a marked block [mcp_servers.harness-summit] in $CODEX_HOME/config.toml, with tool approvals | $CODEX_HOME/skills/<name>/SKILL.md | none needed |
| OpenCode | opencode mcp add --global harness-summit ... | $XDG_CONFIG_HOME/opencode/commands/<name>.md | none needed |
| pi | registered by the extension on every session start (no mcp.json entry; an older one is removed) | ~/.pi/agent/prompts/<name>.md | ~/.pi/agent/extensions/harness-summit.ts |
| OMP | mcpServers.harness-summit in ~/.omp/agent/mcp.json | ~/.omp/agent/commands/<name>.md | ~/.omp/agent/extensions/harness-summit.ts |
$CODEX_HOME is ~/.codex and $XDG_CONFIG_HOME is ~/.config unless you set them; OpenCode uses
$OPENCODE_CONFIG_DIR instead of $XDG_CONFIG_HOME/opencode when you set it. Install, doctor and
uninstall read them (each must be an absolute path; a bad one blocks only Codex or only OpenCode).
After you change one, run install again: it moves that registration and its commands from the old dir to
the new one. With --home <dir> they ignore all three and use <dir>/.codex and <dir>/.config.~/.pi/agent and ~/.omp/agent and ignores PI_CODING_AGENT_DIR.<file>.harness-summit.bak, and records every step in
~/.local/share/harness-summit/install-state.json.uninstall restores a file byte for byte when you did not edit it after install. When you did, it
removes only the harness-summit keys. A config file that install created is deleted only when nothing of
yours is in it; a key you added there stays, also after a re-install.node and to dist/cli.js. Run install again after you
move the checkout, upgrade the package, switch from a checkout to the npm package, or switch the Node.js
version (for example with nvm). That run points every registration at the node and CLI that run it,
also in a config file you did not touch since the last install (it prints edit or run for each).After npm install -g harness-summit@latest, run harness-summit install again with the same harnesses. It
rewrites the generated files and removes the files it wrote earlier that the new version no longer has (a
file you edited stays, and install says so). Claude Code reads the plugin from install's folder, so the new
files load when you restart Claude Code or run /reload-plugins; install also runs claude plugin update harness-summit@harness-summit so claude plugin list shows the new version. A second run changes nothing:
its only command is the read-only claude plugin list --json, and if you removed the plugin by hand
(/plugin uninstall), that run adds it back.
All state is plain files under ~/.harness-summit (or $HARNESS_SUMMIT_HOME): a folder per group (md5
of the project root, or the name after /sg) with a folder per agent and one append-only file per sender,
plus identity, session, heartbeat, wake and log files. SPEC.md section 4 lists them.
git clone https://github.com/anthonyleung-dev/harness-summit.git
cd harness-summit
npm install
npm run build
node dist/cli.js install --harness all # registers this checkout
npm test # build, then unit and integration tests (vitest)
npm run typecheck
npm run format:check
claude --plugin-dir plugins/claude, or
pi -e adapters/pi-omp/harness-summit.ts (the same file works for omp -e).HARNESS_SUMMIT_HOME to a temp dir and run install only against a temp home.npm run build type-checks, then bundles the CLI with esbuild into one file, dist/cli.js, plus
dist/THIRD_PARTY_LICENSES.txt. The published package has no runtime dependencies: the libraries are
inside the bundle, so npm i -g harness-summit and the Claude plugin install nothing else.npm run build writes every generated file from package.json: plugins/claude/, the public
plugin and marketplace in .claude-plugin/, and server.json. Commit them with the change. CI fails
when a committed copy differs from the build output. The build deletes any file in plugins/claude/
that the templates no longer produce, so do not put hand-written files there. The build step
(gen-plugin) runs only in a git checkout with src/; an installed package refuses it.main): on a branch, bump version in
package.json (the only place you edit), run npm run build, commit, push the branch and open a PR.
Right after the PR is merged, tag the merge commit and push the tag: git fetch origin, then
git tag v<version> <merge sha>, then git push origin v<version>. Tag at once: from the merge until npm
has the version, the public marketplace on main names a version npm lacks, so /plugin install fails.
The tag starts the release workflow: it checks that the tag matches package.json, runs the audit, the
tests and the generated-files check, publishes to npm, then lists the release in the
MCP Registry as io.github.anthonyleung-dev/harness-summit
(GitHub OIDC, no token; server.json name must equal mcpName, a unit test checks it). If publish
fails for a cause outside the code, re-run the job; else fix it in a new PR that also bumps version to
the next patch, and release that: never move a pushed tag, and npm never takes a version number twice.src/cli.ts, src/cli/ CLI entry, sub-commands, Claude Code hooks
src/server/ MCP server and tool schemas (Zod)
src/flows/ one flow per tool
src/core/ files, identity, messages, notice, wake, locks, logging
src/install/ install, uninstall, doctor, command templates
scripts/bundle.ts esbuild bundle of the CLI and its third-party license notices
adapters/pi-omp/ the pi and OMP extension
plugins/claude/ dev Claude Code plugin, generated by `npm run build`
.claude-plugin/ public Claude plugin and marketplace, generated by `npm run build`
test/ unit and integration tests
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y harness-summitMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-anthonyleung-dev-harness-summit": {
"command": "npx",
"args": [
"-y",
"harness-summit"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceharness-summit works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.