Claude Code Multi-Agent SendMessage 2026

Claude Code Cross-Session Messaging: The Complete Guide to SendMessage and ListAgents (2026)

The Prompt Shelf ·

Shipped in v2.1.224 (August 7, 2026), cross-session messaging lets one Claude Code session hand information to another — a different terminal, a different worktree, even a different machine — without you copy-pasting between them. Claude uses two tools to do it: ListAgents to find a target, SendMessage to deliver text to it.

That one-sentence description undersells how much this changes for anyone running more than one session at a time, and it also gets confused constantly with three other Claude Code features that sound similar but do different jobs. This guide covers what the feature actually does, exactly which settings control it, and where it stops — including the cases where “message my other session” is the wrong tool for what you’re trying to do.


What cross-session messaging actually is

A message is a short piece of plain text one Claude writes to another Claude. Not conversation history. Not files. Not permissions. Just text, plus a sender name and a reply address.

Claude decides when to send one — usually because it just did something that affects work happening elsewhere — or you ask it to:

Ask the session running in my other terminal whether the migration finished
Explain what we just did to the session working on the payments API

You never call ListAgents or SendMessage yourself. Claude discovers reachable sessions and addresses the message on its own. To see what it can see, run /list-agents (alias: /peers).


Cross-session messaging vs. Remote Control vs. Agent Teams vs. Subagents

This is the part the release notes don’t make obvious: Claude Code now has four different ways to connect multiple sessions, and they solve different problems. Mixing them up is the most common way people get stuck.

FeatureWhat it connectsWho starts the exchangeWhat travels
Cross-session messagingTwo independent sessions you started separately (same machine or across machines)Either session, once; only the receiver’s machine can reply cross-machinePlain text only
Remote ControlYou (phone/web) and one Claude Code sessionYou, from the client deviceFull conversation, steering, approvals
Agent teamsA supervisor session and teammates it spawned itselfThe supervisor, by designStructured team protocol messages
SubagentsThe main thread and agents it delegates to within one sessionThe main threadFull task context, in-session only
Resuming a sessionOne conversation, continued elsewhereYouEverything — full history and context

If you actually want to move a whole conversation somewhere else, resume it — cross-session messaging is not a context-transfer mechanism, and Anthropic is explicit about that in the docs: “a message is a piece of text one Claude writes to another, never conversation history or files.” If you’re steering a session from your phone, that’s Remote Control. If Claude spawned the other session itself, that’s an agent team or a subagent, and it already has a dedicated SendMessage channel for that — this page is specifically about independent sessions you started and steer yourself.


Requirements

RequirementDetail
VersionClaude Code v2.1.224 or later
OSmacOS and Linux (including WSL2). No native Windows support.
ProviderNot available on Amazon Bedrock, Claude on AWS, Google Cloud Agent Platform, or Microsoft Foundry
EnablementOn by default — nothing to turn on when the requirements are met
Env var gatesSetting CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, DISABLE_TELEMETRY, DO_NOT_TRACK, or DISABLE_GROWTHBOOK can silently disable the underlying feature flag

Check a session with /list-agents. If the command isn’t recognized, the session predates the feature or is running on an unsupported platform — start with claude --version.


How sessions find each other

Each session registers itself in files on disk and binds an inbox socket there. Other sessions on the same machine read those files to discover it — nothing goes through Anthropic’s servers for same-machine delivery.

That has a concrete consequence: two sessions can only reach each other when they can see the same filesystem. A session running inside a container can’t message a session on the host, because the container has its own filesystem. Two sessions inside the same container — including on a self-hosted runner — can still message each other fine.

A session’s name comes from /rename or the --name flag. If you never set one, Claude Code derives it from the working directory, e.g. myapp-3f. Two sessions can end up with the same name — /list-agents shows each one’s working directory so you can tell them apart, and Claude appends a short identifier to disambiguate when it addresses a message.

ListAgents output has three tiers:

  • Subagents running inside the current session
  • Other local sessions — including background sessions — that have bound an inbox socket
  • Sessions beyond this machine, labeled Remote Control, visible only while Remote Control is connected

Cross-machine sessions are reply-only. Claude here can answer a message that arrived from your laptop or from Claude Code on the web, but it can’t initiate a new conversation with one — see the table below.


Where the message actually travels

Where the other session runsTransportWhat this session can send
Same machineDirect socket, never through Anthropic serversNew messages and replies
Another of your machinesThrough Anthropic servers, arriving via that machine’s Remote Control connectionReplies only
Claude Code on the webThrough Anthropic servers, straight to the cloud sessionReplies only

There’s one edge case worth knowing about: if the replying session isn’t itself connected to Remote Control, the reply still goes out as a direct request to Anthropic — it just arrives without a reply address, so the other side can’t answer back. Claude is told this before it sends.


Message delivery: delivered, held, or refused

The receiving session checks every arriving message against its own inbound controls, and one of three things happens:

  • Delivered — passed straight to Claude, read between tool calls if a turn is running, or opens a new turn if idle
  • Held — set aside; an approval dialog shows the sender and a preview, and it reaches Claude only if you approve it (or a later settings change allows it)
  • Refused — dropped silently, no approval dialog

Once delivered, a message counts toward usage like anything you typed yourself.

The default rule (when you haven’t set anything)

