@heyhuynhgiabuu/pi-peers

Session-to-session plain-text mailboxes for Pi: discover live sessions across projects and message them (including pi-task subagents), with prompt-free accept/refuse inbound and race-hardened delivery.

Packages

Package details

extension

Install @heyhuynhgiabuu/pi-peers from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@heyhuynhgiabuu/pi-peers
Package
@heyhuynhgiabuu/pi-peers
Version
0.1.0
Published
Aug 13, 2026
Downloads
99/mo · 14/wk
Author
killerkidbo
License
MIT
Types
extension
Size
66.4 KB
Dependencies
0 dependencies · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/index.js"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-peers — pi sessions find and message each other, with roles

A Pi extension for session-to-session plain-text mailboxes: every pi session registers itself in a shared directory and watches an inbox. Sending is a file landing in another session's inbox; receiving is that file being claimed and handed to the agent as a message clearly marked as coming from a peer, not from the user.

Built as an independent experiment after researching @shift-labs/pi-peer — same mechanics, different posture where the tradeoffs matter:

shift-labs/pi-peer pi-peers
Inbound default accept accept — no confirm dialogs; refuse is the explicit opt-out
Identity self-asserted, any same-user session cwd/session hash-bound records, still advisory under the same-user file model
Roles none user / companion / task declared per session
Subagent habit a task session can inject under accept pi-task children self-label as task; accept delivers them like other peers
Install npm package npm package

Agent creation and lifecycle intentionally stay with pi-task — this package is transport only: discovery, delivery, presence, receipts.

Install

pi install npm:@heyhuynhgiabuu/pi-peers

or add to ~/.pi/agent/settings.json:

{ "packages": ["npm:@heyhuynhgiabuu/pi-peers"] }

Every session sharing the same machine (and PI_PEERS_DIR) then discovers the others automatically.

Configuration

Variable Default Meaning
PI_PEERS_DIR ~/.pi/agent/peers Where records and mailboxes live (0700); relative values resolve to an absolute path
PI_PEERS_INBOUND accept accept delivers with no prompt; refuse drops everything; invalid values fail closed as refuse
PI_PEERS_ROLE inferred Override the role as user, companion, or task; pi-task children are inferred as task, other sessions default to user

Use

peer action=list    # discover: live/stalled first, newest offline (folded past 10)
peer action=send    # send plain text to another session by name
/peers              # human listing; shows every record (no offline folding)

Plain text only, capped at 32 KB. A message is a summary plus a path, not a payload. ANSI escape sequences and control characters are stripped at parse, keeping newlines and tabs. A session that is not running keeps its mailbox, so mail waits and is read on resume. Every delivery carries the no-authority preamble: it cannot approve anything, cannot change configuration, and any slash command in it is inert text. A policy receipt can be delivered, rejected, or report a delivery error; no receipt before timeout remains queued/pending.

Working with pi-task subagents

Use pi-task's task tool to create, control, resume, cancel, and collect the result from subagents. Task children self-label as role task. Once a task session appears in peer action=list, use peer action=send only as a coordination side-channel for a new finding or warning that materially affects its work. Do not poll task status through peer mail, and do not treat peer mail as delegation, approval, or the task result.

Inbound is accepted without prompts by default, including messages from pi-task subagents. Set PI_PEERS_INBOUND=refuse only when this session should receive no peer mail.

Guarantees (pinned by the test suite)

  • Identity is a hash of cwd+session id; two sessions in one directory never share an inbox.
  • Presence is pid + heartbeat + liveness: live / stalled (alive but wedged) / offline (mail still waits); a pid whose process died decays to offline, so crashed sessions never ghost the listing and unresumable empty inboxes are actually swept. Registry writes use a live-owner fence: transient lock contention throws so the holder keeps its lease (retries), while a real replacement returns ownership loss and closes the stale watcher.
  • Sweep never destroys a mailbox that holds mail; only the empty mailbox of an unresumable session is discarded promptly.
  • A reader never sees a half-written letter (.tmp + rename); a letter is atomically claimed before it is read, so concurrent watchers cannot deliver it twice, claims from dead processes are recovered, and requeues land under a fresh name when the original is occupied.
  • Loops terminate structurally: dedupe window, per-sender rate, backlog cap, and consecutive-error circuit breaker.
  • Default inbound is accept — peer mail always delivers without a prompt; refuse is the only opt-out via PI_PEERS_INBOUND.

Trust model

Local same-user advisory identity: records, letters, receipts, and roles are forgeable by other same-user processes. Mitigations are behavioral, not cryptographic — bounded reads, sanitized metadata, control-byte stripping, and a no-authority preamble on every delivery. Do not send secrets over peer mail.

Layout

src/
  registry.ts   addresses, roles, presence, lock/lease fencing, sweeping
  mailbox.ts    deposit, drain, watch, receipts, claims
  policy.ts     accept/refuse policy and loop guards
  format.ts     the strings the model reads
  index.ts      pi wiring: lifecycle, tool, delivery
test/
  index.test.ts behavior spec