> ## Documentation Index
> Fetch the complete documentation index at: https://prism.ntecdev.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-34: ADR-34

> # 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}` w

<Info>**Status:** `accepted` · **ADR-34** · Filed 2026-04-30</Info>

# 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`
