@getpipher/armory-mesh

extensionmaintained

Hardened peer-to-peer mesh for pi agents — live presence, work claims, cross-session duplicate checks, and a durable fleet memory for N parallel sessions. Signed + secured by default.

by — · v0.1.3 · published 4w ago

$ pi install npm:@getpipher/armory-mesh
downloads/mo
654
stars
0
last push
4w ago
open issues
0

Signals

license: MITtestspi manifest: missinginstall size: —deps: 0peer deps: 0

Download trend

No downloads in the last 12 weeks.

README

armory-mesh

Your AI agents work in parallel. Now they can work together.

A hardened peer-to-peer mesh for pi coding-agent sessions — live presence, atomic work claims, cross-session duplicate checks, and a durable fleet memory. Signed and secured by default.

npm CI tests License: MIT

Two pi sessions in a shared pool: hunter-alpha claims gmtrade and banks a finding; hunter-beta's claim is rejected and its dup-check comes back with an instant overlap match.

Real output from two live sessions in a shared pool. Zero config on one machine; one small hub process for cross-machine.


The problem

Every pi session is an isolated process. Run three in parallel — three bug-bounty hunts, three features, three refactors — and they're strangers: they duplicate each other's work, forget what the others learned, and die with their knowledge.

armory-mesh gives them a shared nervous system:

  • Presence — each session sees the fleet live: who's running, on what model, how much context is left, what they're claiming. A session that dies is evicted automatically — no ghosts.
  • Claims — atomic work claims (mesh_claim_target) so two sessions never hunt the same target. A losing claimant is told no, and who holds it.
  • Duplicate checks — mesh_dup_check sweeps the pool: "has anyone seen this bug?" Every peer answers from its ledger in seconds. An overlap reply is a duplicate submission saved.
  • Durable memory — findings banked at 02:00 with nobody online are replayed to whoever joins at 09:00. The fleet-state ledger (fleet-state.jsonl) survives every session.

Quickstart

# user scope — available in every project, no trust prompt
pi install npm:@getpipher/armory-mesh

# or project scope — lives in .pi/settings.json, shared with the repo;
# pi auto-installs it on next start once you trust the project
pi install -l npm:@getpipher/armory-mesh

# a local checkout works too
pi install /path/to/armory-mesh

The npm: prefix is required — a bare package name parses as a local path and fails.

Then fire your sessions. Each one prints the join line and grows a live fleet widget below the editor:

📡 mesh: joined "my-project" as agent-2cc1e9
mesh bug-bounty-fleet · 6 peers
  gmtrade-audit   glm-5.3-flash  ctx:34%  ⟨gmtrade⟩  1s
  veilo-recon     glm-5.3-flash  ctx:10%             1s
  hunter-3        glm-5.3-flash  ctx:67%             0s
  … +3 more peers

Presence updates every 2 seconds (name, model, live context-window usage, claimed target, last-seen). The widget collapses past PI_MESH_WIDGET_MAX_ROWS (default 10), most-recently-active first.

Running a session you don't want in the mesh at all? PI_MESH_OFF=1 pi … — the package stays installed, but that session registers no mesh surface (no tools, no widget, no socket, no key).

Who can see whom: a session joins the pool named by — in order of precedence — the PI_MESH_PROJECT env var, a .pi/mesh.json anywhere up its folder tree, or its working folder's basename. Same pool = visible to each other. Different pool = complete strangers. Knowledge itself only moves when a session calls a tool — presence metadata (heartbeats) is the only automatic traffic.

The tools (injected into every session)

ToolWhat it does
mesh_listLive peers: name, model, host, context usage, claimed target, last-seen
mesh_sendSend a typed message to a peer or a channel
mesh_get / mesh_awaitPull (fire-and-forget) or block for matching messages
mesh_claim_target / mesh_release_targetAtomic work claims (filesystem-lock) — stale claims from dead sessions are auto-reclaimable
mesh_bank_findingAnnounce + permanently persist a finding
mesh_dup_check"Has anyone seen this?" — every peer answers from its ledger in seconds
mesh_handoffPublish a resume pointer for the next session
mesh_fleet_stateRead the durable ledger (claims, findings, dup-checks, handoffs)
mesh_channelsChannels + live subscriber counts

Slash commands for the human at the keyboard: /mesh (pool status) and /mesh doctor (full install + runtime diagnostics — wiring, trust, key, transport, peers, claims, ledger).

The workflow it enables

  1. Claim before you start — mesh_claim_target("gmtrade"). A duplicate claimant is told no, and who holds it.
  2. Bank at milestones — mesh_bank_finding(...) writes through to fleet-state.jsonl and broadcasts on #dup-check. Even with zero peers online, it's durable.
  3. Check before you submit — mesh_dup_check(...) sweeps the fleet. An overlap reply is a duplicate submission saved.
  4. Handoff on exit — mesh_handoff(...) so the next session resumes instead of restarting.

How it works

