[BUG] Desktop: cross-session send_message from an SSH-remote session carries no sender mode, so bypass-mode receivers hold it and refuse it after 5 min
Summary: In Claude Desktop, a cross-session send_message whose sender is an SSH-remote session reaches the receiving CLI without a sender permission mode. When the receiver runs in bypassPermissions, the default mode-parity policy holds the message. Desktop has no approval UI for that hold, so the message expires at dialogExpiry (5 min) and is refused. The same message sent from a local session to the same receiver is delivered.
Environment
- Claude Desktop 2.19675.0 (Windows 11 host), bundled ccd-cli 2.1.286
- Sessions: local Windows sessions and SSH-remote macOS sessions in the same app, all
bypassPermissions - No
crossSessionInbound/dialogExpiryset anywhere (user, local, project, managed)
Symptommcp__ccd_session_mgmt__send_message (and SendMessage(to="local_…"), which takes the same route) to an idle session returns undelivered ("no sign of starting on it within 20s"). The message appears in the app transcript as a user turn but never reaches the receiving Claude.
Controlled comparison (same warm idle receiver, default policy)
| Sender | Result |
|---|---|
| Local Windows session (bypass) | delivered, ran |
| SSH-remote macOS session (bypass) | undelivered; host main.log shows the CLI refusing it ~300 s later |
| SSH-remote sender, receiver host set to crossSessionInbound: "accept" | delivered (warm and cold receivers) |
| Same, after reverting the setting | undelivered again (reproduced) |
Root cause (from the CLI code and logs)
- Desktop injects the message on the CLI's host stdin lane with
origin.kind = "peer"but, for SSH-remote senders, withoutorigin.fromMode. The CLI already reads it (hostInjectedpeer origin acceptsorigin.fromMode === "bypass" | "prompting"). The app seems to attest a local sender's mode but not to know/attest a remote session's mode. - The receiver bypasses permissions, so the default parity policy holds it with cause
no-mode-asserted(documented: the receiving session "delivers one only when the sending session identifies itself as also bypassing"). - Desktop has no approval surface for the hold, so it expires at
dialogExpiry(default 5 min) and the CLI reportsrefused.
Log evidence
- Host
main.log, all 5 rotated logs: 76 peer inputs with a pairable start time. 6 were taken within 300 s (all ran); 70 were refused at 300–316 s (57 at exactly 300 s); none was refused before 300 s. Each time:drew no acknowledgement from the CLI in 45003ms — settled as undelivered, thenCLI refused input … without running it~300 s after hand-off. - Remote Control lane to the same idle sessions: delivered immediately (the envelope carries
from-mode="bypass"). - The running CLI reloads
crossSessionInboundlive; no restart is needed for the comparison above.
Expected: the app attests the sending session's permission mode for SSH-remote senders too, so bypass↔bypass messages deliver without turning off the parity check.
Also
- On one send the app SIGTERM'd a 43-hour-old warm SSH-remote CLI and respawned it with
--resumejust to deliver (SSH daemon log:exited with code 143, signalled at client request). Possibly related to #92687. - The tool result says the receiver "may be waiting for approval there, or slow to start". It should name the actual hold cause (
no-mode-asserted) and say that Desktop cannot approve it.
Workaround: set crossSessionInbound: "accept" on the receiving host (this turns off parity for every sender), or send over the Remote Control lane.
Related: #85888 (held message has no approval UI), #91372 (held vs delivered indistinguishable), #92383 (auto-mode sender dropped), #92687
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