send_message via the inbox socket #158

Open
opened 2026-09-15 18:25:32 +02:00 by lz · 0 comments
Owner

"Tell session 2 to look at the auth bug." The highest-value tool and the one with the most measured detail behind it.

Depends on #154. Scope: nexus:write.

Use the inbox socket, not sendNudge

Every session exports CLAUDE_CODE_MESSAGING_SOCKET and CLAUDE_CODE_MESSAGING_TOKEN. Measured inside one worker:

/tmp/cc-socks/1450.sock    srw-------
/tmp/cc-socks/23068.sock   srw-------
/tmp/cc-socks/309071.sock  srw-------

A message delivered there arrives as a cross-session message, which never counts as consent and so cannot answer a pending permission prompt on the recipient's behalf. sendNudge types raw text into the PTY and has no such guarantee — the hazard its own comment in nexus/src/lib/server/artifacts/tmux-nudge.ts already describes.

That gap is tolerable today because the only sender is the operator approving their own artifact feedback. It becomes a hole the moment a second principal exists, which is the direction this milestone is heading: one principal's send_message could answer a permission dialog in another's session. The socket is the option that survives.

Integration details, each pinned by a test

  • Nexus reaches the socket via docker exec, so it is not an "own-child" sender; the message goes through the receiving session's crossSessionInbound controls.
  • The fleet runs defaultMode: auto, which counts as prompting, so messages are delivered. A session running bypassPermissions holds them for approval instead. Pin this rather than discovering it later — it is the difference between a tool that works and one that silently queues.
  • Protocol: send {"type":"auth","token":"<CLAUDE_CODE_MESSAGING_TOKEN>"} as the first line. Optional on Linux, required on Windows; send it always.
  • Open the connection only when the payload is ready — claude closes a connection idle for 30s.

Resolving the socket

Each session's socket is named for its claude pid. Resolution has to go from a sessions row to that pid. Note procps is not installed in the worker image (AGENTS.md fact #5) — walk /proc/[0-9]*/cmdline directly, as checkSessionHealth already does, and reuse its kind-dispatching match: kind='session' matches the full --remote-control "<workspace> · <name>" argv precisely so one Remote Control process does not satisfy every session's probe.

Out of scope

sendNudge stays where it is. Artifact feedback submission is not in scope; whether it should also migrate is a follow-up.

Do not build a mailbox or session-to-session messaging. Claude Code already does it, and Nexus made its own fleet addressable without meaning to — ListAgents from inside a worker returned 28 peers, sibling sessions over a Unix socket plus sessions in other Nexus workers via Remote Control. A Nexus mailbox would be a worse copy of something with inbound controls, loop throttling, burst caps, a 100-message hold queue, and the no-consent guarantee above.

Done when

A message sent through the tool appears in the target session as a cross-session message; a bypassPermissions session is observed to hold rather than deliver it; and the auth line, the 30s idle close and the pid resolution each have a test proven able to fail.

"Tell session 2 to look at the auth bug." The highest-value tool and the one with the most measured detail behind it. Depends on #154. Scope: `nexus:write`. ## Use the inbox socket, not `sendNudge` Every session exports `CLAUDE_CODE_MESSAGING_SOCKET` and `CLAUDE_CODE_MESSAGING_TOKEN`. Measured inside one worker: ``` /tmp/cc-socks/1450.sock srw------- /tmp/cc-socks/23068.sock srw------- /tmp/cc-socks/309071.sock srw------- ``` A message delivered there arrives as a cross-session message, which **never counts as consent** and so cannot answer a pending permission prompt on the recipient's behalf. `sendNudge` types raw text into the PTY and has no such guarantee — the hazard its own comment in `nexus/src/lib/server/artifacts/tmux-nudge.ts` already describes. That gap is tolerable today because the only sender is the operator approving their own artifact feedback. **It becomes a hole the moment a second principal exists**, which is the direction this milestone is heading: one principal's `send_message` could answer a permission dialog in another's session. The socket is the option that survives. ## Integration details, each pinned by a test - Nexus reaches the socket via `docker exec`, so it is **not** an "own-child" sender; the message goes through the receiving session's `crossSessionInbound` controls. - The fleet runs `defaultMode: auto`, which counts as *prompting*, so messages are **delivered**. A session running `bypassPermissions` **holds** them for approval instead. Pin this rather than discovering it later — it is the difference between a tool that works and one that silently queues. - Protocol: send `{"type":"auth","token":"<CLAUDE_CODE_MESSAGING_TOKEN>"}` as the first line. Optional on Linux, required on Windows; send it always. - Open the connection **only when the payload is ready** — claude closes a connection idle for 30s. ## Resolving the socket Each session's socket is named for its claude pid. Resolution has to go from a `sessions` row to that pid. Note `procps` is **not installed** in the worker image (AGENTS.md fact #5) — walk `/proc/[0-9]*/cmdline` directly, as `checkSessionHealth` already does, and reuse its `kind`-dispatching match: `kind='session'` matches the full `--remote-control "<workspace> · <name>"` argv precisely so one Remote Control process does not satisfy every session's probe. ## Out of scope `sendNudge` stays where it is. Artifact feedback submission is not in scope; whether it should also migrate is a follow-up. **Do not build a mailbox or session-to-session messaging.** Claude Code already does it, and Nexus made its own fleet addressable without meaning to — `ListAgents` from inside a worker returned 28 peers, sibling sessions over a Unix socket plus sessions in *other* Nexus workers via Remote Control. A Nexus mailbox would be a worse copy of something with inbound controls, loop throttling, burst caps, a 100-message hold queue, and the no-consent guarantee above. ## Done when A message sent through the tool appears in the target session as a cross-session message; a `bypassPermissions` session is observed to hold rather than deliver it; and the auth line, the 30s idle close and the pid resolution each have a test proven able to fail.
lz added this to the MCP support (#140) milestone 2026-09-15 18:25:32 +02:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lz/agent-nexus#158
No description provided.