Pi Intercom logo

Pi Intercom

Community
nicobailon
pi-intercom

Streamline session-to-session coordination with pi-intercom. Send messages, delegate tasks, and coordinate work across multiple pi sessions on the same machine. Use for planner-worker workflows, cross-session context sharing, and real-time collaboration between sessions.

Overview

Publishernicobailon
Repositorypi-intercom
Skill namepi-intercom
Stars
533
Forks
97
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by nicobailon on GitHub. Read the source before you install it.

Installation

Install the Pi Intercom AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/nicobailon/pi-intercom/tree/main/skills/pi-intercom
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/nicobailon/pi-intercom.git /tmp/pi-intercom
mkdir -p .claude/skills
cp -r /tmp/pi-intercom/skills/pi-intercom .claude/skills/pi-intercom
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Pi Intercom in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Pi Intercom on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Pi Intercom is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Pi Intercom Skill

Use this skill when you need to coordinate work across multiple pi sessions running on the same machine. Pi-intercom enables direct 1:1 messaging between sessions for delegation, context sharing, and collaborative workflows.

When you are supervising pi-subagents, delegated child agents can escalate to you via contact_supervisor if pi-subagents supplied child bridge metadata. This skill covers how to handle those orchestrator-side escalations.

When to Use

  • Task delegation: Split work between a planner session and worker sessions
  • Context handoffs: Send findings from a research session to an execution session
  • Clarification loops: Worker asks questions, planner answers, work continues
  • Multi-session workflows: Coordinate between specialized sessions (frontend/backend, research/implementation)
  • Cross-codebase peer messages: Message an explicit live peer in another project, or open a visible Herdr project pane when a long-lived conversation is needed

Core Patterns

Pattern 1: Planner-Worker Delegation

The most common pattern. One session holds the big picture, others do hands-on work.

Setup (in each session):

/alias planner   # Terminal 1
/alias worker    # Terminal 2

Planner delegates a task (fire-and-forget):

typescript
intercom({
  action: "send",
  to: "worker",
  message: "Task-3: Add retry logic to API client. Key files: src/api/client.ts. Ask if anything's unclear."
})

Worker asks for clarification (blocks until answer):

typescript
intercom({
  action: "ask",
  to: "planner",
  message: "Should I use exponential backoff or fixed intervals?"
})
// → Returns the planner's reply as the result

Worker reports completion:

typescript
intercom({
  action: "ask",
  to: "planner",
  message: "Task-3 complete. Added exponential backoff (100ms → 1600ms, max 5 retries). Ready for task-4?"
})

Pattern 2: Quick Status Check

Before sending, verify who's connected:

typescript
intercom({ action: "list" })
// → Shows all connected sessions with names, cwd, models, live status, and
//   current Herdr workspace/tab/pane (or explicit not-hosted/unavailable state)

Pattern 3: Reply Naturally

When responding to an inbound ask, prefer reply instead of reconstructing raw IDs:

typescript
// In the turn triggered by the ask:
intercom({
  action: "reply",
  message: "Use exponential backoff starting at 100ms."
})

// If replying later and there might be more than one pending ask:
intercom({ action: "pending" })
intercom({ action: "reply", to: "planner", message: "Use exponential backoff starting at 100ms." })

reply still preserves exact threading under the hood by sending the response with the original replyTo value.

Pattern 4: Broadcast to Multiple Workers

Send to multiple sessions in parallel:

typescript
const workers = ["worker-1", "worker-2", "worker-3"];
const task = "Check for null pointer exceptions in your assigned files";

// Fire-and-forget to all workers
workers.forEach(w => 
  intercom({ action: "send", to: w, message: task })
);

Pattern 5: Send with Attachments

Share code snippets, files, or context:

typescript
intercom({
  action: "send",
  to: "worker",
  message: "Here's the fix for the auth issue:",
  attachments: [{
    type: "snippet",
    name: "auth.ts",
    language: "typescript",
    content: `function validateUser(user: User | null) {
  if (!user) throw new Error("User required");
  return user.email?.includes("@");
}`
  }]
})

