{"_id":"@diegopetrucci/pi-intercom","_rev":"4-84e534ec84a17c47d74d5ebaee5fa660","name":"@diegopetrucci/pi-intercom","dist-tags":{"latest":"0.8.0"},"versions":{"0.6.1":{"name":"@diegopetrucci/pi-intercom","version":"0.6.1","keywords":["pi-package"],"license":"MIT","_id":"@diegopetrucci/pi-intercom@0.6.1","maintainers":[{"name":"diegopetrucci","email":"baulei@icloud.com"}],"homepage":"https://github.com/diegopetrucci/pi-intercom#readme","bugs":{"url":"https://github.com/diegopetrucci/pi-intercom/issues"},"pi":{"skills":["./skills"],"extensions":["./index.ts"]},"dist":{"shasum":"78ae40d104806d27c283b1483a1e5858f9699199","tarball":"https://registry.npmjs.org/@diegopetrucci/pi-intercom/-/pi-intercom-0.6.1.tgz","fileCount":19,"integrity":"sha512-lri24b1oEBd85IxhfFbQfK2uXMdrqlpxmVgfqOgrDcbiCTKDkBe7onc4mso9KN4bfdpgmmS6jTxNm02oORTEHw==","signatures":[{"sig":"MEQCIBblbtMSDZ12QDYwKKECWDA2p9O9YYIZDLch+lQ+9k6RAiB7x2zbTXxsE9kPgw734wU1tIg09TeHo/64mWnfHdKccQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":198830},"main":"index.ts","type":"module","gitHead":"685b7627fbebbbbf853bdf7d6472dd523cf4146a","scripts":{"test":"tsx --test broker/paths.test.ts broker/spawn.test.ts profile.test.ts reply-tracker.test.ts intercom.integration.test.ts test/inline-message.test.ts"},"_npmUser":{"name":"diegopetrucci","email":"baulei@icloud.com"},"repository":{"url":"git+https://github.com/diegopetrucci/pi-intercom.git","type":"git"},"_npmVersion":"11.17.0","description":"Local session-to-session intercom extension for Pi coding agent and tlh workflows.","directories":{},"_nodeVersion":"26.4.0","dependencies":{"tsx":"^4.20.0","typebox":"^1.1.24"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@mariozechner/pi-tui":"*","@mariozechner/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/pi-intercom_0.6.1_1782765756535_0.6886323838018442","host":"s3://npm-registry-packages-npm-production"}},"0.6.2":{"name":"@diegopetrucci/pi-intercom","version":"0.6.2","keywords":["pi-package"],"license":"MIT","_id":"@diegopetrucci/pi-intercom@0.6.2","maintainers":[{"name":"diegopetrucci","email":"baulei@icloud.com"}],"homepage":"https://github.com/diegopetrucci/pi-intercom#readme","bugs":{"url":"https://github.com/diegopetrucci/pi-intercom/issues"},"pi":{"skills":["./skills"],"extensions":["./index.ts"]},"dist":{"shasum":"559fb6a71627f4853a7570ff88a58c43a6ea3881","tarball":"https://registry.npmjs.org/@diegopetrucci/pi-intercom/-/pi-intercom-0.6.2.tgz","fileCount":19,"integrity":"sha512-0OWS/LR3dGPkmJx/jN46K+NPWHvYDuKIGEDpBOboLlTwkrfZp4LlbCyFrDRGCmySQjtCXYJzEjoPOXW1nrT1mw==","signatures":[{"sig":"MEYCIQCdvGTjrREvNtj81gugbit0V8fDwk97rFTlRv8PVB88JAIhAOsUuSKBnWsO6q4+bS/bDUJSQPdRVx+Ej2fuimnzTAIC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":199085},"main":"index.ts","type":"module","gitHead":"4a46542ae981c477958e62e3dd873681a3a0ea35","scripts":{"test":"tsx --test broker/paths.test.ts broker/spawn.test.ts profile.test.ts reply-tracker.test.ts intercom.integration.test.ts test/inline-message.test.ts"},"_npmUser":{"name":"diegopetrucci","email":"baulei@icloud.com"},"repository":{"url":"git+https://github.com/diegopetrucci/pi-intercom.git","type":"git"},"_npmVersion":"11.17.0","description":"Local session-to-session intercom extension for Pi coding agent and tlh workflows.","directories":{},"_nodeVersion":"26.4.0","dependencies":{"tsx":"^4.20.0","typebox":"^1.1.24"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@mariozechner/pi-tui":"*","@mariozechner/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/pi-intercom_0.6.2_1782848924369_0.8203314562794293","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@diegopetrucci/pi-intercom","version":"0.7.0","keywords":["pi-package"],"license":"MIT","_id":"@diegopetrucci/pi-intercom@0.7.0","maintainers":[{"name":"diegopetrucci","email":"baulei@icloud.com"}],"homepage":"https://github.com/diegopetrucci/pi-intercom#readme","bugs":{"url":"https://github.com/diegopetrucci/pi-intercom/issues"},"pi":{"skills":["./skills"],"extensions":["./index.ts"]},"dist":{"shasum":"6c019f8b087a96db04c107cbc85248e8a853d547","tarball":"https://registry.npmjs.org/@diegopetrucci/pi-intercom/-/pi-intercom-0.7.0.tgz","fileCount":19,"integrity":"sha512-RG8bYR/s/9bU0kSwgIoEEWd59G6o9PtPM/DRlPvwTUz3GQc0CavV5Ef7ltmGItukDax2bGW3nvAcaDi4F3KcsA==","signatures":[{"sig":"MEQCIFN/bq12l4cmLa4Zaej4RH2gCQwP+2nV766JyoTuj1YnAiAaa645fJRUYC14m4g73SiLRpak2DRi1XP4wkKF8nO54w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@diegopetrucci%2fpi-intercom@0.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":200117},"main":"index.ts","type":"module","gitHead":"5be6f69f3ce230dedbd19287dfd421d6857ad5d0","scripts":{"test":"tsx --test broker/paths.test.ts broker/spawn.test.ts profile.test.ts reply-tracker.test.ts intercom.integration.test.ts test/inline-message.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:595c32aa-7618-4bda-82bf-8f3c5f2842bf"}},"repository":{"url":"git+https://github.com/diegopetrucci/pi-intercom.git","type":"git"},"_npmVersion":"11.16.0","description":"Local session-to-session intercom extension for Pi coding agent and tlh workflows.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"tsx":"^4.20.0","typebox":"^1.1.24"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@mariozechner/pi-tui":"*","@mariozechner/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/pi-intercom_0.7.0_1783545073621_0.7143593193181177","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@diegopetrucci/pi-intercom","version":"0.8.0","description":"Local session-to-session intercom extension for Pi coding agent and tlh workflows.","license":"MIT","type":"module","main":"index.ts","scripts":{"test":"tsx --test broker/paths.test.ts broker/spawn.test.ts profile.test.ts reply-tracker.test.ts intercom.integration.test.ts test/inline-message.test.ts"},"keywords":["pi-package"],"repository":{"type":"git","url":"git+https://github.com/diegopetrucci/pi-intercom.git"},"publishConfig":{"access":"public"},"pi":{"extensions":["./index.ts"],"skills":["./skills"]},"peerDependencies":{"@mariozechner/pi-coding-agent":"*","@mariozechner/pi-tui":"*"},"dependencies":{"tsx":"^4.20.0","typebox":"^1.1.24"},"gitHead":"10137fc83a26f62f259454e957864000363962f1","_id":"@diegopetrucci/pi-intercom@0.8.0","bugs":{"url":"https://github.com/diegopetrucci/pi-intercom/issues"},"homepage":"https://github.com/diegopetrucci/pi-intercom#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-sbyBb5jtrVkIVaAqWroaqVg/eeWy8+LNiIc7IYBtxxsMAmPTH82IbAtrBcOFUpPYQRXPGOTbf49bY4+/k942BA==","shasum":"340a93480585d32f25cc820daf8f385420342502","tarball":"https://registry.npmjs.org/@diegopetrucci/pi-intercom/-/pi-intercom-0.8.0.tgz","fileCount":19,"unpackedSize":205630,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@diegopetrucci%2fpi-intercom@0.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAY50yPlOC1xzdtPMBk3CnbVEnzc3N0hZP1tGeDKDsHnAiEAq4c5pu/SpzJ9zUDMoZFuO3d3LZOJnCkSEUCWkxFGDBc="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:595c32aa-7618-4bda-82bf-8f3c5f2842bf"}},"directories":{},"maintainers":[{"name":"diegopetrucci","email":"baulei@icloud.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-intercom_0.8.0_1784038116397_0.17370576101454005"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-29T20:42:36.359Z","modified":"2026-07-14T14:08:36.813Z","0.6.1":"2026-06-29T20:42:36.721Z","0.6.2":"2026-06-30T19:48:44.513Z","0.7.0":"2026-07-08T21:11:13.765Z","0.8.0":"2026-07-14T14:08:36.538Z"},"bugs":{"url":"https://github.com/diegopetrucci/pi-intercom/issues"},"license":"MIT","homepage":"https://github.com/diegopetrucci/pi-intercom#readme","keywords":["pi-package"],"repository":{"type":"git","url":"git+https://github.com/diegopetrucci/pi-intercom.git"},"description":"Local session-to-session intercom extension for Pi coding agent and tlh workflows.","maintainers":[{"name":"diegopetrucci","email":"baulei@icloud.com"}],"readme":"<p>\n  <img src=\"banner.png\" alt=\"pi-intercom\" width=\"1100\">\n</p>\n\n# Pi Intercom\n\nDirect 1:1 messaging between pi sessions on the same machine. Send context, findings, or requests from one session to another — whether you're driving the conversation or letting agents coordinate.\n\n> TLH fork note: this fork exists to serve **The Last Harness (tlh)**, where tlh automation bundles and pins this package version on purpose. It is maintained as a TLH compatibility fork, not as a general standalone distribution target outside that tlh use.\n\n```text\nUser flow: press Alt+M or run /intercom to pick a session and send a message\n```\n\n## Why\n\nSometimes you're running multiple pi sessions — one researching, one executing, one reviewing. Pi-intercom lets you:\n\n- **User-driven orchestration** — Send context or findings from your research session to your execution session\n- **Agent collaboration** — An agent can reach out to another session when it needs help or wants to share results\n- **Session awareness** — See what other pi sessions are running and their current status\n\nUnlike pi-messenger (a shared chat room for multi-agent swarms), pi-intercom is for targeted 1:1 communication where you pick the recipient.\n\nPi-intercom also integrates well with [pi-subagents](https://github.com/nicobailon/pi-subagents). Modern `pi-subagents` provides native child-to-supervisor tooling. For compatibility, pi-intercom's `full` surface still registers its legacy `contact_supervisor` implementation when child bridge metadata is present; `bridge` omits that duplicate and relies on native `pi-subagents` supervision. Normal sessions never receive the child-only tool.\n\n## In One Minute\n\nEach pi session that has `pi-intercom` loaded, `enabled`, and a non-`off` surface connects to a tiny local broker over a local IPC transport. In the default `full` surface, the extension gives you both a tool (`intercom`) and a small overlay UI (`/intercom` or `Alt+M`). In `bridge`, it keeps the broker/runtime path needed for subagent rich-result and control relays but omits the local intercom tool and pi-intercom's compatibility supervisor tool. Incoming messages are rendered inline inside the recipient session, can trigger a turn immediately, and are also stored in Pi session history as extension entries.\n\n## Install\n\n```bash\npi install npm:@diegopetrucci/pi-intercom\n```\n\nThen restart Pi. The extension auto-connects to the broker on startup and registers the bundled `pi-intercom` skill for common coordination patterns.\n\nIf you're using The Last Harness (tlh), keep using the version bundled or explicitly pinned by tlh automation rather than treating this fork as a generally floating standalone install target.\n\nFor The Last Harness (tlh), pin the exact fork version instead of relying on an unpinned install:\n\n```bash\npi install npm:@diegopetrucci/pi-intercom@0.6.2\n```\n\n**Recommended:** Add this snippet to your project's `AGENTS.md` to help agents understand when to coordinate across sessions:\n\n```xml\n<pi-intercom>\nCoordinate with other local pi sessions on related codebases. Use `/skill:pi-intercom` for patterns.\n\n**When:** Same codebase (parallel work), reference codebase (consulting patterns), related repos (shared libraries).\n\n**Not when:** Unrelated codebases, trivial questions, or when you can proceed independently.\n\n**Principle:** Prefer `send` for notifications; `ask` only when blocked waiting for input.\n</pi-intercom>\n```\n\nA session becomes intercom-connected when all of these are true:\n- the `pi-intercom` extension is installed and loaded in that session\n- `enabled` is not set to `false` in `$PI_CODING_AGENT_DIR/intercom/config.json` (defaults to `~/.pi/agent/intercom/config.json`)\n- the effective surface is not `off`\n- the session has started or reloaded after the extension was installed\n- the local broker is running or can be auto-started\n\nFor tlh migrations, `PI_INTERCOM_SURFACE` is the intended temporary runtime override because it changes the exposed surface without rewriting user-owned `config.json`.\n\nThe session list only shows intercom-connected sessions, not every open Pi process on the machine.\n\nIf a session is unnamed, pi-intercom now exposes a runtime-only fallback alias like `subagent-chat-1a2b3c4d` so other sessions can still target it. That alias is not persisted as the Pi session title, so `pi --resume` can keep showing the transcript snippet instead of a generic `session-...` name.\n\n## Quick Start\n\n### From the Keyboard\n\nPress **Alt+M** or type `/intercom` to open the session list overlay:\n\n1. **Select a session** — Use arrow keys to pick a target session\n2. **Compose message** — Write your message in the compose overlay\n3. **Send** — Press Enter to send, Escape to cancel\n\n### From the Agent\n\nThe agent can list sessions and send messages using the `intercom` tool. Tool calls and results render as compact transcript rows so send/ask/reply flows are easy to scan. For common patterns like planner-worker delegation, the bundled `pi-intercom` skill provides copy-paste ready examples:\n\n```typescript\n// List active sessions\nintercom({ action: \"list\" })\n// → **Current session:**\n// → • executor (20d43841) — ~/projects/api (claude-sonnet-4) [self, idle]\n// → **Other sessions:**\n// → • research (6332faab) — ~/projects/api (claude-sonnet-4) [same cwd, thinking]\n\n// Send a message\nintercom({ action: \"send\", to: \"research\", message: \"Check if UserService.validate() handles null\" })\n// → Message sent to research\n\n// Check connection status\nintercom({ action: \"status\" })\n// → Connected: Yes, Session ID: abc123, Active sessions: 3\n\n// Send with attachments (code snippets, files, or context)\nintercom({\n  action: \"send\",\n  to: \"worker\",\n  message: \"Here's the fix:\",\n  attachments: [{\n    type: \"snippet\",\n    name: \"auth.ts\",\n    language: \"typescript\",\n    content: \"function validate(user: User) { ... }\"\n  }]\n})\n```\n\n### Receiving Messages\n\nWhen a message arrives, it appears inline in your chat with the sender's info and a reply hint:\n\n```\n**From research** (~/projects/api)\n\nTo reply, use the intercom tool: intercom({ action: \"reply\", message: \"...\" })\n\nFound the issue — UserService.validate() doesn't check for null input.\nSee auth.ts:142-156.\n```\n\nThe reply hint (enabled by default) points to `intercom({ action: \"reply\", ... })`, so recipients do not need raw sender or `replyTo` IDs. Idle recipients get a new turn immediately; busy interactive recipients receive the message once they go idle. Attachment content is included in the agent-visible body, and messages are rendered inline and stored in Pi session history.\n\n## Workflow: Planner-Worker Coordination\n\nThe most natural use of pi-intercom is splitting a task between two sessions — one holds the big picture, the other does the hands-on work. When the worker hits an ambiguity (\"should I optimize for readability or performance here?\"), they ask without losing context.\n\n### Setup\n\nOpen two terminals and start pi in each. Name them so they can find each other:\n\n```\n# Terminal 1                    # Terminal 2\n/name planner                   /name worker\n```\n\nVerify they see each other from either session:\n\n```typescript\nintercom({ action: \"list\" })\n// → • worker — ~/projects/api (claude-sonnet-4) [idle]\n```\n\n### The Conversation\n\nHere's how a typical exchange looks. The planner delegates with `send` (fire-and-forget). The worker uses `ask` for anything that needs a response — questions, discoveries, completion reports. `ask` sends the message and blocks until the planner replies, so the worker gets the answer as a tool result and continues in the same turn.\n\n**Planner sends a task:**\n```typescript\nintercom({\n  action: \"send\",\n  to: \"worker\",\n  message: \"Task-3: Add retry logic to API client. Key files: src/api/client.ts, src/api/types.ts. Ask if anything's unclear.\"\n})\n```\n\n**Worker hits an ambiguity — asks and waits:**\n```typescript\nintercom({\n  action: \"ask\",\n  to: \"planner\",\n  message: \"Should retry apply to all endpoints or just idempotent ones? Also, max retry count and backoff strategy?\"\n})\n// → Reply from planner: Only GET/PUT/DELETE — never POST. Max 3 retries, exponential backoff starting at 100ms.\n// Worker continues implementing with the answer, same turn, full context.\n```\n\n**Worker finds something unexpected — escalates and waits:**\n```typescript\nintercom({\n  action: \"ask\",\n  to: \"planner\",\n  message: \"Found: fetchWithTimeout swallows network errors. Fixing this changes the error shape. OK to proceed?\"\n})\n// → Reply from planner: Yes, surface the error types. The current behavior is a bug.\n```\n\n**Worker reports completion:**\n```typescript\nintercom({\n  action: \"ask\",\n  to: \"planner\",\n  message: \"Task-3 done. Added RetryPolicy type, applied to GET/PUT/DELETE, surfaced NetworkError, 4 tests passing.\"\n})\n// → Reply from planner: Looks good. Move on to task-4.\n```\n\n### Communication Patterns\n\n| Pattern | Action | Why |\n|---------|--------|-----|\n| **Task Delegation** | Planner uses `send` | Fire-and-forget. Planner doesn't need to wait for an ack. |\n| **Clarification Request** | Worker uses `ask` | Worker needs the answer to proceed. Blocks until reply. |\n| **Discovery Escalation** | Worker uses `ask` | Worker needs approval before changing course. |\n| **Completion Report** | Worker uses `ask` | Planner might have follow-up instructions or the next task. |\n\n### Reply Hints\n\nWhen `replyHint` is enabled (the default), incoming messages include the exact `intercom()` call to respond:\n\n```\n**From planner** (~/projects/api)\n\nTo reply, use the intercom tool: intercom({ action: \"reply\", message: \"...\" })\n\nOnly GET/PUT/DELETE — never POST. Max 3 retries with exponential backoff starting at 100ms.\n```\n\nThis matters because the agent receiving the message doesn't need to reconstruct raw `to` and `replyTo` IDs — the hint is right there. Combined with idle-gated `triggerTurn` delivery, it enables real back-and-forth conversation without interrupting work in progress. If the reply happens later instead of in the triggered turn, `intercom({ action: \"reply\" })` falls back to the single unresolved inbound ask, and `intercom({ action: \"pending\" })` shows who is still waiting.\n\n### `send` vs `ask`\n\n`send` is fire-and-forget — the tool returns immediately after delivery. By default, it sends immediately even in interactive sessions. If you want an approval dialog before non-reply sends, set `confirmSend: true` in config. Replies that include `replyTo` still skip confirmation so reply-hint flows can continue without an extra approval step.\n\n`ask` sends the message and blocks until the recipient responds (2-minute timeout by default). The reply comes back as the tool result, so the agent continues in the same turn with full context. No confirmation dialog — if you're asking and waiting, the intent is clear.\n\n`reply` is receiver-side sugar for replying to an inbound ask. In the turn triggered by an incoming intercom ask, `intercom({ action: \"reply\", message: \"...\" })` targets that exact sender and message automatically. If you reply later, it falls back to the single unresolved inbound ask. If multiple asks are pending, use `intercom({ action: \"pending\" })` to inspect them and then call `reply` with `to` to disambiguate.\n\nThe planner typically uses `send`. If you prefer manual approval for outgoing non-reply messages, turn on `confirmSend: true`. The worker uses `ask` for everything (no confirmation needed, gets answers inline), so it can operate autonomously either way.\n\n## Workflow: Subagent-to-Supervisor Escalation\n\nThis workflow requires [`pi-subagents`](https://github.com/nicobailon/pi-subagents). Modern `pi-subagents` owns and provides native child-to-supervisor supervision. In `full` mode, pi-intercom also retains its legacy/compatibility `contact_supervisor` implementation when child bridge metadata is present; this sits alongside the regular `intercom` tool. In `bridge` mode, pi-intercom deliberately omits that duplicate and relies on the native `pi-subagents` supervisor tool. Normal sessions never receive a child-only `contact_supervisor` tool.\n\nThe temporary `bridge` surface remains responsible only for rich subagent result/control delivery compatibility during tlh migration work. It does not replace or provide native supervisor tooling.\n\n### When pi-intercom's Compatibility Tool Appears\n\nIn `full` mode, pi-intercom's compatibility `contact_supervisor` registers when `pi-subagents` sets all of these environment variables:\n\n- `PI_SUBAGENT_ORCHESTRATOR_TARGET` — the supervisor session name or ID\n- `PI_SUBAGENT_RUN_ID` — the run identifier\n- `PI_SUBAGENT_CHILD_AGENT` — the agent type\n- `PI_SUBAGENT_CHILD_INDEX` — the child index within the run\n\nIf any are missing, pi-intercom does not register its compatibility `contact_supervisor`; in `full` mode its regular `intercom` tool remains available. This condition does not describe registration of modern `pi-subagents`' native supervisor tool.\n\n### Foreground vs Async Child Sessions\n\nBlocking supervisor contact requires a live reply path. `pi-subagents` async/background launches provide that path, so `need_decision` and `interview_request` can wait for your reply. Foreground launches mark the reply path unavailable instead: blocking asks fail fast before any intercom message is sent, while `progress_update` and other non-blocking sends still work.\n\nIf you expect a child to need decisions while it is running, launch it async/background. If a foreground child still gets blocked, have it return the blocker in its final result instead of trying to wait through `contact_supervisor` or `intercom({ action: \"ask\" })`.\n\n### Three Reasons\n\n| Reason | Behavior | Use When |\n|--------|----------|----------|\n| `need_decision` | Sends an ask and blocks until the supervisor replies (2-minute timeout by default) | The subagent is blocked, uncertain, needs approval, or faces a product/API/scope decision |\n| `interview_request` | Sends structured questions and blocks until the supervisor replies (2-minute timeout by default) | The subagent needs multiple machine-readable answers from the supervisor in one exchange |\n| `progress_update` | Fire-and-forget update to the supervisor | Meaningful progress or unexpected discoveries that change the plan |\n\nDo not use `contact_supervisor` for routine completion handoffs. Return the final subagent result normally through `pi-subagents`.\n\n### Example: Blocked Subagent Asks for Guidance\n\n```typescript\ncontact_supervisor({\n  reason: \"need_decision\",\n  message: \"The auth service returns 403 instead of 401 for expired tokens. Should I treat 403 as a re-auth trigger or a hard failure?\"\n})\n// → Reply from supervisor: Treat 403 as re-auth trigger. Update the token refresh logic.\n```\n\n### Example: Structured Supervisor Interview\n\n```typescript\ncontact_supervisor({\n  reason: \"interview_request\",\n  message: \"Please answer these before I continue the migration.\",\n  interview: {\n    title: \"API migration choices\",\n    questions: [\n      { id: \"api\", type: \"single\", question: \"Which API should I target?\", options: [\"Stable API\", \"Experimental API\"] },\n      { id: \"constraints\", type: \"text\", question: \"What constraints should I preserve?\" }\n    ]\n  }\n})\n// → Reply from supervisor: { \"responses\": [{ \"id\": \"api\", \"value\": \"Stable API\" }, ...] }\n```\n\n### Example: Progress Update\n\n```typescript\ncontact_supervisor({\n  reason: \"progress_update\",\n  message: \"Discovered the bug is in the retry wrapper, not the API client. Fixing the wrapper will also close issue #42.\"\n})\n// → Progress update sent to supervisor planner\n```\n\n### What the Supervisor Sees\n\nThe supervisor receives a formatted message with run metadata:\n\n```\n**From subagent-worker-78f659a3-1**\n\nSubagent needs a supervisor decision.\nRun: 78f659a3\nAgent: worker\nChild index: 0\n\nWhich API should I use?\n```\n\nReply hints work the same as regular `intercom` ask/reply flows. The supervisor can reply with `intercom({ action: \"reply\", message: \"...\" })` and the subagent receives the answer as the tool result. If the child completes or disconnects before you reply, the pending ask expires and `pending`/`reply` tell you to use the completed child session or artifact path for follow-up instead of sending into a dead session.\n\nFor `interview_request`, the supervisor message includes the structured questions plus a fenced JSON answer example using this stable shape:\n\n```json\n{\n  \"responses\": [\n    { \"id\": \"api\", \"value\": \"Stable API\" },\n    { \"id\": \"constraints\", \"value\": \"Keep the public error shape unchanged.\" }\n  ]\n}\n```\n\nThe supervisor can reply with plain JSON or a fenced `json` block. If the reply matches the `{ \"responses\": [...] }` shape and references valid question ids/options, the child tool result includes it in `details.structuredReply` while still showing the raw reply text.\n\n## Tool Reference\n\n### intercom\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `action` | string | `\"list\"`, `\"send\"`, `\"ask\"`, `\"reply\"`, `\"pending\"`, or `\"status\"` |\n| `to` | string | Target session name or ID (for send/ask, or to disambiguate reply) |\n| `message` | string | Message text (for send/ask/reply) |\n| `attachments` | array | Optional `file`, `snippet`, or `context` attachments |\n| `replyTo` | string | Optional message ID for threading or replying to an `ask` |\n\n### contact_supervisor\n\nModern `pi-subagents` provides the native supervisor tool. Pi-intercom registers the compatibility implementation documented below only in `full`-surface sessions where `pi-subagents` supplied the required child bridge metadata; `bridge` omits it to avoid duplicating the native tool. It contacts the supervisor session that delegated the current task.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `reason` | string | `\"need_decision\"` (blocking), `\"interview_request\"` (blocking structured questions), or `\"progress_update\"` (fire-and-forget) |\n| `message` | string | The decision request, optional interview note, or progress update |\n| `interview` | object | Required for `interview_request`: `{ title?, description?, questions: [...] }` |\n\n**`need_decision`** — Sends a formatted ask to the supervisor and blocks until it replies (2-minute timeout by default) when the child has a live reply path. Async/background subagents get that live path; foreground children fail fast here and should return blockers in their final result instead. Includes run metadata in the message so the supervisor knows which subagent is asking.\n\n**`interview_request`** — Sends a formatted, agent-readable interview to the supervisor and blocks until it replies (same 2-minute default timeout) when the child has a live reply path. Foreground children fail fast here just like `need_decision`, so they should report blockers in their final result instead of waiting. Questions use a local pi-interview-like shape: `{ id, type, question, options?, context? }` where `type` is `single`, `multi`, `text`, `image`, or `info`. `info` questions are context-only and do not need responses. The supervisor reply should be JSON with `{ \"responses\": [{ \"id\": \"...\", \"value\": ... }] }`. Parsed JSON replies are returned in `details.structuredReply`.\n\n**`progress_update`** — Sends a non-blocking update to the supervisor. Returns immediately after delivery. Use only for meaningful progress or unexpected discoveries that change the plan.\n\n### intercom actions\n\n**`list`** — Returns the current session plus other active intercom-connected sessions with name, short ID, working directory, model, and live status. Status is derived automatically from Pi lifecycle events: `idle`, `thinking`, or `tool:<name>`.\n\n**`send`** — Sends a message to the specified session. By default it sends immediately, including in interactive sessions. Set `confirmSend: true` in config if you want a confirmation dialog for non-reply sends. Replies that include `replyTo` skip confirmation. Returns delivery confirmation.\n\n**`ask`** — Sends a message and waits for the recipient to reply (2-minute timeout by default). The reply is returned as the tool result. No confirmation dialog. Only one pending `ask` is allowed per session at a time. Use this when the agent needs the answer to continue working.\n\n**`reply`** — Replies to the current intercom-triggered message if there is one. Otherwise it falls back to the single unresolved inbound ask. If multiple asks are pending, pass `to` or inspect them with `pending` first. Under the hood this is still a normal `send` with the exact `replyTo` value.\n\n**`pending`** — Lists unresolved inbound asks with sender, message ID, elapsed time, and a short preview. Useful when replying after the original triggered turn.\n\n**`status`** — Shows connection status, session ID, and total count of active sessions (including the current session).\n\n## Keyboard Shortcuts\n\n| Key | Action |\n|-----|--------|\n| Alt+M | Open session list overlay |\n| ↑/↓ | Navigate session list |\n| Enter | Select session / Send message |\n| Escape | Cancel / Close overlay |\n\n## Config\n\nCreate `$PI_CODING_AGENT_DIR/intercom/config.json` (or `~/.pi/agent/intercom/config.json` when `PI_CODING_AGENT_DIR` is unset):\n\n```json\n{\n  \"brokerCommand\": \"npx\",\n  \"brokerArgs\": [\"--no-install\", \"tsx\"],\n  \"confirmSend\": false,\n  \"enabled\": true,\n  \"surface\": \"full\",\n  \"replyHint\": true,\n  \"showIncomingMessages\": true,\n  \"status\": \"researching\"\n}\n```\n\n### Surface modes\n\n`surface` controls registration of intercom-facing tools, UI, and runtime. `enabled` remains a separate legacy runtime switch: `false` suppresses broker/session connection and broker-required operations, but it does not unregister public resources and local subagent event relay may still operate. Use `surface: \"off\"` for the hard stop.\n\n| Surface | Default | What it does |\n|---------|---------|--------------|\n| `full` | yes | Default behavior: registers the `intercom` tool, `/intercom`, `Alt+M`, normal reply hints, and pi-intercom's compatibility `contact_supervisor` when `pi-subagents` provides child metadata |\n| `bridge` | no | Keeps broker/runtime compatibility for temporary tlh migration bridging, including rich subagent result delivery and control relay behavior, but omits the local `intercom` tool, `/intercom`, `Alt+M`, reply-hint tool instructions, and pi-intercom's duplicate compatibility `contact_supervisor` |\n| `off` | no | Installs no intercom runtime or public surface |\n\n`bridge` is intentionally narrower than `full`: it is a temporary compatibility surface until native `pi-subagents` has rich-result/control delivery parity, not a replacement for native supervisor tooling (which modern `pi-subagents` already provides).\n\n### `PI_INTERCOM_SURFACE` precedence\n\nThe effective surface is resolved in this order:\n\n1. `PI_INTERCOM_SURFACE`, if set\n2. `surface` in `$PI_CODING_AGENT_DIR/intercom/config.json`\n3. the default `full`\n\nAccepted values are `full`, `bridge`, and `off`.\n\nIf `PI_INTERCOM_SURFACE` is set to an invalid value, pi-intercom warns and fails safe to `full`. This override still wins over `config.json`, so an invalid environment value will not silently leave the session in `bridge` or `off`.\n\nIf `config.json#surface` is invalid, pi-intercom warns and falls back safely to `full` unless a valid `PI_INTERCOM_SURFACE` override is present.\n\nTo undo a temporary override, unset `PI_INTERCOM_SURFACE` and reload/restart the session. For example:\n\n```bash\nunset PI_INTERCOM_SURFACE\n```\n\nTo undo a checked-in or local config override instead, remove the `surface` key (or set it back to `\"full\"`) in `$PI_CODING_AGENT_DIR/intercom/config.json`, then reload/restart the session.\n\n### Other settings\n\n| Setting | Default | Description |\n|---------|---------|-------------|\n| `brokerCommand` | `\"npx\"` | Command used to start the local broker process |\n| `brokerArgs` | `[\"--no-install\", \"tsx\"]` | Arguments passed to `brokerCommand` before the broker script path |\n| `confirmSend` | false | Show a confirmation dialog before non-reply sends from an interactive session with UI |\n| `enabled` | true | Legacy runtime switch. When `false`, suppresses broker/session connection and broker-required operations; it does not unregister public resources, and local subagent event relay may still operate. Use `surface: \"off\"` for a hard stop |\n| `surface` | `\"full\"` | Choose `full`, `bridge`, or `off` as described above |\n| `replyHint` | true | Include reply instruction in incoming messages when the full tool surface is active |\n| `showIncomingMessages` | true | Render inbound message boxes in the TUI; when false, messages are still delivered to the model |\n| `status` | — | Optional custom status suffix shown after the automatic lifecycle status, for example `thinking · researching` |\n\nFor example, if you have Bun installed and want it to start the broker directly, use:\n\n```json\n{\n  \"brokerCommand\": \"bun\",\n  \"brokerArgs\": []\n}\n```\n\nPi-intercom publishes live session status automatically. Sessions register as `idle`, switch to `thinking` while the agent is running, show `tool:<name>` during tool execution, and return to `idle` on agent completion. If `status` is set in config, it is appended as context instead of replacing the lifecycle status.\n\n## How It Works\n\n```mermaid\ngraph TB\n    subgraph A[\"Pi Session A\"]\n        A1[Intercom Client]\n        A2[intercom tool]\n        A3[UI overlays]\n    end\n\n    subgraph Broker[\"Intercom Broker\"]\n        B1[Session Registry]\n        B2[Message Router]\n    end\n\n    subgraph B[\"Pi Session B\"]\n        B3[Intercom Client]\n        B4[intercom tool]\n        B5[UI overlays]\n    end\n\n    A1 <-->|Local Socket/Pipe| B1\n    B1 --- B2\n    B2 <-->|Local Socket/Pipe| B3\n```\n\nThe broker is a standalone TypeScript process that manages session registration and message routing. It auto-spawns when the first intercom-enabled session needs it and exits after 5 seconds when the last connected session disconnects. Clients now reconnect automatically if the broker disappears and later comes back.\n\nMessages use length-prefixed JSON over a local socket/pipe transport (4-byte length + JSON payload) to handle fragmentation properly. The protocol includes request correlation for session listing, explicit delivery failures, and validation for malformed or out-of-order messages.\n\nAsync extension work (startup, inbound flushes, reconnects, overlays, and relays) no-ops if the session shuts down or reloads before it settles.\n\nRuntime files live at `$PI_CODING_AGENT_DIR/intercom/` (default `~/.pi/agent/intercom/`):\n- `broker.sock` — Unix domain socket for communication (macOS/Linux only; Windows uses a named pipe instead)\n- `broker-launch.vbs` — Windows helper script used to launch the broker without a console window\n- `broker.pid` — Broker process ID\n- `config.json` — User configuration\n\n## Design Decisions\n\n**Local IPC instead of TCP.** Same-machine only by design. `pi-intercom` uses Unix sockets on macOS/Linux and a named pipe on Windows, which keeps setup simple and avoids port management.\n\n**Auto-spawn with file lock.** The broker starts on first connection and exits after 5 seconds idle. There is no daemon to manage. A spawn lock file, keyed by PID and timestamp, prevents duplicate brokers when multiple sessions start at once.\n\n**`ask` stays client-side.** The broker still routes plain messages; it does not have a special request/response mode for `ask`. The client waits for a matching reply before it triggers a new turn, then returns that reply as the tool result. Reply hints make that flow practical by showing the recipient the exact `send` call to use. Separately, `list` / `sessions` now carry a `requestId` so a delayed session-list reply cannot be mistaken for a newer one.\n\n## pi-intercom vs pi-messenger\n\n| Aspect | pi-intercom | pi-messenger |\n|--------|-------------|--------------|\n| **Model** | Direct 1:1 messaging | Shared chat room |\n| **Primary use** | User orchestrating sessions | Autonomous agent coordination |\n| **Discovery** | Broker-based (real-time) | File-based registry |\n| **Messages** | Private, session-to-session | Broadcast to all agents |\n| **Persistence** | In Pi session history | Shared coordination files |\n\nUse pi-messenger for multi-agent swarms working on a shared task. Use pi-intercom when you want to manually coordinate your own sessions or have one agent reach out to another specific session.\n\n## File Structure\n\n```\n$PI_CODING_AGENT_DIR/extensions/pi-intercom/  # defaults to ~/.pi/agent/extensions/pi-intercom/\n├── package.json\n├── index.ts              # Extension entry point\n├── types.ts              # SessionInfo, Message, protocol types\n├── config.ts             # Config loading\n├── broker/\n│   ├── broker.ts         # Broker process\n│   ├── client.ts         # IntercomClient class\n│   ├── framing.ts        # Length-prefixed JSON protocol\n│   ├── paths.ts          # Platform-specific socket/pipe paths\n│   ├── spawn.ts          # Auto-spawn logic with lock file\n│   ├── spawn.test.ts     # Broker spawn tests\n│   └── paths.test.ts     # Path resolution tests\n├── ui/\n│   ├── session-list.ts   # Session selection overlay\n│   ├── compose.ts        # Message composition overlay\n│   └── inline-message.ts # Received message display\n└── skills/\n    └── pi-intercom/\n        └── SKILL.md      # Bundled skill for common patterns\n```\n\n## Limitations\n\n- **Same machine only** — Uses local sockets/pipes, no network support\n- **No dedicated intercom log** — Messages are kept in Pi session history, but there is no separate intercom transcript or inbox\n- **No attachments UI** — `file`, `snippet`, and `context` attachments are supported in the protocol, but not in the compose overlay\n- **Only connected sessions appear** — The list shows Pi sessions that have loaded `pi-intercom` and successfully registered with the broker, not every open Pi process on the machine\n- **Broker lifecycle** — The broker auto-spawns on first use and exits when idle; sessions reconnect automatically if the broker restarts\n","readmeFilename":"README.md"}