CI / validate (pull_request) Failing after 1s
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
5.5 KiB
5.5 KiB
Zulip Platform Plugins — Domain Vocabulary
Version: 2.0 (DM-First) Date: 2026-06-21
This document captures the shared language and architectural invariants for the multi-platform Zulip agent communication system under the DM-first architecture.
Domain Terms
| Term | Definition |
|---|---|
| Agent | An AI agent operating on a platform (Hermes/Agent Zero/PI) that can receive and respond to Zulip messages |
| Adapter / Plugin | A platform-native component that bridges Zulip events to the agent framework |
| DM (Direct Message) | A Zulip private message from a user directly to a bot. The primary communication channel for agent-owner interaction |
| @all-bots | A content-based mention detection pattern in #agent-hub stream. Detected via regex matching @**all-bots** or @**All Bots** in message content |
| #agent-hub | The shared stream used exclusively for @all-bots broadcasts. Agents ignore all non-@all-bots messages here |
| Stream | A Zulip channel for topic-based discussions. Only used for @all-bots broadcasts in this architecture |
| Topic | A Zulip conversation thread within a stream. Not used for agent routing in DM-first architecture |
| Owner | The human user associated with an agent bot, stored in per-agent config |
Naming Conventions
- Agent Zulip bot display names: lowercase, dash-separated,
-botsuffix — e.g.,tanko-bot,mumuni-bot - Agent Zulip bot emails:
@chat.sysloggh.net— e.g.,tanko-bot@chat.sysloggh.net - DM address:
@**tanko-bot**(same format as @mention, but sent as private message) - Owner privacy: agent should never expose owner name to other agents or users
- No private topics, no dedicated
@all-botsbot user
Agent Registry
| Agent | Platform | Zulip Bot | CT | DM Access | @all-bots Detection |
|---|---|---|---|---|---|
| tanko | Hermes (Python) | tanko-bot | amdpve CT 112 | ✅ Native Hermes | Regex on #agent-hub |
| mumuni | Hermes (Python) | mumuni-bot | minipve CT 114 | ❌ Not deployed | Regex on #agent-hub |
| koonimo | Hermes (Python) | koonimo-bot | amdpve CT 113 | ❌ Not deployed | Regex on #agent-hub |
| koby | Hermes (Python) | koby-bot | amdpve CT 111 | ❌ Not deployed | Regex on #agent-hub |
| kagentz | Agent Zero | kagentz-bot | amdpve CT 105 | ❌ Not deployed | Regex on #agent-hub |
| abiba | PI (TypeScript) | abiba-bot | amdpve CT 100 | ⚠️ Extension deployed but broken | Regex on #agent-hub |
DM-First Communication Flow
User sends DM to @tanko-bot
→ Zulip fires event ONLY to tanko-bot's event queue
→ Event has: {type: 'message', message: {type: 'private', ...}}
→ Bot detects: message.type === 'private'
→ No @mention parsing, no topic routing needed
→ Bot processes message
→ Bot replies via POST /api/v1/messages {type: 'private', to: [sender_id]}
Key invariants:
- Bot receives events ONLY when the bot is the DM recipient
message.type === 'private'is trivially detectable with no Zulip SDK version dependency- Reply goes to the same DM thread — Zulip handles threading
- No
mentioned_usersfield is checked or used - No stream subscription needed for DM communication
@all-bots Resolution
@all-bots uses content-based detection on #agent-hub stream messages — no dedicated bot user:
/@\*\*(?:all-bots|All Bots)\*\*/i
- Each bot subscribes to
#agent-hubstream exclusively for@all-botsdetection - Each bot receives every message in
#agent-hub(Zulip push model) - Each bot checks: "Does content match the @all-bots regex?"
- If match: bot forwards the full message to its agent for processing
- If no match: bot ignores the message entirely
- There is NO dedicated "All Bots" Zulip bot user
Response Rules
- DM (primary): Agent always responds to the sender's DM — no routing logic needed
- #agent-hub (broadcast only): Agent responds only when
@all-botsis detected in message content - Non-@all-bots messages: All agents ignore any message in
#agent-hubthat does not contain@all-bots - No private topics, no @mention of individual agents in streams — DMs replace both patterns
Response Rules for Agent-Owner DM
- Owner sends DM to bot → agent processes and replies
- Bot processes ALL DMs from ANY Zulip user (API key is the only access gate)
- Agent owner email in config is for identification, not ACL enforcement
- Future: rate limiting and spam protection via Zulip's built-in rate limiting
Monorepo Structure
All 3 platform plugins live in a single Gitea repository at git@git.sysloggh.net:SyslogSolution/zulip-platform-plugins.git
zulip-platform-plugins/
├── hermes-zulip-plugin/ # Hermes Python adapter (4 agents)
├── pi-zulip-extension/ # PI TypeScript extension (abiba)
├── agent-zero-plugin/ # Agent Zero Python plugin (kagentz)
├── scripts/ # deploy.sh, rollback.sh
├── docs/ # ADRs, ARCHITECTURE.md, PRD.md, CONTEXT.md
├── config.yaml.example # Template for per-agent config
└── .gitea/ # PR template, workflows (if CI enabled)
Guardian Directives
- All destructive actions require user confirmation before execution
- Plugin updates are version-controlled through Gitea
- Config files are per-agent and pushed alongside code
- DM-first architecture means no @mention-related Zulip SDK features are relied upon
- Pi extension on CT 100 has a broken Zulip client connection that needs repair