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
3.3 KiB
ADR 1: DM-First Communication Topology
Date: 2026-06-21 (supersedes 2026-04-28 topic-based topology)
Decision
Each agent communicates primarily via Zulip Direct Messages (DMs). The #agent-hub stream is retained as an optional broadcast-only channel for inter-agent coordination, @all-bots announcements, and cross-agent visibility. Agent-private topics (<agent>-private) are deprecated in favor of native Zulip DMs.
Context
Zulip bots are regular user accounts — any user can send a private message to any bot by composing a DM with the bot as the sole recipient. The bot's event queue then receives an event with message.type: 'private', which requires no @mention detection, no topic parsing, no stream subscription checks.
The original design used topics under #agent-hub with @mention routing, but this introduced several failure modes:
| Problem | Impact |
|---|---|
mentioned_users field not populated by Zulip 12.0 SDK |
@mention detection silently fails |
| Topic routing required capturing origin topic + stream for reply | Added parsing complexity |
| All 6 bots subscribed to same stream | Every bot receives every message, wasting resources |
type:'stream' events different from type:'private' |
Required additional event filtering logic |
DMs solve all of this natively:
- Every DM is inherently for the bot recipient — no @mention needed
- Reply in the same DM thread — Zulip handles threading
- Only the recipient bot sees the message — no broadcast noise
message.type: 'private'is trivially detectable
Architecture Change
Before (Deprecated):
User @mentions @tanko-bot in #agent-hub > tanko-private
→ Zulip fires event to ALL 6 bot event queues
→ Each bot checks mentioned_users for its user_id
→ Only matching bot processes the event
→ Bot replies to same stream+topic
After (DM-First):
User DMs @tanko-bot directly
→ Zulip fires event ONLY to tanko-bot's event queue
→ Bot receives message.type: 'private'
→ No @mention detection, no topic parsing
→ Bot processes and replies in same DM thread
Consequences
- Positive: Dramatically simpler event processing — no @mention detection, no topic routing, no mentioned_users dependency, no stream subscription requirement
- Positive: Each bot only receives its own messages — less noise, less resource usage
- Positive: Zulip's native DM threading handles all reply routing automatically
- Positive: No need to subscribe all 6 bots to
#agent-hubstream (except for@all-botsbroadcast capability) - Negative: Single #agent-hub stream topic no longer shows all agent activity in one timeline
- Negative: Cross-agent visibility requires
@all-botsbroadcast or agents explicitly CC each other - Neutral:
#agent-hubstream is retained for:@all-botsbroadcasts, inter-agent coordination, and user-initiated multi-agent topics
Migration Path
- All plugins listen for
type: 'private'events as primary communication channel #agent-hubstream listener is secondary — only for@all-botsbroadcast detection- Existing
<agent>-privatetopics are deprecated but not deleted (grace period) - Owners communicate with their agents via DM, not via private topics
@all-botscontinues to work in#agent-hubfor cross-platform broadcasts