Skip to main content
Status: accepted · ADR-34 · Filed 2026-04-30

Title

Agent DM channel is keyed on agent_id, not session_id

Decision

Replace the per-session Redis pubsub channel prism:events:session:{session_id} with a per-agent channel prism:events:agent:{agent_id}. WS subscribers (mcp-node stream) subscribe to their agent_id channel at connect time; backend’s signal-publish targets the resolved agent_id and publishes to that stable channel. Each new agent_session (post-restart, post-machine-move) subscribes to the same channel.

Rationale

The session-keyed channel design tied delivery to a process-lifetime ID. When an agent wraps and restarts:
  1. Pending signals queued for the old session_id had no live subscriber; they only delivered via piggyback (HTTP poll), which bypasses the WS stream subscriber where signalCache.record() writes the per-identity ring file.
  2. Result: bell+count permanently dark even when signals were arriving — they came in via the wrong code path.
  3. Workarounds (replay across sessions, transfer pending across IDs) all add complexity without addressing the root issue: the routing target was the wrong abstraction.
Keying on agent_id makes the channel the agent’s mailbox, not the current process’s port. Continuity across wraps becomes automatic: same channel, new subscriber on next prism_start. Pending signals deliver as soon as a subscriber is alive again — no special mechanism needed. This also paves the way for cross-machine continuity (Donna on mini1 in morning, mini3 in afternoon — same agent_id, same channel) and the future Enterprise Agent Services pattern (catalogue services may have multiple instantiations across projects, each with its own agent_id). session_id (now agent_session_id) remains useful for heartbeat tracking, master election, audit (which process emitted/received this signal), and lifecycle (which process to terminate when wrap is called). It is not in any routing channel name.

Alternatives Considered

  1. Keep session-keyed channels, add a server-side replay-on-reconnect mechanism. Trades one architecture seam (process-keyed channel) for another (replay correctness). The agent_id channel is simpler and exercises fewer code paths.
  2. Multi-channel subscription per agent (session + agent). Considered; rejected because it doubles subscriber counts and requires deduplication on the receive side. Single agent_id channel is the cleaner contract.
  3. Continue session-keyed and require all consumers to drain via piggyback poll. Status quo for SPEC-054 Phase 3 — observed broken in practice; the bell never lights up. Rejected.

Status

accepted

References

  • SPEC-056 §Channel naming
  • Memory: project_spec_054_port_miss_project_id
Last modified on May 3, 2026