Tech
The pi-mesh Tool Family: A Four-Piece Toolkit for Local Multi-Agent Coordination
Machine-translated from the Chinese original. Corrections welcome.TMT
pi is the coding-agent harness we use daily. With a single terminal it is a quiet assistant; with three or four terminals open at once, each running an agent over the same repository, questions pile up: who is online? Who is editing which file? Was that message actually seen? Who has the right to stop the build running at midnight?
A family of small tools grew around pi-mesh to turn that coordination layer into infrastructure. Each owns one concern, and they interlock:
1. pi-mesh: the communication backbone
pi-mesh is a local bus: a broker detached from any session (NDJSON frames over a unix socket), each pi terminal a peer with an alias, organized into rooms. Messages arrive in under 50 ms; zero runtime dependencies, Node ≥ 20.
Its most admirable trait is the honest status model: delivered (written to the recipient’s socket) ≠ read (injected into the recipient’s session) ≠ answered (an explicit reply came back) — three states never conflated, none of them meaning “done”. The companion durable ledger is hash-only: message bodies are never persisted; after a restart you can audit who sent what to whom and when, but never read the content. This self-restraint later became the family’s design axiom: the mesh stays a router, never a database.
Three coordination needs live in the backbone:
mesh_reservepath reservations: reserve before editing; other peers’edit/writetools get blocked on those paths — concurrent editing is prevented by mechanism, not by shouting.mesh_claimtask leases: a single-writer lock with anepoch:fence(a broker restart invalidates old fences); commits carryMesh-Lease: task#leaseId#epoch:fence, and the bundled commit-msg hook rejects stale-fence commits outright.- Capability routing
cap::mesh_send({ "to": "cap:deploy", ... })routes the task to any idle peer advertising that capability instead of waiting for a busy teammate. Three message priorities: normal queues, urgent interrupts, force aborts the recipient’s current turn and delivers once it settles (force is a control class and requires a reason).
Add mesh_wait_all for group verdicts (one call returns who answered and who is missing), mesh_status for peer activity (● working / ○ idle / ✕ stuck), and a pimesh CLI for session-less access (pimesh attach can adopt a dead session’s identity). Multi-machine deployment is supported: one machine runs the broker, the rest connect as clients.
The honesty reaches down to exit codes: in the CLI, 3 means expired — a late reply is still delivered, you just stopped waiting; 5 means a stale lease, and the commit-msg hook rejects the commit on that basis. Even the host-specific edge of ESC purging the message queue is covered: a batch injected just as a turn aborts is re-delivered through an abort-safe channel once the turn settles (bounded retries), with a re-delivery counter visible in status.
2. pi-board: the shared context board
Messages are ephemeral; the ledger is hash-only. Where does “what we learned” live? pi-board fills that layer. Five typed entries:
- OBSERVED — something seen, no commitment
- FACT — a verified truth
- FAIL — a falsified path (the highest-value kind: the whole team stops re-burning budget on it)
- CLAIM — an ownership note, paired with a
mesh_claimlease (the board records; it never enforces) - PATCH_SUMMARY — what a landed change did
The design is bounded and honest throughout: append-only local storage, refuse-not-evict (over-limit writes are refused, never silently evicted), short entries by default with a detail field unfolded only by id, boolean search (, = OR, & = AND) across the full history while board_read serves only the recent window; a search miss returns an honest empty, never a guess. Writes go to the room as ordinary broadcast frames; a new-FAIL digest line rides every turn boundary; the room’s member / observer roles follow mesh semantics, so a read-only peer is never re-admitted as a writer after a reconnect. It joins the room as a normal peer — all storage stays at the board’s home; zero persistence in the broker. A bundled piboard CLI does it in five verbs — join (member / observer) / watch / write / read / grep, one verb per action — so even a session-less terminal can join a room read-only and observe. The typology and the “small entries + on-demand detail + recent memory / full-history search” split come straight from the research literature (the lineage story is in the next post).
3. pi-jobd: the background job daemon
bash blocks the current turn; /reload kills the process. pi-jobd runs long commands in their own process group supervised by a per-user daemon: it returns in ~150 ms, and the job outlives the session. When to use it? Three criteria: the command will run longer than 60–90 seconds; you must keep working while it runs; or it must survive /reload and session end — plus “another agent should be able to stop it”: mesh_job_control lets any authorized peer remotely stop/pause/resume someone else’s background job.
The state machine is equally honest: running / paused / stopped / exited / failed, plus lost — when the daemon restarts and cannot prove pid ownership, it refuses to stop rather than signal an unproven process. One more clever touch: installing the package is not enough — the model must know when to use it. Three layers feed the model the decision rule: a prompt snippet, guidelines on all seven tools, and an on-demand skill.
4. pi-subagents: worker control
pi-subagents manages in-process child agents: foreground children stream inside the conversation; background children live in a detached runner process you can check later. It works right after install with no slash commands to learn — just say “use reviewer to review this diff”. It ships common roles like scout and reviewer, and supports saved workflows and parallel reviews. Its mesh interface is mesh_run_control: remotely stop or steer a peer’s RPC worker.
5. One rehearsal of the four-piece suite
6. Five minutes to onboard
One line each: mesh and subagents install as pi packages — pi install npm:pi-mesh-extension, pi install npm:pi-subagents; pi-board is not on npm yet — clone, npm ci, npm run build — and it works CLI-only (reading and writing the local board needs no mesh at all); pi-jobd builds from source the same way, with pijob run / list / log / stop working out of the box. Open two pi sessions in one directory and you have two peers visible to each other in mesh_status — “zero config” is not a slogan here.
Conversation over mesh, memory on the board, long work to jobd, exclusivity by lease — four packages, each doing its job, none overstepping. This blog’s redesign was their proving ground: two mesh terminals (op-gitea, op-artalk) ran in parallel with the mainline, nineteen commits in one day; during the publish-chain outage, one lane reserved build.sh for emergency repair while an incoming hotfix edit was correctly blocked by the reservation — collisions are prevented by rule, not by reflex.
Together the four pieces contain no database and no central brain, yet pin down all four questions: who is online, who is doing what, what was learned, and who watches the long jobs. Small tools, hard boundaries, honest states — that philosophy is worth copying more than any individual package.
评论区加载失败。