Claude Code groups sessions into two classes — bypassing (running with bypassPermissions, or in auto mode) and prompting (everything else, including plan mode with bypass unavailable). Then:

  • If your session prompts for permissions: it delivers every message, and only holds one if the sender identifies itself as bypassing.
  • If your session bypasses permissions: it holds every message, and only delivers one if the sender also identifies as bypassing.

The asymmetry is intentional — a bypassing session is the one that can act on a message without stopping to ask you, so it’s the one that gets the extra checkpoint.

Settings that override the default

SettingValuesWhat it does
crossSessionInboundaccept / hold / refuseOverrides the default class-based behavior for this session
dialogExpiryduration, default 5mHow long a held message’s approval dialog stays open before it’s dropped
isolatePeerMachinesbooleanRequires your explicit approval before any SendMessage leaves this machine, even in bypass mode
{
  "crossSessionInbound": "accept",
  "dialogExpiry": "10m"
}

For a headless claude -p worker that needs to receive messages unattended, pass crossSessionInbound: "accept" in its --settings value — a -p session can’t render an approval dialog, so anything held there stays held indefinitely.

Claude Code holds a maximum of 100 undelivered messages per session and drops the oldest past that. It also rate-limits repeated sends and drops identical duplicates arriving in a short window, so a message loop between two sessions stops itself.


What a receiving session can’t do with a message

This is the actual security boundary, and it’s worth reading closely if you’re going to rely on this between sessions with different trust levels:

  • It can’t approve anything on your behalf. A message from another session never counts as your consent for a pending permission prompt.
  • It can’t change configuration. Claude is instructed never to modify permission settings, CLAUDE.md, or any other config because a peer session asked.
  • Commands in the text don’t execute. If a message contains /compact or a shell command, it arrives as plain text — Claude Code never runs it.
  • Ordinary permission prompts still fire. If acting on a message needs a permission the receiving session doesn’t already have, you see the normal prompt.

Permission boundaries also stay per-session in the other direction: Claude is told never to ask another session to do something its own permissions would block, and to route that back to you instead of routing around it via a peer.


A worked example: two worktrees, one warning

Say you’re running Claude Code in two git worktrees of the same repo — one on a schema migration, one building a feature that reads the table being migrated. You didn’t wire anything up. You just tell the migration session:

Let the other session working on the payments feature know once this lands

When the migration finishes, the sending Claude writes something like:

Schema migration finished: the new column is tenant_id, and rebasing on main is safe now.

The receiving session sees a collapsed Message from row (Ctrl+O expands it), reads it between its own tool calls if it’s mid-turn, and can act on it — subject to its own permission prompts, exactly as if you’d typed the instruction yourself.


Turning it off

Receiving and sending are independent controls.

Stop receiving — set crossSessionInbound to refuse:

{ "crossSessionInbound": "refuse" }

Stop sending and listing — deny the tools directly:

{
  "permissions": {
    "deny": ["SendMessage", "ListAgents"]
  }
}

Note that denying SendMessage also removes messaging to subagents and agent-team teammates, since it’s the same tool underneath.

For an org-wide lockdown, combine both in managed settings:

{
  "permissions": {
    "deny": ["SendMessage", "ListAgents"]
  },
  "crossSessionInbound": "refuse"
}

A refused session shows no visible change in /status or in other sessions’ /list-agents output — you have to check the config directly to confirm it’s off.


Limitations

  • Plain text only. No files, no structured data, no conversation state. Agent-team protocol messages are a separate, structured channel that stays within the team.
  • No native Windows support, and no support on Bedrock, AWS, Google Cloud Agent Platform, or Microsoft Foundry as of this writing.
  • Cross-machine is reply-only. A session on another machine can’t be the first message in a conversation from here — only Remote Control lets you initiate that direction.
  • Loops are throttled but not impossible to trigger accidentally if two sessions keep prompting each other to reply — the 100-message hold cap and duplicate suppression are the backstop, not a guarantee of clean behavior.

FAQ

Do I need to call SendMessage or ListAgents myself? No. You just tell Claude what you want the other session to know, in plain language. Claude finds the target and writes the message.

Can a message from another session approve a permission prompt for me? No. Consent from a peer session is never treated as your consent. Pending prompts still wait for you.

Does this replace claude --resume? No — resuming carries the full conversation and context. Cross-session messaging carries one piece of text between two conversations that stay separate.

Why does my bypass-mode session hold every incoming message by default? Because a bypassing session can act on a message without asking you first, Claude Code adds the approval dialog as a checkpoint you’d otherwise skip. Set crossSessionInbound: "accept" if you’ve decided that’s unnecessary for your setup.

Can two sessions in different Docker containers message each other? No — each container has its own filesystem, and discovery depends on both sessions seeing the same inbox-socket files. Two sessions inside the same container can still reach each other.

Does this work with a claude -p headless session? Yes, as long as it isn’t started in bare mode (which skips binding the inbox socket entirely). Set crossSessionInbound: "accept" in its settings if you need it to receive messages without a human present to approve them.


Browse how real projects configure Claude Code — permissions, hooks, sandboxing — in our rules gallery.

Related Articles

Explore the collection

Browse all AI coding rules — CLAUDE.md, .cursorrules, AGENTS.md, and more.

Browse Rules