Pattern 6: Cross-Codebase Peer Messages

Use to alone to message any explicit live peer on the machine, even when it is in another codebase. Use cwd alone when there should be exactly one live peer in that repo. Use to plus cwd when the directory is a safety guard.

typescript
intercom({
  action: "ask",
  cwd: "/path/to/other-repo",
  to: "workbench-agent",
  message: "Which module owns workbench source slices?"
})

Only open a Herdr project pane when you need a durable visible peer session in that repo. For bounded work, prefer pi-subagents with an explicit cwd; the child can use contact_supervisor for owner decisions and regular intercom for explicit peer coordination.

typescript
intercom({
  action: "send",
  cwd: "/path/to/other-repo",
  openProjectPaneIfMissing: true,
  message: "Let's discuss the workbench API ergonomics in this repo."
})

If a live session already exists in that cwd, intercom reuses it. If multiple sessions are active there, pass to to select one by name or session ID.

Pattern 6b: Hand Over Your Session

When the user moves work to another session, handover summarizes this session (next task, decisions, files, current state, open questions) with the current model and sends it. The receiver acts on it like any inbound message. Pass the next task as message; targeting works exactly like send.

typescript
intercom({
  action: "handover",
  cwd: "/path/to/other-repo",
  openProjectPaneIfMissing: true,
  message: "Port the schema fix here and run the adapter tests"
})

Humans can run /handover <target> [next task] to review the summary in an editor before it is sent. /handover alone opens a picker for the target.

Pattern 7: Handle Subagent Escalations (Orchestrator Side)

When pi-subagents spawns a delegated child and supplies child bridge metadata, that child can reach you through contact_supervisor. You receive a formatted message that includes run metadata:

**From subagent-worker-78f659a3-1**

Subagent needs a supervisor decision.
Run: 78f659a3
Agent: worker
Child index: 0

Which API should I use?

Reply using reply:

typescript
// The reply hint in the incoming message will show the exact call:
intercom({ action: "reply", message: "Use the stable v2 API." })

This works because reply resolves the correct sender and message ID automatically.

Three types of escalations to expect:

TypeWhat it meansHow to respond
need_decisionSubagent is blocked and waiting for your answer. Uses the shared ask timeout: 10 minutes by default, configurable with PI_INTERCOM_ASK_TIMEOUT_MS.Reply promptly with a clear decision. If you need more context, ask follow-up questions via reply.
interview_requestSubagent needs multiple structured answers in one blocking exchange. Uses the shared ask timeout: 10 minutes by default, configurable with PI_INTERCOM_ASK_TIMEOUT_MS.Reply with plain JSON or a fenced json block using the provided { "responses": [...] } shape.
progress_updateSubagent is sharing meaningful progress or a plan-changing discovery. Not blocking.Read and acknowledge. No reply required unless you want to redirect.

When a subagent asks:

typescript
// In the turn triggered by the incoming ask:
intercom({ action: "reply", message: "Use exponential backoff, max 3 retries." })

When a subagent sends an interview request:

Read the rendered questions in the incoming message and reply with the exact ids in JSON. info questions are context-only and do not need response entries:

typescript
intercom({
  action: "reply",
  message: "```json\n{\n  \"responses\": [\n    { \"id\": \"api\", \"value\": \"Stable API\" },\n    { \"id\": \"constraints\", \"value\": \"Keep the public error shape unchanged.\" }\n  ]\n}\n```"
})

If you receive multiple pending asks from different subagents:

typescript
intercom({ action: "pending" })
// → Shows all unresolved inbound asks with sender, elapsed time, and preview

intercom({ action: "reply", to: "subagent-worker-78f659a3-1", message: "Use the v2 API." })

Important: Only sessions where pi-subagents supplied child bridge metadata get the contact_supervisor tool. Normal sessions use the regular intercom tool. If you see the formatted supervisor decision/progress update message, treat it as a contact_supervisor escalation. A subagent may use regular intercom for peer coordination, including peers in other directories, but owner decisions and new visible project panes should go through the supervisor.

