[BUG] `agents_cross_session_inbox` gate off: no UDS inbox is bound, `@` lists no peers, but send_message still reports success

Status Open
Reported on v2.1.232
Maintainer reply ✓ Yes — dhollman
Activity 3 comments · opened Aug 14, 2026
💡 Likely answer: A maintainer (dhollman, contributor) responded on this thread — see the highlighted reply below.

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

On Windows, the CLI never binds its cross-session messaging inbox, because the remote feature gate is off:

[uds-messaging] Skipped: cross-session messaging gate off (will late-bind if a GrowthBook refresh enables it)

Nothing surfaces this anywhere. The @-mention picker (advertised in the 2.1.232 release notes) just lists no sessions, SendMessage / ccd_session_mgmt.send_message stay exposed as usable tools, and the desktop send_message returns success. The feature fails open — it looks available and reports success — instead of failing closed with a stated reason.

Filed separately from the desktop held-steer regression (#86385, #86386, #86014, #86279): those describe a message that reaches the target session's queue but never triggers a responding turn. This report is about the layer below — on this machine the inbox listener is never bound at all, so CLI-to-CLI peer discovery yields nothing.

Evidence

1. The gate is off (CLI debug log)

From ~/.claude/debug/<uuid>.txt, on CLI 2.1.232:

[DEBUG] [uds-messaging] Skipped: cross-session messaging gate off (will late-bind if a GrowthBook refresh enables it)

Reproduced on two independent runs. It is the only [uds-messaging] line emitted.

2. The gate identifier

In the 2.1.232 bundle, the branch that emits the line above sits in the same if/else chain as the bind path: when the gate is on, that branch calls startCrossSessionInbox() and reports the outcome under the identifier agents_cross_session_inbox (bind_failed, bind_failed_late, plus a degraded-cause variant). The late-bind path logs [uds-messaging] Late bind: gate enabled by a GrowthBook refresh after startup.

Other strings in the same area: CLAUDE_CODE_MESSAGING_SOCKET, CLAUDE_CODE_MESSAGING_TOKEN, setup_uds_messaging_ms, [uds-messaging] Skipped: remote thin client.

3. Negative control: two clean CLI 2.1.232 sessions cannot see each other

Two interactive sessions, same machine, same working directory, both live, both persisting transcripts (~22 KB each). Typing @ in session A lists only files and agents — no session entries. No error, and no hint that peer discovery is unavailable.

Rigor note: an earlier attempt was invalid because the CLI inherited CLAUDE_CODE_CHILD_SESSION=1 from its parent process, which disables transcript persistence (the TUI does warn about that one: Transcript saving is off — inherited CLAUDE_CODE_CHILD_SESSION marker). The run above was relaunched with those markers cleared, and that warning was gone.

4. No messaging socket in a desktop session's environment

A Claude Desktop-hosted session's environment contains CLAUDE_CODE_SESSION_ID, CLAUDE_CODE_HOST_SESSION_ID, CLAUDE_CODE_ENTRYPOINT=claude-desktop and friends, but neither CLAUDE_CODE_MESSAGING_SOCKET nor CLAUDE_CODE_MESSAGING_TOKEN.

Actual behaviour

The gate is off and nothing says so. @ returns an empty peer list that is indistinguishable from "no other sessions running", and send_message returns success.

Why this matters

The 2.1.232 release notes advertise @-mention by session name, SendMessage delivery to a bare name, unique per-machine session names, and a /config row for cross-session inbound accept/hold/refuse. With the gate off, all of it is inert with no diagnostic. Users — and agents driving these tools — cannot distinguish "feature disabled for my account" from "bug" or from "no peers running".

Asks

  1. Confirm whether agents_cross_session_inbox is intended to be off for general accounts at this version, and what the rollout state is.
  2. Make the gate state observable (/status or /doctor).
  3. Fail closed: when the inbox is not bound, SendMessage and ccd_session_mgmt.send_message should refuse with the reason rather than report success.
  4. Make the @ picker distinguish "peer messaging unavailable" from "no peers found".

What Should Happen?

Either the gate is on and peer sessions are discoverable, or the gate is off and that fact is visible:

  1. The @ picker states that peer messaging is unavailable, instead of returning an empty list that is indistinguishable from "no other sessions are running".
  2. SendMessage / ccd_session_mgmt.send_message fail closed — they refuse with the reason (inbox not bound / feature gated off) instead of returning success.
  3. /status or /doctor reports whether the cross-session inbox is bound.

At minimum, a gated-off feature should not report successful delivery.

Error Messages/Logs

The only [uds-messaging] line emitted at startup, from ~/.claude/debug/<uuid>.txt (CLI 2.1.232, Windows):

[DEBUG] [uds-messaging] Skipped: cross-session messaging gate off (will late-bind if a GrowthBook refresh enables it)

No error is shown in the TUI, and no corresponding line appears in the Claude Desktop main log.

Steps to Reproduce

On Windows:

  1. Install CLI 2.1.232: npm i -g @anthropic-ai/claude-code
  2. Open two interactive claude sessions in the same directory. Launch them from a shell with no CLAUDE_CODE_* session markers set — in particular CLAUDE_CODE_CHILD_SESSION, CLAUDE_CODE_SESSION_ID, CLAUDE_CODE_HOST_SESSION_ID, CLAUDE_CODE_ENTRYPOINT, CLAUDECODE. (If the TUI shows Transcript saving is off — inherited CLAUDE_CODE_CHILD_SESSION marker, the shell is contaminated and the test is invalid.)
  3. Send one prompt in each session so both sessions exist. Confirm both are persisting transcripts.
  4. In session A, type @.

Observed: the picker lists only files and agents. No peer sessions, no error, no indication that peer messaging is unavailable.

  1. To see the cause, run claude --debug and inspect ~/.claude/debug/<uuid>.txt:
[DEBUG] [uds-messaging] Skipped: cross-session messaging gate off (will late-bind if a GrowthBook refresh enables it)

Separately, from Claude Desktop, calling ccd_session_mgmt.send_message at another local session returns success to the caller.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.232 (Claude Code) — standalone CLI; Claude Desktop 1.30096.1.0 bundles 2.1.229

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

Precise environment:

  • Windows 11 Pro 10.0.22621
  • Claude Desktop 1.30096.1.0 (Microsoft Store / MSIX; auto-update disabled by design on MSIX installs), bundling CC runtime 2.1.229
  • Standalone CLI installed via npm: 2.1.232

Both the desktop-hosted sessions and the standalone CLI sessions on this machine are affected — no [uds-messaging] bind ever happens.

Related but distinct, for triage: #86385, #86386, #86014, #86279 describe the desktop-side symptom (message reaches the target session but no responding turn is triggered; a held steer is only flushed once the user types into the target session). This report is only about the gate/inbox layer and the absence of any signal that the feature is disabled.

View original on GitHub ↗

3 Comments

dhollman contributor · 12 days ago

Thanks for the report. Following up on the "sender says success, recipient refused" mismatch: a fix is up for review that (1) makes a refused cross-session message report back to the sender as refused (with the reason) instead of appearing sent, and (2) makes ListAgents and Remote Control mark a session that cannot currently receive cross-session messages, and refuse the send up front rather than posting into the void. It will note here once it lands and which release carries it. Separately, the Windows-side rollout that caused most of these "refused" results is being enabled independently of the code fix.

bakemocho · 12 days ago

A datapoint from the other side of this gate, plus a warning about an adjacent workaround.

The gate is on for at least one macOS account. CLI 2.1.234 on macOS (Darwin 25.5.0), running under the desktop app (manually swapped into the app's runtime directory — context in #86298): the UDS inbox binds normally here. /tmp/cc-socks/ holds a socket per live session (nine as I write this), peer discovery lists live sessions (seven just now), and the channel has carried real traffic in both directions as recently as yesterday — outbound sends acknowledged with typed delivery receipts, and inbound peer replies arriving tagged from="uds:/tmp/cc-socks/<pid>.sock". I can't quote the [uds-messaging] line to match yours because I don't have debug logging enabled; the bound sockets, populated peer list, and completed round-trips are the same signal from the outside.

So this isn't a feature that's globally off — it's enabled somewhere and silently absent elsewhere, which I think strengthens your fail-closed argument: a gate that's live for some accounts and absent for others is exactly the case where "no peers listed" needs to state a reason, and where send_message returning success is most misleading.

Warning for anyone arriving from the neighbouring threads: the two-lock workaround circulating for the desktop regression (engine >= 2.1.232 plus "crossSessionInbound": "accept") will not help with this issue. I verified that recipe on macOS yesterday and it does fix the desktop path — but that path is ccd_session_mgmt send_message, where the message reaches the target session and fails to become a turn. This report is about the UDS listener never binding at all. Different channel, different mechanism; the setting doesn't reach it. Worth stating explicitly since the two failure modes read almost identically from the sender's side, and both end in a success receipt.

yiwang0w0 · 5 days ago

The rollout has reached this machine; re-verified both fixes from your comment above on Windows.

Environment

  • Claude Code runtime: 2.1.246 (2.1.237 also present)
  • Claude Desktop, Microsoft Store / MSIX build
  • Windows 11 Pro 10.0.22621

Re-ran the repro from the original issue: two interactive sessions on the same machine, peer listing in one, then a send.

Peer listing — fixed. ListAgents returns a roster, and a newly started CLI shows up within ~12 s with a status:

Peer sessions (5):
  scode-96 [ad2d01]  ·  interactive  ·  idle  ·  started 12s ago
  ...

On 2026-08-14 the @ picker on this machine returned only files and agents, with nothing indicating that peer messaging was unavailable. (Today's probe is the ListAgents tool; I have not separately re-checked the picker UI.)

Residual: when that session's process was killed it was removed from the roster rather than listed and marked as unable to receive, so a caller cannot distinguish "no such session" from "was there, cannot receive now".

Refusal reporting — fixed. Sending to the killed session:

{"success":false,"message":"No agent named 'scode-96 [ad2d01]' is reachable. Did you mean: scode-ba?
Use ListAgents to see everyone you can message."}

No false success, no silent queue.

Residual: the message conflates an unknown name with a known-but-unreachable one.

I could not exercise the specific "inbox not bound" refusal — every live session now binds one, and 2.1.229, the last runtime here that did not, has since been cleaned off disk.

Observability (the /status / /doctor ask from the original report) — partially there. The bind is now loudly logged: [uds-messaging] Listening: \\.\pipe\LOCAL\cc-msg-<hash> appears in ~/.claude/debug/<uuid>.txt (observed 2026-08-25, post-rollout) where Skipped: cross-session messaging gate off used to be the only line. So bind state is readable from the debug log; I have not re-checked whether /status or /doctor surface it.

Delivery — checked by observable side effect, not by the return value

Two independent probes, each asking the target to echo a marker string, with nobody touching the target window:

  • same working directory, ~15 s round trip
  • across different working directories, ~20 s round trip

Both showed the same three things: the target's transcript gained a <cross-session-message from="..."> user turn, the target started a turn on its own and replied with the marker, and the desktop log had no flushed held steers line that day — so neither round trip came from the "type something into the target to flush it" workaround.

Rollout vs. code fix — these are separable here

Each session writes ~/.claude/sessions/<pid>.json, and a session that bound an inbox records a messagingSocketPath there — so counting those files reads the rollout state passively, with no sends involved. Measured on 2026-08-21:

| runtime | sessions | with inbox |
|---|---|---|
| 2.1.229 | 17 | 0 |
| 2.1.234 | 36 | 6 |

The 6 bound sessions are exactly the 2.1.234 sessions started after a flag flip that landed between 2026-08-20 06:50 and 2026-08-21 10:37 JST (bracketed by the last non-binding and the first binding session start). Neither condition alone was enough: 2.1.234 sessions started before the flip did not bind, and 2.1.229 sessions started after it did not either. Everything above was therefore measured with both in place — new runtime, flag on.

One last observation: a successful delivery no longer emits the Sending message to session <id> line the desktop log used to write for every attempt. Delivery appears to have moved onto the named-pipe inbox rather than the previous queue, so I can't say whether the old queue path — the one behind the flushed held steers behaviour — is still reachable in other configurations; only that my sends no longer take it.

Thanks for the follow-up.