Machine 1: three sessions on Unix sockets, peer-to-peer signed frames, durable fleet-state ledger; machine 2: two hub-mode sessions; hub in the middle relaying over HTTP+SSE without ever seeing the project key.
  • Same machine: each session listens on a private Unix socket (~/.pi/mesh/<project>/sockets/<id>.sock, 0600). Sending = connect → write one length-prefixed JSON frame → ack → close.
  • Cross-machine: a small hub relays over HTTP + SSE.
  • Unreachable peer? Mesh relay: a peer that can reach the destination forwards the frame — with a visited-set + hop-count so loops are impossible.
  • Persistence: senders write through to per-channel logs (local: shared ndjson; hub: a disk-backed store under ~/.pi/mesh/ that survives hub restarts) — the durable ledger (fleet-state.jsonl) is always written.

Security (by default, even on localhost)

  • Project key — 32 random bytes per pool (~/.pi/mesh/<project>/key, 0600). Every message is HMAC-SHA256 signed over a canonical encoding; receivers verify with a timing-safe compare and drop forgeries.
  • Replay protection — per-sender monotonic nonces; a captured frame can't be re-injected.
  • Hub LAN gate — the hub requires its own token and never sees the project key; it's a dumb relay, messages stay end-to-end signed.
  • Flood caps — per-message size cap (256 KB), per-channel rate cap (10 msg/s), bounded queues.
  • Full threat model + residual risks: SECURITY.md.

Cross-machine: the hub

# machine A — the hub (one process, no deps)
PI_MESH_AUTH_TOKEN=<secret> PI_MESH_HUB_PORT=7399 npx jiti src/hub.ts

# machine B — point sessions at it (and copy the project key across)
PI_MESH_HUB_URL=http://<A>:7399 PI_MESH_AUTH_TOKEN=<same-secret> pi

The hub holds the cross-machine registry, relays messages, and keeps bounded per-channel history for late-joiner replay — on disk, so a hub restart no longer wipes the catch-up history (PI_MESH_STORE_PATH to relocate, =off for memory-only). Clients fail over automatically across PI_MESH_HUB_URLS (comma-separated) if the primary dies — and a reconnect back-fills exactly the messages missed while the stream was down (proven by the reconnect smoke). Run the hub on infrastructure you trust; terminate TLS in front of it if it leaves the LAN.

Project-scoped pools

Drop a .pi/mesh.json at any workspace root and every session fired under it joins the same pool — regardless of which subfolder it was launched from:

{
  "project": "my-fleet",
  "persistChannels": ["#dup-check", "#handoff", "#general", "#learnings"]
}

Precedence: PI_MESH_PROJECT env → nearest .pi/mesh.json → folder basename.

Configuration (env)

VariableDefaultMeaning
PI_MESH_OFF—Per-session opt-out: 1/true/yes/on → this session registers no mesh surface (package stays installed)
PI_MESH_PROJECTfolder basenamePool id
PI_MESH_AGENT_NAMErandomReadable name in the widget
PI_MESH_HUB_URL / PI_MESH_HUB_URLS—Hub endpoint(s) — cross-machine mode
PI_MESH_AUTH_TOKEN—Required for hub mode
PI_MESH_STORE_PATH~/.pi/mesh/hub-store.ndjsonHub replay store (set off for memory-only)
PI_MESH_PING_MS / PI_MESH_EVICTION_MISSES2000 / 5Heartbeat interval / eviction window
PI_MESH_MAX_MESSAGE_BYTES262144Per-message cap
PI_MESH_CHANNEL_RATE_PER_SEC10Per-channel send-rate cap
PI_MESH_MAX_HOPS8Mesh-relay hop limit
PI_MESH_WIDGET_MAX_ROWS10Pool-widget peer rows before collapsing into "… +K more"
PI_MESH_PERSIST_CHANNELS#dup-check,#handoff,#generalChannels with durable logs

Why not just use coms?

coms (disler) pioneered peer-to-peer pi messaging — armory-mesh is the hardened evolution.

comsarmory-mesh
Pool sizeN peersN peers (bounded relay + caps)
Auth—project key + HMAC-signed frames, even on localhost
Replay protection—monotonic nonces, timing-safe verify
Livenesskeepalive pingssigned heartbeat gossip + auto-eviction (no ghosts)
Messagestext linestyped messages + subscription-scoped channels
Persistence—send-through logs + late-joiner replay + durable fleet ledger
Fleet primitives—claim / bank / dup-check / handoff, built in
Cross-machineseparate codepathunified transport: sockets ↔ hub, with failover + relay
Abuse limitsline cap256 KB per-message + 10 msg/s per-channel caps + mesh relay loop prevention

coms is a great chat wire; armory-mesh is a fleet operating layer.

Status

🚀 v0.1.x — built and hardened through 12 smoke-tested suites (transport, liveness, channels, persistence, fleet-state, hub, relay/failover/replay, hardening, wiring, diagnostics, reconnect), running in a live multi-session security-hunting fleet. API may still shift before 1.0.

License

MIT