Key Differences

ActionBehaviorUse When
sendFire-and-forget; infers the sole pending ask as its replyYou don't need a response
askBlocks until reply (10 min default, configurable with PI_INTERCOM_ASK_TIMEOUT_MS)You need an answer to continue
replyResponds to the active or pending inbound askYou were asked something and need to answer naturally
pendingLists unresolved inbound asksYou need to see who is waiting before replying
listReturns all sessions with live status and freshly resolved Herdr locationYou need to discover targets or choose an idle peer
statusReturns your connection stateTroubleshooting

Visible Peer Sessions

For bounded cross-codebase work, prefer pi-subagents with an explicit cwd. Use intercom({ action: "send", cwd: "/path", openProjectPaneIfMissing: true, ... }) only when a long-lived visible peer session is useful.

If Herdr is unavailable, do not invent a terminal fallback inside this workflow. Ask the user before opening another visible surface manually.

Important Constraints

ask Limitations

  • Connected targets only: ask fails immediately when the target is not in the live intercom roster. Use list before asking when liveness is uncertain; use send for non-blocking mailbox delivery.
  • Configurable timeout: If no reply arrives before the shared ask timeout, the ask fails. The default is 10 minutes; set PI_INTERCOM_ASK_TIMEOUT_MS to a positive millisecond value to change it.
  • One at a time: Cannot have multiple pending asks from the same session
  • Cannot self-target: A session cannot ask itself, including through disconnected-mailbox remapping
typescript
// Check if already waiting before asking
const result = await intercom({ action: "ask", to: "planner", message: "..." });
if (result.isError && result.content[0].text.includes("Already waiting")) {
  // Use send instead, or wait for current ask to complete
}

send Behavior

  • No timeout: Message is delivered or fails immediately
  • Sole pending ask inference: If the destination has exactly one pending inbound ask, send attaches its replyTo and reports Reply sent to <target> (inferred from pending ask)
  • Ambiguity stays unthreaded: Zero or multiple matching asks leave the send as an ordinary message
  • Confirmation dialogs: If confirmSend: true in config, interactive sessions confirm ordinary and inferred sends
  • Explicit replies skip confirmation: A caller-supplied replyTo skips the dialog

Best Practices

Use list location instead of guessing

For a Herdr-hosted session, list displays readable workspace and tab labels plus stable opaque IDs and a diagnostic pane ID. The workspace/tab values come from a fresh bounded Herdr snapshot for that list request, joined by the Pi session identity that remains stable when Herdr changes the workspace-qualified pane ID, so use them instead of inferring location from cwd or session name. not under Herdr means the session did not register a Herdr pane. Herdr location unavailable means it did register one, but the current snapshot failed or no longer contained that pane. Use herdrLocation.paneId, not the launch-time herdrPaneId, when current diagnostic pane metadata is needed. Do not use pane IDs as intercom addressing handles; target the session name or intercom session ID. If no connected session is Herdr-hosted, list does not call Herdr or add location lines.

Use ask for blocking workflows

When the worker needs information to proceed:

typescript
// GOOD: Worker blocks until planner responds
const reply = await intercom({
  action: "ask",
  to: "planner",
  message: "API rate limit is 100/min. Should I implement client-side throttling or batching?"
});
// Continue with the answer...

Use send for notifications

When you just want to inform:

typescript
// GOOD: Fire-and-forget notification
intercom({
  action: "send",
  to: "reviewer",
  message: "PR #123 is ready for review. Key changes in auth.ts."
});
// Continue immediately, don't wait

Name sessions meaningfully

Use /alias so others can target you easily. It names the current session and is shown in intercom lists, send/reply results, overlays, and incoming headers:

/alias api-worker
/alias frontend-dev
/alias planner

Error Handling

Common Errors and Solutions

"Already waiting for a reply"

typescript
// You can only have one pending ask at a time
// Option 1: Use send instead
intercom({ action: "send", to: "planner", message: "..." });

// Option 2: Wait for current ask to complete first

