Atomic sessions can talk to each other. Press ALT+M to message another session, or ask the agent to coordinate with a peer.
Intercom
Atomic bundles@bastani/intercom, a first-party extension for direct 1:1 messaging between Atomic 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. Connections are lazy and tool-driven: the extension registers its commands and tools at startup, but a session does not connect until you or the model actually invoke Intercom. No separate install is needed.
Key capabilities:
- Session messaging -
send,ask(blocking, 10-minute timeout),reply,pending,list, andstatusvia theintercomtool - Session discovery - List connected sessions with name, short ID, working directory, model, and live status
- Keyboard overlay - ALT+M or
/intercomopens a session picker and compose overlay - Attachments - Share
file,snippet, andcontextpayloads between sessions - Subagent escalation - Delegated children get a
contact_supervisortool for decisions, structured interviews, and progress updates - Run notifications - Workflows and subagents deliver async results and control notices to a parent session over Intercom
- Bundled skill -
/skill:intercomprovides planner-worker and escalation-handling patterns
- Planner–worker splits across two terminals
- Research → implementation context handoffs
- Supervisor decisions and structured interviews for delegated subagents
- Async workflow/subagent completion and needs-attention notices
- Pair debugging between sessions
Table of Contents
- Quick Start
- How Connection Works
- The intercom Tool
- Coordination Patterns
- Subagent Escalation: contact_supervisor
- Workflow and Subagent Notifications
- Configuration
- Keyboard Shortcuts
- How It Works
- Intercom vs Shared-Room Messengers
- Limitations
- Related Docs
Quick Start
From the Keyboard
Press ALT+M or run/intercom to open the session list overlay:
- Select a session — Use arrow keys to pick a target session
- Compose message — Write your message in the compose overlay
- Send — Enter Send · Escape Cancel
From the Agent
The agent can list sessions and send messages using theintercom tool. Tool calls and results render as compact transcript rows so send/ask/reply flows are easy to scan:
Receiving Messages
When a message arrives, it appears inline in your chat with the sender’s info and a reply hint:intercom({ action: "reply", ... }), so recipients never 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 Atomic session history.
How Connection Works
Intercom connections are tool-driven. Sessions keep the lightweight wrapper unloaded until the model or user invokes an Intercom tool,/intercom, or the ALT+M overlay. Merely launching a foreground or background delegated child does not connect either session. Concurrent first-use callers share one import and connection attempt, and lazy broker state is leased to the active session generation and cleaned up on shutdown or replacement.
A session becomes intercom-connected when all of these are true:
- the intercom extension is loaded in that session
enabledis not set tofalsein~/.atomic/agent/intercom/config.json(or the legacy~/.pi/agent/intercom/config.jsonfallback)- the model or user has invoked an Intercom tool,
/intercom, or the ALT+M overlay in that session - the local broker is running or can be auto-started
/name so they can target each other (for example /name planner and /name worker). If a session is unnamed, Intercom exposes a runtime-only fallback alias like subagent-chat-1a2b3c4d so other sessions can still target it. That alias is not persisted as the session title, so resume pickers keep showing the transcript snippet instead of a generic name.
The intercom Tool
Actions
Sent and received messages are recorded in session history as
intercom_sent / intercom_received entries.
Targeting Sessions
Target lookup resolves an exact full ID first, then an exact case-insensitive name, then a unique session-ID prefix. If a prefix matches multiple sessions, Intercom reports every match and asks for a longer ID or exact name instead of guessing. Resolving a prefix to the current session triggers the normal self-target rejection (“Cannot message the current session”).send vs ask vs reply
send is fire-and-forget — the tool returns immediately after delivery. By default it sends immediately, including 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 continue without an extra approval step.
ask sends the message and blocks until the recipient responds (10-minute timeout). 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. Only one pending ask is allowed per session at a time; if several blocking requests race (parallel ask calls, or ask alongside contact_supervisor), one wins the reservation and each other call returns a normal “Already waiting for a reply” tool error without disturbing the pending ask.
reply is receiver-side sugar for replying to an inbound ask. In the turn triggered by an incoming intercom message, intercom({ action: "reply", message: "..." }) targets that exact sender and message automatically. If you reply later, it falls back to the single unresolved inbound ask; with multiple pending asks, use pending to inspect them and pass to to disambiguate. Under the hood this is still a normal send with the exact replyTo value.
Attachments
send, ask, and reply accept an attachments array of { type, name, content, language? } objects where type is "file", "snippet", or "context". Attachment content is included in the recipient’s agent-visible message body. Attachments are supported in the protocol but not in the ALT+M compose overlay.
Coordination Patterns
The most natural use of Intercom is splitting a task between two sessions — one holds the big picture, the other does the hands-on work. Open two terminals, start Atomic in each, and name them so they can find each other:intercom({ action: "list" }), then coordinate:
The bundled
intercom skill (/skill:intercom) has copy-paste ready patterns for planner-worker delegation, status checks, natural replies, broadcasting to multiple workers, attachments, and handling subagent escalations on the orchestrator side.
Recommended: Add this snippet to your project’s AGENTS.md to help agents understand when to coordinate across sessions:
Subagent Escalation: contact_supervisor
When Atomic’s subagent runtime spawns a delegated child with bridge metadata, the child session gets a subagent-onlycontact_supervisor tool in addition to the regular intercom tool. Normal sessions never see contact_supervisor.
When the Tool Appears
contact_supervisor only registers when the subagent runtime sets all of these environment variables:
ATOMIC_SUBAGENT_ORCHESTRATOR_TARGET— the supervisor session name or IDATOMIC_SUBAGENT_RUN_ID— the run identifierATOMIC_SUBAGENT_CHILD_AGENT— the agent typeATOMIC_SUBAGENT_CHILD_INDEX— the child index within the run
PI_SUBAGENT_* bridge metadata remains compatible. The optional ATOMIC_SUBAGENT_INTERCOM_SESSION_NAME variable sets the delegated child’s session name. If required variables are missing, the session falls back to the regular intercom tool.
The Three Reasons
Do not use
contact_supervisor for routine completion handoffs — return the final subagent result normally. Blocking calls share the same single reply-waiter reservation as ask, with the same “Already waiting for a reply” semantics.
What the Supervisor Sees
The supervisor receives a formatted message with run metadata:intercom ask/reply flows. The supervisor replies with intercom({ action: "reply", message: "..." }) and the subagent receives the answer as the tool result.
Structured Interview Replies
interview_request questions use the shape { id, type, question, options?, context? } where type is single, multi, text, image, or info (info questions are context-only and need no response):
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; parse errors are surfaced in details.structuredReplyParseError.
Workflow and Subagent Notifications
Intercom is also the delivery channel for async run results and control notices from workflows and subagents.Workflow Delivery Modes
Programmaticworkflow() calls accept an intercom option that controls how async direct-run results and control notices reach a parent session:
When neither
enabled nor delivery is set, async direct parallel/chain runs default to control-and-result when Intercom is available; otherwise delivery is off. Treat Intercom payloads from async direct runs as user-visible workflow output.
While a workflow stage generation is open, incoming Intercom messages are admitted through the stage session’s native steering/follow-up queue; late messages surface once through the main-chat notification path.
Subagent Control Notices
Thesubagent tool’s control options select which control events notify the parent and over which channels:
notifyOn— defaults to["active_long_running", "needs_attention"]notifyChannels— defaults to["event", "async", "intercom"](all that are available)
subagent({ action: "doctor" }) reports Intercom bridge availability and whether Intercom is enabled in config.
If live child-to-parent coordination is needed, invoke intercom({ action: "status" }) in the parent before launching; the child connects on its first contact_supervisor or intercom call. Fresh child processes receive the bundled Intercom wrapper through normal package discovery unless an explicit extensions allowlist excludes it.
Delivery Ordering
During a foreground subagent run, Atomic probes for the exact live foreground owner before delivery: the matching child reserves the request, accepts a generation-scoped detach commit, and acknowledges it before messages enter the parent’s model-visible steering queue. Blocking calls stay alive until the exact threaded reply; cancellation or replacement invalidates stale handshakes. For delegated background children, queued messages and terminal lifecycle notices are ordered per child: pre-terminal messages are admitted FIFO and atomically together with the paused, completed, or failed notice, exact terminal-identity deduplication prevents double admission, failed dispatches remain retryable, and correlated ask replies bypass unrelated queued sends. See Subagents for the full coordination contract.Configuration
Create~/.atomic/agent/intercom/config.json. The legacy ~/.pi/agent/intercom/config.json fallback is read when the Atomic config is absent:
The default
npx --no-install tsx pair is a compatibility sentinel: Intercom recognizes it and starts the broker through the current Atomic runtime (process.execPath). Node-based installs use that runtime with a resolved tsx CLI, falling back to Atomic’s bundled jiti loader when tsx is unavailable; Bun source-checkout runs use the current Bun executable directly; standalone Atomic binaries re-enter the split launcher through a narrow internal broker handoff. Default startup therefore does not rely on npx, tsx, or bun being on PATH. Explicit custom broker commands still work — for example, to intentionally use Bun from PATH:
idle, switch to thinking while the agent is running, show tool:<name> during tool execution, and return to idle on completion. A configured status is appended as context instead of replacing the lifecycle status.
Keyboard Shortcuts
How It Works
The broker is a standalone process that manages session registration and message routing. It auto-spawns when the first intercom-enabled session needs it and exits 5 seconds after the last connected session disconnects; clients reconnect automatically if the broker restarts. A spawn lock keyed by PID and timestamp prevents duplicate brokers when multiple sessions start at once. Transport is local IPC only — a Unix domain socket on macOS/Linux or a named pipe on Windows — using length-prefixed JSON (4-byte length + payload) with request correlation for session listing, explicit delivery failures, and validation of malformed or out-of-order messages.ask stays client-side: the broker routes plain messages, and the client waits for the matching reply before returning it as the tool result.
Runtime files live under the active agent directory — ~/.atomic/agent/intercom/ by default, or below ATOMIC_CODING_AGENT_DIR when set (the legacy PI_CODING_AGENT_DIR alias is honored when the Atomic variable is unset):
broker.sock— Unix domain socket (macOS/Linux; Windows uses a named pipe instead)broker-launch.vbs— Windows helper script to launch the broker without a console windowbroker.pid— Broker process IDbroker.spawn.lock— Short-lived lock used to avoid duplicate auto-spawnsconfig.json— User configuration
Intercom vs Shared-Room Messengers
Use a shared-room messenger for multi-agent swarms working on one shared task. Use Intercom when you want to manually coordinate your own sessions or have one agent reach out to another specific session.
Limitations
- Same machine only — Uses local sockets/pipes, no network support
- No dedicated intercom log — Messages are kept in session history; there is no separate intercom transcript or inbox
- No attachments UI —
file,snippet, andcontextattachments are supported in the protocol, but not in the compose overlay - Only connected sessions appear — The list shows sessions that have connected to the broker, not every open Atomic process
- Broker lifecycle — The broker auto-spawns on first use and exits when idle; sessions reconnect automatically if it restarts