Skip to main content

Intercom operations

Connection states and recovery

Start with the state you can observe. The existing sections below explain the corresponding lifecycle and delivery contracts in detail.

How Connection Works

Intercom connects when you use its tool, /intercom, or ALT+M. Launching an Intercom-enabled subagent may also connect the parent to authorize supervisor communication. An admitted subagent child connects as soon as its session starts, so it appears in its supervisor’s and peers’ intercom list and can receive send/ask before it ever uses Intercom itself; if the broker is unavailable at that moment, the child falls back to connecting on its next Intercom use. Connections are cleaned up when the session closes or is replaced. A session becomes intercom-connected when all of these are true:
  • the mandatory bundled Intercom extension is loaded in that Atomic model session
  • the model or user has invoked an Intercom surface in that session, or the parent runtime is authorizing an Intercom-enabled child supervisor relationship
  • the local broker is running or can be auto-started
The session list and ALT+M picker show connected agent sessions, not every open Atomic process. Internal workflow routing/control connections, model-less ctx.ui prompts, and ctx.tool nodes are not recipients and do not contribute to session counts or presence events. Genuine agents remain visible and messageable while executing tools, including tool:workflow, or awaiting human input. Name sessions with /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-1111-4222-8333-123456789abc 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.

Troubleshooting initialization

Intercom heavy initialization failed; a later call will retry: … means initialization can be attempted again on a later Intercom call. Interactive sessions show this as a yellow warning in the chat pane, without a console stack trace; non-interactive sessions (print, JSON, and RPC) retain console diagnostics. Terminal relay and cleanup failures appear as error notifications in interactive sessions. If initialization keeps failing, check the reported cause and ~/.atomic/agent/intercom/broker.log (or the Intercom directory under ATOMIC_CODING_AGENT_DIR). Do not automatically resend an operation reported with an unknown delivery outcome; check with the recipient first.

Workflow-stage route refusals

When a workflow stage starts, its session registers a live Intercom route with the broker. A refusal names the condition that failed: A stage name reused by a later occurrence in the same run (for example reviewer-a in a second review round while the first round’s completed session is still connected) is not a duplicate owner. The later stage registers under its stage id, and the reused name is ambiguous: neither occurrence keeps a live name alias, so a send to that name is routed through the workflow owner rather than delivered to whichever occurrence registered first. Address such stages by the id-form target that intercom list shows.

How It Works

The local broker starts on first use and exits after five seconds without registered sessions. Clients reconnect automatically using delays of 1, 2, 5, 10, then 30 seconds. Explicit connection failures remain visible while background recovery continues. If the broker stops answering health requests for about a minute, it terminates itself so clients can start a replacement. A single slow request does not restart a responsive broker. This protection starts with a newly launched broker; a broker still running from an older Atomic version must restart before it gains it. A process suspended by the operating system cannot run its own recovery. If it remains stuck, verify which process owns the broker before stopping it manually. Do not delete the Intercom database or key files. If workflow-stage warm-up exhausts its retries, a stage with queued messages fails without consuming them or spending a model retry. Restore broker availability before retrying the work. Protocol, authentication, configuration, and terminal delivery failures require attention rather than a model change. For send, ask, and reply, the tool owns reconnect recovery. One invocation makes the initial attempt and up to three retries, waiting 1, 2, then 5 seconds between attempts. Retries preserve the original message ID, caller arguments, attachment order and presence, and reply thread. The model neither supplies nor receives a retry token. Every new invocation is a fresh intentional operation, even with identical text. Existing integrations must stop passing retryToken; caller-supplied tokens are refused without sending. Initialization may retry before delivery begins. Exhaustion or cancellation there returns outcome: "not_sent". Recoverable disconnects trigger retries; unrelated errors stop them. Cancellation stops new attempts but does not undo a successful receipt. Retry and reply waits share the original 11-minute operation deadline. delivered means the recipient saved the message to its session. A message saved by a busy recipient is shown when it goes idle, as before; if the recipient is killed or crashes first, resuming its session shows each saved message once, in arrival order, after the transcript appears. Saved messages go through the same sender check as interrupted deliveries: one from a sender that is still connected is shown and may start a turn, one from a sender that is gone is added once, in full, to the session history without starting a turn, and the recovery notice says the sender is gone. One whose sender cannot be checked is deferred until the session is opened again: Intercom was unreachable, or the sender is a relaunched subagent that has not reconnected yet. If the recipient does not confirm the save within about 8 seconds, the sender gets a failure saying the outcome is uncertain: the recipient may still save and show the message. Check with the recipient before sending it again as a new message. Intercom’s own retries reuse the original message ID, and a recipient that already saved a message does not show it twice. A recipient that disconnects before confirming receives the message again when it reconnects. While a broker started by an earlier Atomic version is still running after an upgrade, delivered keeps its earlier meaning, that the message reached the recipient, and the recipient still saves it on arrival; the broker exits when idle, and the next one uses the new meaning. outcome: "unknown" means delivery may have occurred, including an accepted ask that ended without a reply. Check with the recipient before sending again. A new tool invocation is a new operation, not another retry of the old one. Intercom refuses new delivery when it cannot safely track duplicates, including capacity or storage failures. Do not delete its runtime files to force a resend when an outcome is unknown. Transport remains local to this machine. Custom hosts may declare an optional recipientPurpose on session registration and workflow-stage roster entries. Only "agent" and "control" are accepted; omission preserves legacy agent behavior. Invalid strings, null, and non-string values are rejected, not silently treated as controls. Session purpose is immutable after registration; presence updates cannot change it. Workflow roster-update completion waits for a broker round trip on the announcing connection so subsequent discovery does not race an unprocessed update. Configuration and diagnostics live in ~/.atomic/agent/intercom/, or under ATOMIC_CODING_AGENT_DIR. The legacy PI_CODING_AGENT_DIR applies when the Atomic variable is unset. Edit config.json for Intercom settings. When startup fails, read the broker.log path printed in the error. Ordinary diagnostics are capped at 8 KiB per broker. The next spawn keeps a bounded copy in broker.log.previous; broker-watchdog.log separately retains the latest automatic termination’s time, PID, and reason. Preserve these files when reporting repeated stalls or restarts. They live under the Intercom directory above.

