Skip to content

Zulip @mention Quick Start

This quick start verifies a real Zulip trigger for ChatRSS: one Zulip account sends a message mentioning a ChatRSS-managed watcher account; the watcher account polls Zulip with its own API key; ChatRSS normalizes the mention into an event, routes it, plans actions, and writes a ledger. The complete actor -> watcher -> worker -> action-bot reply case is documented in real-world cases.

What was verified

Environment: controlled Zulip service environment with public entry and private credential storage

Platform:

  • Zulip URL: https://zulip.public.wzhecnu.cn
  • Stream: chatrss-quickstart
  • Topic: trigger-router-action

Accounts:

account role
watcher@example.invalid Sends the test message.
watcher@example.invalid / ChatRSS Watcher Bot ChatRSS-managed watcher; polls Zulip and detects mentions.
watcher@example.invalid / ChatRSS Agent Bot Action account used in the real reply case; external writes are not enabled by default.

The watcher credentials and API key are stored only in the task-local secrets file on the host with mode 0600; no password or API key is stored in this repository.

Flow

ChatRSS Actor
  -> sends a Zulip stream message mentioning @ChatRSS Watcher Bot
  -> Watcher polls Zulip messages API using its own API key
  -> Zulip message flags include mentioned
  -> ChatRSS normalizes the message into TriggerEvent
  -> Router/model stub decides act
  -> Action planner produces dry-run actions
  -> JSONL ledger records the whole chain

Verified message:

message_id: 16
permalink: https://zulip.public.wzhecnu.cn/#narrow/channel/chatrss-quickstart/topic/trigger-router-action/near/16
watcher_detected: true
mention_flag: true

Event envelope

{
  "source": "zulip",
  "connector": "zulip.messages",
  "event_type": "community.mention.created",
  "event_id": "zulip:message:16:mention:watcher@example.invalid",
  "subject": {
    "type": "zulip.message",
    "stream": "chatrss-quickstart",
    "topic": "trigger-router-action",
    "message_id": 16
  },
  "raw": {
    "mentioned": true,
    "flags": ["mentioned"]
  }
}

Router/action result

{
  "decision": "act",
  "model_used": "rule-router + deterministic model stub",
  "actions": [
    "internal.notify",
    "agent.run",
    "zulip.message.draft"
  ],
  "requires_approval": true
}

All actions were dry-run/draft only:

action result external write
internal.notify DRY_RUN_OK false
agent.run DRY_RUN_OK false
zulip.message.draft DRY_RUN_OK false

Validation artifacts

The validation script, ledger, JSON result, and report stay in a private task project. Public docs retain only non-sensitive message ids, event ids, action types, and workflow summaries; they do not expose hostnames, home paths, credential-file paths, or secret key names.

The reusable implementation target for ChatRSS is a future zulip.messages connector backed by a trigger job like:

id: zulip-watcher-mention
source: zulip
connector: zulip.messages
account: zulip-watcher
poll:
  interval_seconds: 30
  cursor: newest
filter:
  mentioned: true
  stream: chatrss-quickstart
context:
  read_topic: true
  max_messages: 50
actions:
  - internal.notify
  - agent.run
  - zulip.message.draft

Complete real reply case

The minimum quick-start acceptance can stop at dry-run / draft actions. The verified full case went further and executed a real reply:

Field Value
Actor message https://zulip.public.wzhecnu.cn/#narrow/channel/chatrss-quickstart/topic/trigger-router-action/near/20
Reply message https://zulip.public.wzhecnu.cn/#narrow/channel/chatrss-quickstart/topic/trigger-router-action/near/21
Event id zulip:message:20:mention:watcher@example.invalid
Action result SENT external_write=true message_id=21

The actor asked a worker to analyze OpenAI Codex differences across a regular account, ChatGPT Plus, and ChatGPT Pro for coding usage. ChatRSS captured the mention, routed it to act, ran a bounded research worker, and used the action bot to reply in the same Zulip topic. The normalized event, route decision, and ledger order are documented in real-world cases.