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
This commit is contained in:
+76
-26
@@ -1,59 +1,109 @@
|
||||
# Zulip Platform Plugins — Domain Vocabulary
|
||||
|
||||
This document captures the shared language and architectural invariants for the multi-platform Zulip agent communication system.
|
||||
**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 |
|
||||
| **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 |
|
||||
| **@mention** | A Zulip mention (`@**Tanko Bot**`) that triggers the named agent to respond |
|
||||
| **@all-bots** | A dedicated Zulip bot user that, when @mentioned, triggers ALL agents across all platforms |
|
||||
| **Topic** | A Zulip conversation thread within a stream |
|
||||
| **Private topic** | An agent-named topic (e.g., `tanko-private`) where only the bot and its owner participate |
|
||||
| **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, `-bot` suffix — e.g., `tanko-bot`, `mumuni-bot`
|
||||
- Agent Zulip bot emails: `@chat.sysloggh.net` — e.g., `tanko-bot@chat.sysloggh.net`
|
||||
- Private topics: `{name}-private` — e.g., `tanko-private`
|
||||
- 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-bots` bot user
|
||||
|
||||
## Agent Registry
|
||||
|
||||
| Agent | Platform | Zulip Bot | CT | Private Topic |
|
||||
|-------|----------|-----------|-----|---------------|
|
||||
| tanko | Hermes (Python) | tanko-bot | amdpve CT 112 | tanko-private |
|
||||
| mumuni | Hermes (Python) | mumuni-bot | minipve CT 114 | mumuni-private |
|
||||
| koonimo | Hermes (Python) | koonimo-bot | amdpve CT 113 | koonimo-private |
|
||||
| koby | Hermes (Python) | koby-bot | amdpve CT 111 | koby-private |
|
||||
| kagentz | Agent Zero | kagentz-bot | amdpve CT 105 | kagentz-private |
|
||||
| abiba | pi (TypeScript) | abiba-bot | amdpve CT 100 | abiba-private |
|
||||
| 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_users` field is checked or used
|
||||
- No stream subscription needed for DM communication
|
||||
|
||||
## @all-bots Resolution
|
||||
|
||||
@all-bots refers to all 6 agents across all frameworks (Hermes, Agent Zero, pi). When @all-bots is mentioned in any topic:
|
||||
1. Each per-agent bot receives the event (since they all share `narrow: stream agent-hub`)
|
||||
2. Each bot checks: "Is `All Bots` in `mentioned_users`?"
|
||||
3. If yes, bot forwards the message to its agent
|
||||
4. @all-bots is a **dedicated Zulip bot user** with display name `All Bots` and email `all-bots@chat.sysloggh.net`
|
||||
`@all-bots` uses **content-based detection** on `#agent-hub` stream messages — no dedicated bot user:
|
||||
|
||||
```regex
|
||||
/@\*\*(?:all-bots|All Bots)\*\*/i
|
||||
```
|
||||
|
||||
1. Each bot subscribes to `#agent-hub` stream exclusively for `@all-bots` detection
|
||||
2. Each bot receives every message in `#agent-hub` (Zulip push model)
|
||||
3. Each bot checks: "Does content match the @all-bots regex?"
|
||||
4. If match: bot forwards the full message to its agent for processing
|
||||
5. If no match: bot ignores the message entirely
|
||||
6. There is NO dedicated "All Bots" Zulip bot user
|
||||
|
||||
## Response Rules
|
||||
- **Own topic**: Agent always responds (to its private topic)
|
||||
- **Collaboration topic** (any topic that isn't a private topic): Agent responds only when @mentioned
|
||||
- **@all-bots**: All agents respond
|
||||
- **Private topics**: Only the agent owner + bot are participants; bot enforces this via config owner_email matching
|
||||
|
||||
## Private Topic ACL (v1 — documented limitation)
|
||||
- **DM (primary)**: Agent always responds to the sender's DM — no routing logic needed
|
||||
- **#agent-hub (broadcast only)**: Agent responds only when `@all-bots` is detected in message content
|
||||
- **Non-@all-bots messages**: All agents ignore any message in `#agent-hub` that does not contain `@all-bots`
|
||||
- **No private topics, no @mention of individual agents in streams** — DMs replace both patterns
|
||||
|
||||
In v1, private topic access is enforced by matching `sender_email == config.owner_email` on each message. **This is not cryptographically authenticated** — Zulip does not enforce sender identity. A user who knows the owner email can impersonate them. This is an acceptable limitation for v1 internal use. v2 should use Zulip invite-only stream permissions or shared-secret challenge-response.
|
||||
## 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
|
||||
|
||||
Reference in New Issue
Block a user