Files
zulip-platform-plugins/docs/adr/ADR-002-dm-routing.md
T
kagentz-bot 705c29a4e0
CI / validate (pull_request) Failing after 1s
feat: DM-First v2 architecture - Tanko live on CT 112
Architecture change: DM-First (v2) replaces @mention-in-stream (v1) as primary
agent interaction channel. See ADR-001-dm-topology and ADR-002-dm-routing.

Key changes:
- New DM-first Zulip adapter (adapter_dm.py) deployed on CT 112
  - Registers empty narrow to receive ALL events
  - Demuxes DMs (type: 'private') vs stream events
  - Replies to DMs back in private thread, stream replies to #agent-hub
  - Uses blocking long-poll (dont_block=False) to eliminate rate limiting
- Rewritten ARCHITECTURE.md, CONTEXT.md, PRD.md for v2 DM-First
- New ADRs: ADR-001 (DM Topology), ADR-002 (DM Routing)
- Archived old ADRs: 001, 002, 005 (topic-topology, mention-routing, mention-detection)
- Updated ADRs: 003 (agent-naming), 004 (per-agent-bots), 006 (all-bots-model)
- Updated PI extension (index.ts) with DM-aware patterns
- Tanko agent confirmed responding in both DM and @all-bots in #agent-hub
2026-06-21 07:50:30 -04:00

2.5 KiB

ADR 2: DM-First Routing

Date: 2026-06-21 (supersedes 2026-04-28 @mention-based routing)

Decision

Agents are triggered primarily by Zulip Direct Messages (DMs). Users send a DM to any agent's bot user (e.g., @tanko-bot) to communicate with that agent. Stream-based @mention routing is deprecated for agent-owner communication but retained for @all-bots broadcasts and multi-agent coordination in #agent-hub.

Context

The original design required users to @mention an agent in #agent-hub stream topics. This proved unreliable because:

  1. Zulip 12.0 SDK may not populate mentioned_users on stream message events
  2. Every bot subscribed to #agent-hub receives every message — wasteful
  3. Topic routing (capturing origin stream + topic for reply) adds parsing complexity
  4. Distinguishing type: 'stream' vs type: 'private' required extra event filtering

DMs eliminate all of these concerns:

  • Only the recipient bot receives the DM — no broadcast noise
  • No @mention parsing needed — the DM itself is the signal
  • No topic/stream capture needed — reply in the same DM thread
  • message.type: 'private' is trivially detectable in the event queue

DM Event Flow

User sends DM to @tanko-bot
  → Zulip pushes event to tanko-bot's event queue
  → Event has: {type: 'message', message: {type: 'private', ...}}
  → Bot checks: message.type === 'private' (trivial)
  → Bot reads message.content, processes, responds
  → Bot sends reply to same DM via /api/v1/messages with
    {type: 'private', to: [user_id], content: 'response'}

@all-bots Exception

The stream-based approach is retained only for @all-bots broadcasts:

  • @all-bots in #agent-hub → all bots detect the mention and respond
  • This remains necessary for cross-platform broadcasts
  • Detection can use Zulip SDK mentioned_users or content-based @**All Bots** matching

Consequences

  • Positive: Dramatically simpler routing logic — no @mention parsing, no topic/stream tracking
  • Positive: Each bot only processes its own DMs — no wasted event processing
  • Positive: Zulip's native DM threading handles all reply threading automatically
  • Positive: No dependency on mentioned_users field behavior in Zulip 12.0
  • Negative: Owners must DM their agent directly instead of using stream topics
  • Negative: Cross-agent visibility in stream topics is reduced (mitigated by @all-bots)
  • Neutral: @all-bots in #agent-hub still uses the original @mention detection pattern