Workflow and Subagent Notifications

Intercom is also the delivery channel for workflow run results and subagent control notices from workflows and subagents.

Workflow Delivery Modes

Programmatic workflow() calls accept an intercom option that controls how asynchronous direct-run results and control notices reach a parent session:
When neither enabled nor delivery is set, direct parallel runs default to control-and-result when Intercom is available; otherwise delivery is off. Treat Intercom payloads from direct runs as user-visible workflow output. Live workflow stages receive incoming messages according to the sender’s delivery option: "steer" (default) after the current tool calls finish, "followUp" after the stage’s agent stops, and "interrupt" by cancelling its current model call or cancellable tool first. See Intercom for when to use each. A child’s message releases its parent’s foreground wait without cancelling the child. Admission failures return an actionable error to a blocking asker instead of waiting ten minutes. Claimed single-child parent handoffs still end that child.

Subagent Control Notices

The subagent 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", "intercom"] (all that are available)
Run results report each child’s Intercom target as “Run intercom target” or “Previous intercom target”; a target may be inactive after completion. Use intercom({ action: "status" }) to inspect connection state and memberships. For live peer coordination, call intercom({ action: "status" }) in the parent before launching. Children connect on first use. Fresh children receive Intercom even when an extension allowlist omits it.

Delivery Ordering

Parallel communication does not cancel the batch. A blocking ask waits only in its requesting child; the correlated reply continues that same execution. Sends and progress updates remain nonblocking. Claimed single-child parent asks retain their terminal fresh-start handoff. Queued messages from a child arrive before its completion notice. Delivery retries do not rerun work or change its outcome.

Running Intercom across machines

By default, each machine’s broker serves only the sessions on that machine. With multi-node routing, brokers on different machines that use the same shared storage database deliver messages to each other through it. Sessions still connect only to the broker on their own machine, and brokers never connect to each other: they read and write the shared database.

Turning it on

Give every machine the same shared top-level storage selection, including the same prefix. To reach other machines, the selection must be an adapter whose module implements openDatabase and connects to a database that every machine can reach, as described in Sharing storage across hosts. Install the adapter on every machine, for example as an Atomic package so that atomic install also brings its driver. Both the npm installation and the standalone binary run multi-node routing and load storage adapters. The broker takes its selection from one of two places:
  • --storage, --storage-file, or ATOMIC_STORAGE on the Atomic process that starts the broker. See Selecting storage per process.
  • Otherwise, the top-level storage in the global settings file, ~/.atomic/agent/settings.json (or settings.json in the agent directory under ATOMIC_CODING_AGENT_DIR).
