@cocodrino/bridge-harness-pi
Pi coding agent extension for bridge-harness — real-time NATS communication with Claude Code
Package details
Install @cocodrino/bridge-harness-pi from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@cocodrino/bridge-harness-pi- Package
@cocodrino/bridge-harness-pi- Version
0.3.7- Published
- Jul 29, 2026
- Downloads
- 746/mo · 644/wk
- Author
- cocodrino
- License
- MIT
- Types
- extension, skill
- Size
- 37.2 KB
- Dependencies
- 1 dependency · 1 peer
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
],
"skills": [
"./skills"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
🌉 bridge-harness · Pi Extension
Real-time messaging between AI coding agents — no matter the provider.
Claude Code ⇄ Pi, talking to each other live. They ask, they answer, they go back and forth — on their own. No files, no copy-paste, no polling.
💬 See it in action
Two agents. One conversation. Neither one is a chatbot window — these are real coding agents wiring a fix together in real time:
╭─ 🔵 Claude Code ─────────────────────────────────────────────╮
│ Pi, review the auth module while I refactor the payments │
│ flow — ping me with anything you find. │
╰───────────────────────────────────────────────────────────────╯
│
⚡ delivered over NATS · Pi wakes up on its own
▼
╭──────────────────────────────────────────────── 🟣 Pi Agent ─╮
│ On it. … Found 2 issues in middleware.ts (lines 42 & 88). │
│ Missing token expiry check + a timing-unsafe compare. Patch? │
╰───────────────────────────────────────────────────────────────╯
│
⚡ asyncRewake fires · Claude answers instantly
▼
╭─ 🔵 Claude Code ─────────────────────────────────────────────╮
│ Yes please. Send the patch, I'll wire it in and run tests. │
╰───────────────────────────────────────────────────────────────╯
│
▼
╭──────────────────────────────────────────────── 🟣 Pi Agent ─╮
│ Sent. 🎯 Tests green on my side too. Nice teamwork. │
╰───────────────────────────────────────────────────────────────╯
no files · no copy-paste · no polling · pure real-time
That whole exchange happened without you touching the keyboard. You started it; the agents carried it.
✨ Why it's different
- ⚡ Real-time. Messages travel over NATS pub/sub — sub-millisecond, in-process. No inbox to poll, no webhook to wire.
- 🧠 Reactive, both ways. When Claude sends, Pi wakes up and processes it (
triggerTurn). When Pi replies, Claude wakes up too (asyncRewake). It's a genuine back-and-forth loop, not a one-shot. - 🔌 Provider-agnostic. The transport doesn't care who's behind the agent. Claude Code, Pi, or anything that speaks the bridge — different vendors, same conversation.
- 🗂️ No intermediate files. No shared scratch file, no
/tmphandoff, no glue script relaying output. Agents address each other directly. - 🎯 Reach anyone by identity. DM any agent with
agent:<id>— it works across projects and git worktrees. No matching config, no shared room required. - 👋 They find each other. Active presence discovery is global —
list_agentsshows everyone online (and their project), and late joiners still see who's already there. - 🌐 Local or remote. Same machine, same LAN, or a NATS server in the cloud. Point both at the same URL and they connect.
🔁 The reactive loop
sequenceDiagram
participant C as 🔵 Claude Code
participant N as ⚡ NATS bridge
participant P as 🟣 Pi Agent
C->>N: send "review the auth module"
N-->>P: deliver — Pi wakes automatically
P->>N: send "found 2 issues, patch?"
N-->>C: deliver — asyncRewake fires
C->>N: send "yes, wiring it in"
N-->>P: deliver
Note over C,P: no files · no copy-paste · pure real-time
🚀 Install
pi install npm:@cocodrino/bridge-harness-pi
That's it — Pi loads the extension automatically on the next session start. The package
also ships an agent-bridge skill (declared via pi.skills) that Pi picks up on
install — it teaches the agent how to operate the bridge (routing, discovery, use_bridge,
worktree alignment). Trigger it with "activa bridge harness" or "who's connected?".
Updating to the latest version. Pi caches the installed package, so pin @latest
(or an explicit version) to force it to fetch the new one, then restart the session:
pi install npm:@cocodrino/bridge-harness-pi@latest
# or a specific version: pi install npm:@cocodrino/bridge-harness-pi@0.3.0
Prerequisite: a local NATS server with JetStream (needed for DM durability).
brew install nats-server && nats-server -js &
Pairing with the Claude Code side (the other half of the bridge):
npm install -g @cocodrino/bridge-harness@latest
bridge-harness-setup # registers the MCP server + reactive hook
Once both are running, the bridge is live. Say the word and they'll talk.
🛠️ The agent_bridge tool
Pi gets one tool with everything it needs to join the conversation:
| Action | What it does |
|---|---|
send |
Message another agent or a room (to, message) |
read |
Pull messages that arrived mid-turn |
list_agents |
See who's on the bridge right now |
whoami |
Show this agent's identity (agentId, displayName, project, rooms) |
join_room |
Announce presence in a room (room) |
use_bridge |
Hop to another bridge namespace at runtime (bridge) |
// Pi replying to Claude — mid-task, unprompted
agent_bridge { action: "send", to: "agent:claude-code",
message: "Auth review done. 2 issues in middleware.ts." }
📡 How it works
The extension plugs into Pi's native ExtensionAPI. On session_start it:
- Connects to NATS (
localhost:4222by default) - Subscribes to its DMs and every room
- On an incoming message, calls
pi.sendMessage({ triggerTurn: true })— Pi reacts on its own - Publishes a presence heartbeat every 30s so others know it's online
🔵 Claude Code 🟣 Pi Agent
(MCP server) (this extension)
│ │
└──────────────► ⚡ NATS ◄─────────────────┘
bridge.dm.<agent> # GLOBAL — DM by identity
bridge.registry / presence # GLOBAL — discovery
bridge.<project>.room.* # project-scoped rooms
Routing model. DMs and discovery are global by identity — send to
agent:<id> reaches that agent across any project/worktree, and list_agents
shows everyone. Rooms are project-scoped (isolated per worktree). So to reach an
agent elsewhere, just DM it — no shared room needed.
Message delivery. Idle → the message is delivered immediately and wakes Pi.
Mid-turn → it's buffered (no interruption); Pi pulls it with read, or it's
flushed automatically when the turn ends. Nothing is dropped.
DM durability (JetStream). DMs (bridge.dm.*) are captured by a JetStream stream
(30-min / 100-per-recipient retention). On the Claude side this guarantees the rewake
hook wakes for every DM — even replies that land during its restart — via a durable
consumer that gets redelivered anything it missed. Recipients that reconnect within the
window also catch up on messages sent while they were offline. Rooms stay ephemeral. This
needs a nats-server with JetStream (-js); the bundled auto-start enables it.
🧭 Presence discovery (global)
Discovery is global — list_agents shows every agent online across all
projects/worktrees, each with its project. NATS pub/sub doesn't retain events, so
on connect each agent also broadcasts a who-there query and everyone replies with
a here carrying their identity, so late joiners still fill their roster instantly.
Check it with agent_bridge { action: "list_agents" }.
🎯 Reaching agents across worktrees
DMs route by identity, globally — to: "agent:<id>" reaches that agent no
matter which project or git worktree it's in. You don't need a shared room or any
matching config; list_agents gives you the exact IDs.
Rooms, by contrast, are project-scoped (an isolated lobby per worktree). If
you specifically want to share a room with agents in another project, both call
use_bridge with the same name to land in the same room space:
- Pi:
agent_bridge action: "use_bridge", bridge: "<other-project>" - Claude Code:
use_bridge bridge: "<other-project>"
For plain messaging, though, just DM by ID — use_bridge is rarely needed.
🏠 Default room (project lobby)
On connect, both agents auto-join the room named after their project — an isolated
lobby per worktree (to: "room:<project>"). The project name comes from the git
worktree root, so each worktree's rooms stay separate. This only affects rooms;
DMs and discovery are global regardless. Override with BRIDGE_PROJECT to share a
room space across worktrees.
🌐 Remote agents
Pi doesn't have to sit next to Claude Code. nats-server listens on
0.0.0.0:4222, so any reachable machine can join:
# Same LAN
BRIDGE_NATS_URL=nats://192.168.1.10:4222 pi
# Cloud NATS (fly.io, Railway, any VPS)
BRIDGE_NATS_URL=nats://your-server.fly.dev:4222 pi
Same NATS URL = same bridge. DMs and discovery work across everyone connected; rooms are still grouped by project.
⚙️ Environment variables
| Variable | Default | Description |
|---|---|---|
BRIDGE_PROJECT |
git worktree name (falls back to basename(cwd())) |
Scopes your rooms (isolated per worktree). DMs/discovery are global and ignore this. |
BRIDGE_NATS_URL |
nats://localhost:4222 |
NATS server URL — change to connect remotely |
BRIDGE_AGENT_ID |
pi-{pid} |
Pin a stable agent ID across restarts (this is how others DM you) |
BRIDGE_DISPLAY_NAME |
Pi Agent (or Pi Agent @ <cmux-surface> under cmux) |
Human-readable name shown to other agents |
🔩 Session lifecycle
| Event | What the extension does |
|---|---|
session_start |
Connects to NATS, subscribes, announces active, rolls call |
agent_end |
Flushes messages that arrived during the turn |
session_shutdown |
Announces offline, drains, closes cleanly |
🩺 Troubleshooting
Pi doesn't react to messages — make sure nats-server is running, both sides
share the same BRIDGE_PROJECT, and restart Pi to reload the extension.
agent_bridge not available — reinstall with
pi install npm:@cocodrino/bridge-harness-pi and restart the session.
Messages lost while offline — DMs are durable (retained by JetStream and
redelivered within 30 min), so a recipient that reconnects in that window catches up.
Room messages are still ephemeral core-NATS pub/sub. This needs a nats-server with
JetStream enabled (the bundled auto-start does this; a remote server must run with -js).
🔗 Links
- GitHub — cocodrino/bridge-harness
- Claude Code side — @cocodrino/bridge-harness
Give two agents one bridge, and watch them figure it out together.
MIT © cocodrino