"Cannot message the current session"

typescript
// You cannot target yourself
// This usually means you confused session names - double-check the target

"Session not found"

typescript
const result = await intercom({ action: "send", to: "worker", message: "..." });
if (!result.delivered) {
  console.log("Failed:", result.reason);
  // → "Session not found" - check the name and list available sessions
  await intercom({ action: "list" });
}

Replies to recently disconnected explicitly named senders can be queued by the broker and delivered if that sender reconnects with the same name and directory. Runtime-only subagent-chat-... aliases are not reconnect identities. New send calls may target a known live or recently disconnected session; blocking ask calls require a live target.

Ask timeout

typescript
// The ask will reject with a timeout error
// Default: 10 minutes
// Override: set PI_INTERCOM_ASK_TIMEOUT_MS to a positive millisecond value
// For longer tasks, use send + follow-up ask pattern

Troubleshooting

Session not appearing in list

  1. Check intercom is enabled: intercom({ action: "status" })
  2. Verify the target session has loaded pi-intercom
  3. Ensure both sessions are on the same machine (intercom is same-machine only)

Message not delivered

typescript
const result = await intercom({ action: "send", to: "worker", message: "..." });
if (!result.delivered) {
  console.log("Failed:", result.reason);
  // → "Session not found" or delivery failure reason
}

Connection lost

Sessions automatically reconnect if the broker restarts. If persistently disconnected:

typescript
intercom({ action: "status" })
// Check if broker is running and restart if needed

Common Workflows

Research → Implementation Handoff

typescript
// Research session finds relevant code
intercom({
  action: "send",
  to: "impl-session",
  message: "Found the bug. The issue is in validateUser() - it doesn't check for null.",
  attachments: [{
    type: "snippet",
    name: "validate.ts",
    language: "typescript",
    content: `// Line 45-52 - missing null check
function validateUser(user: User) {
  return user.email?.includes("@"); // crashes if user is null
}`
  }]
});

Pair Debugging

typescript
// Session A encounters error
intercom({
  action: "ask",
  to: "session-b",
  message: "Getting 'Cannot read property of undefined' at line 78. Can you check if data.users is populated before this call?"
});

// Session B investigates and replies
intercom({
  action: "reply",
  message: "data.users is null. The fetch failed silently. Add error handling in loadUsers()."
});

Progress Reporting

typescript
// Worker sends periodic updates
intercom({ action: "send", to: "planner", message: "Task-1 complete (15min). Starting Task-2." });
// ... work ...
intercom({ action: "send", to: "planner", message: "Task-2 complete (30min). Task-3 blocked - need API key." });
// ... get unblocked ...
intercom({ action: "send", to: "planner", message: "Task-3 complete. All done." });

Long-Running Task with Checkpoints

typescript
// For tasks that might exceed the ask timeout, use send + periodic asks

// 1. Initial send with full context
intercom({
  action: "send",
  to: "worker",
  message: "Implement user authentication. This will take 30+ minutes. I'll check in at milestones."
});

// 2. Worker sends progress via send (no timeout)
intercom({ action: "send", to: "planner", message: "Milestone 1: Login form complete (10min)" });

// 3. Worker asks for specific decision when needed
const decision = await intercom({
  action: "ask",
  to: "planner",
  message: "Should we use JWT or session cookies? Need decision to continue."
});
// Continue with decision...

Frequently asked questions

What does the Pi Intercom AI skill do?

Streamline session-to-session coordination with pi-intercom. Send messages, delegate tasks, and coordinate work across multiple pi sessions on the same machine. Use for planner-worker workflows, cross-session context sharing, and real-time collaboration between sessions.

Why use Pi Intercom on TypingMind?

Because you install it once and use it with any model. Pi Intercom is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Pi Intercom in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/nicobailon/pi-intercom/tree/main/skills/pi-intercom. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Pi Intercom?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Pi Intercom?

As many as you like. As long as a model supports skills, you can use Pi Intercom with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Pi Intercom AI skill free?

Yes. It is published on GitHub by nicobailon under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