One broker serves every session in an agent directory and keeps the selection it started with until it exits. After changing the selection, run atomic intercom restart. It asks the broker to shut down; the sessions connected to it reconnect within a few seconds, and the first one starts a broker with the new selection. The command waits for that broker and prints its multi-node routing state. When no session is connected, the next session that uses Intercom starts the new broker. A broker started by an older Atomic version, which does not answer the request, is stopped with SIGTERM. atomic intercom status shows whether the broker is running, how many sessions it serves, whether it uses the current selection, and its multi-node routing state with the number of other brokers live in the shared database. atomic storage status shows the same together with the selection for sessions and workflow runs; see Checking the selected storage. In a session, intercom({ action: "status" }) adds a Multi-node routing: line, for example Multi-node routing: on (adapter @bastani/atomic-storage-libsql, prefix none), 1 peer broker live (build-host). Each broker writes its multi-node state to broker.log when it starts: Intercom multi-node routing is on (adapter <adapter>, prefix <prefix>) once it has opened the shared database, or Intercom multi-node routing is off: <reason>. <adapter> is sqlite for a path selection. Multi-node routing stays off, and Intercom behaves exactly as on a single machine, when the selection is:
  • absent, including when only project settings (.atomic/settings.json), sessions.storage, workflows.journal, ATOMIC_SESSIONS_STORAGE, or ATOMIC_WORKFLOWS_JOURNAL select storage;
  • in memory: { "memory": true } or { "path": ":memory:" };
  • an adapter that implements only openSessionStore or openRunJournal and has no openDatabase;
  • invalid, for example an env secret that is not set in the broker’s environment, or an adapter module that cannot be loaded. Sessions warn at startup when the Atomic they run cannot load the adapter.
In each case the broker writes Intercom multi-node routing is off: <reason> to broker.log. A path selection, including the default storage file, is a local SQLite file. Only brokers on the same machine that open the same file share it. Do not put it on a network filesystem. Intercom creates its own tables in the selected database, named with the selection’s prefix like the session and workflow tables. Brokers that use different prefixes cannot see each other’s sessions, so a prefix also separates teams or tenants that share one database.

What works across machines

A session connected to a broker on another machine appears in intercom list and is messaged exactly like a local one:
  • send, ask, and reply keep the same sender identity, reply threads, and delivered meaning: delivered still means the recipient saved the message.
  • Group isolation is the same. A session sees and reaches only sessions that share a group with it.
  • Supervisor messages from contact_supervisor keep their supervisor routing.
  • A send to a subagent that its owner is restoring on another machine is held, and reports the same errors, exactly as on one machine. See the connection states table.
  • Duplicate protection still holds: Intercom’s own retries reuse the message ID, and a recipient never shows a message twice.
When a session on this machine and one on another machine have the same name, the name reaches the local one. Give sessions unique names, or address them by session ID.

Latency

Brokers wake each other through the shared database. Each broker checks it for wake-ups every half second, so a message to a live session on another machine usually arrives within about half a second plus the database round trips, and its delivered confirmation takes about as long again. A slow or distant database adds to each step. If a wake-up is missed, a backup check every 30 seconds finds the message, so delivery can take up to about 30 seconds. A sender waits about 8 seconds for a live recipient to confirm, then gets the uncertain-outcome failure described in How it works. The message is still delivered once. Check with the recipient before sending it again as a new message. Sessions on the same machine do not depend on the shared database. Before delivering locally, the broker checks the database for an earlier cross-machine attempt of the same message, and waits at most 0.3 seconds for it, including while the database is still opening when the broker starts. Connecting to Intercom waits at most 5 seconds for the database, and intercom list waits at most 2 seconds for sessions on other machines before it shows the local ones alone.

Offline sessions

A session that quit cleanly or crashed stays known to every broker for about 7 days after it was last connected. It does not appear in intercom list, but you can still message it by name, Intercom session ID, or Atomic session ID, within the same group rules:
  • A send, ask, or reply returns at once as queued, Message queued for <target>, with target: "offline session" in the result details. An ask does not wait for an answer.
  • The message stays in the shared database and is delivered, in order, when that same Atomic session connects to Intercom again with the same home group, on any machine that uses the same storage.
  • The broker reports the later delivery only to a sender that is still connected. The tool result that already returned stays queued, so check with the recipient if you need confirmation.
