# 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 (`-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-hub` stream (except for `@all-bots` broadcast capability) - **Negative:** Single #agent-hub stream topic no longer shows all agent activity in one timeline - **Negative:** Cross-agent visibility requires `@all-bots` broadcast or agents explicitly CC each other - **Neutral:** `#agent-hub` stream is retained for: `@all-bots` broadcasts, inter-agent coordination, and user-initiated multi-agent topics ### Migration Path 1. All plugins listen for `type: 'private'` events as primary communication channel 2. `#agent-hub` stream listener is secondary — only for `@all-bots` broadcast detection 3. Existing `-private` topics are deprecated but not deleted (grace period) 4. Owners communicate with their agents via DM, not via private topics 5. `@all-bots` continues to work in `#agent-hub` for cross-platform broadcasts