A target that no session has used in that time, or never used, still returns Session not found. When a whole machine or its broker stops, its sessions still look connected for up to about 30 seconds. A send to one of them in that window waits about 8 seconds and ends with the uncertain-outcome failure; after it, sends are queued. Any message one of those sessions had not yet confirmed is delivered again when it reconnects, and shown once.

Data and security

  • Message text and attachments are stored in the shared database until they are delivered, together with the sender’s identity. Delivered messages are deleted about 12 minutes later, which keeps duplicate protection for retries. Messages for an offline session stay until it reconnects.
  • Session names, session IDs, and group memberships are stored there too, so brokers can list and route to sessions on other machines.
  • Anyone who can read the database can read Intercom messages that cross machines, just as they can read sessions stored there. Protect it with the database’s own credentials and transport security, and pass credentials through secrets ({ "env": ... } or { "file": ... }) rather than options. The broker reads env secrets from the environment of the Atomic process that started it.
  • Intercom opens no network port and no broker-to-broker connection. Its security across machines is the database’s security.

Troubleshooting multi-node

A session on another machine does not appear in intercom list.
  • Run atomic storage status on both machines. Both must use the same storage selection and the same prefix, from settings or from the process that started each broker, and the broker must report storage: matches the selection above. A broker started before you changed the selection keeps the old one until atomic intercom restart replaces it.
  • Check that each broker reports multi-node routing on with the other broker live, in atomic intercom status or in broker.log. Intercom multi-node routing is off: <reason> or Intercom multi-node routing is unavailable: <reason> there gives the cause. A path selection reaches only brokers on the same machine, and a machine whose broker is not running is not live.
  • A session appears only after it connects to Intercom, which happens lazily. Ask it to use Intercom once, for example intercom({ action: "status" }).
  • Both sessions must share a group.
  • When the database is slow to answer, intercom list shows only local sessions. Try again.
A send stays queued. The recipient is offline. It receives the message when the same Atomic session connects to Intercom again with the same home group, on a machine that uses the same storage and prefix. A session reopened on a machine with a different selection never sees it. The database is unavailable. Messages between sessions on the same machine keep working. A send to a session on another machine fails with Session not found on this node, and Intercom could not reach the shared storage database to look for it on other nodes. Try again once the database is available. If the database cannot be opened when the broker starts, the broker logs Intercom multi-node routing is unavailable: <reason> and retries after 1 second, doubling up to every 30 seconds. Intercom never falls back to in-memory storage. If sends keep failing after the database is back, run atomic intercom restart so that a new broker starts. An ask to a session on another machine never gets an answer. If that session disconnects before it answers, the asker is not told, and waits until the ask times out after 10 minutes.

Keyboard Shortcuts

Limitations

  • Local connections only — Each session connects to the broker on its own machine over local sockets/pipes. Sessions on other machines are reachable only through a shared storage database; see Running Intercom across machines
  • No dedicated intercom log — Messages are kept in session history; there is no separate intercom transcript or inbox
  • No attachments UI — file, snippet, and context attachments 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
  • Unsaved sessions — A session started with --no-session keeps received messages only in memory; if it exits before showing them, they are lost
  • Paused or quit subagent — A send or ask to a subagent you paused with subagent({ action: "pause" }) waits until you resume it, but only while the Atomic process that paused it keeps running. After a restart, or for a subagent you quit, sends return Session not found until you resume it with subagent({ action: "resume", id, message? }). See Run control
  • Subagent whose owning process is not running — Sends to a subagent are held only while an Atomic process that owns it is running: the reopened session for a plain session’s subagent, the session that launched the run for a workflow stage’s subagent (once the crashed session’s lease has expired, about 120 seconds, and the run is addressable). Atomic keeps no durable mailbox for a subagent. While no such process runs, for example before the owning session is reopened, a send to the subagent is not queued and returns Session not found, the same as for a top-level session that is not running. The same applies for the few milliseconds after the owning session connects to Intercom and before it has placed its hold. Sends are also not held for a stage’s subagent whose stage session cannot be read, or for a subagent that cannot use Intercom. A hold that nothing restores ends on its own: after 60 seconds for a session whose host does not run recovery, such as atomic -p, and when its owning session disconnects
  • Offline sessions with multi-node routing — With multi-node routing on, a send to a session that disconnected within about the last 7 days, including a subagent’s session, is queued for it instead of returning Session not found, unless one of the holds above applies first. See Offline sessions