Loading repository dataβ¦
Loading repository dataβ¦
niyazmft / repository
π¬ High-performance Zulip channel plugin for OpenClaw AI Gateway. Enables seamless bridge between Zulip streams/DMs and agentic AI runtimes with durable deduplication and rich feedback.
High-performance OpenClaw channel plugin for Zulip streams and private messages with persistent event queues, traffic policies, and comprehensive observability.
π‘ The simplest way to get started: Install from ClawHub, restart the gateway, then run the interactive onboarding wizard.
# 1. Install from ClawHub
openclaw plugins install clawhub:@niyazmft/openclaw-zulip
# 2. Restart the gateway
openclaw gateway restart
# 3. Run the interactive channel setup wizard
openclaw channels add
# β Select "Zulip (plugin)" β enter API key, email, URL β route to agent
# 4. Approve yourself for DMs (dmPolicy defaults to "pairing")
# Send a DM to your bot first, then copy the pairing code and run:
openclaw pairing approve zulip <PAIRING_CODE>
# 5. Test
# Send a DM to your bot or mention it in a stream
That's it β no manual config editing needed.
oncall, onmessage, and onchar modes.>=2026.6.0ZULIP_API_KEYZULIP_EMAILThe simplest path β install from ClawHub, restart, then use the built-in wizard:
# Install
openclaw plugins install clawhub:@niyazmft/openclaw-zulip
# Restart gateway (required for the host to load the new plugin)
openclaw gateway restart
# Run the interactive setup wizard
openclaw channels add
# β Select "Zulip (plugin)" β follow the prompts
β οΈ Do NOT clone directly into
~/.openclaw/extensions/zulip. This creates a stale config entry that blocks reinstallation. Always clone to a neutral directory first.
Pre-flight check (verify your environment):
# Check OpenClaw version (>= 2026.6.0 recommended)
openclaw --version
# Ensure no stale zulip config exists
openclaw plugins list --json | grep zulip
If you see a stale config warning, run cleanup first:
openclaw plugins uninstall zulip --force
Clone and build:
# Clone to a neutral directory (NOT inside ~/.openclaw/extensions/)
git clone https://github.com/niyazmft/openclaw-zulip-bridge.git /tmp/openclaw-zulip-bridge
cd /tmp/openclaw-zulip-bridge
pnpm install
pnpm run build
openclaw plugins install ./ --link
openclaw plugins doctor
openclaw plugins list --json | python3 -c "import json,sys; z=[p for p in json.load(sys.stdin).get('plugins',[]) if p['id']=='zulip']; print('OK' if z and z[0]['activated'] else 'FAIL')"
openclaw channels add
# Select "Zulip (plugin)" and follow the prompts
This plugin has zero production npm dependencies. You can build it on a connected machine, then copy the folder to an offline machine:
# On the connected machine:
git clone https://github.com/niyazmft/openclaw-zulip-bridge.git /tmp/zulip-bridge
cd /tmp/zulip-bridge
pnpm install
pnpm run build
Then on the offline machine, from the copied folder:
openclaw plugins install ./ --link
openclaw channels add
# Select "Zulip (plugin)" and follow the prompts
Run the built-in channel onboarding wizard:
openclaw channels add
Then at the interactive prompts:
main)After setup, if dmPolicy is "pairing", send a DM to your bot and approve yourself:
openclaw pairing approve zulip <PAIRING_CODE_FROM_ZULIP_DM>
Tip: If
ZULIP_API_KEY,ZULIP_EMAIL, andZULIP_URLare set as environment variables, the wizard uses them automatically.
For advanced users, add to your openclaw.json:
{
"channels": {
"zulip": {
"enabled": true,
"dmPolicy": "pairing",
"streams": ["*"]
}
}
}
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Enable the Zulip channel |
dmPolicy | string | "pairing" | Who can DM the bot: "open" (anyone), "allowlist" (specific users), "pairing" (must pair first), "disabled" (ignore DMs) |
streams | string[] | ["*"] | Streams to monitor ("*" = all) |
blockStreaming | boolean | false | Enable block streaming for responses |
chatmode | string | "onmessage" | Stream trigger mode: "oncall", "onmessage", "onchar" |
name | string | - | Optional display name for the account |
email | string | - | Bot email address |
apiKey | string | - | Bot API key |
url / site / realm | string | - | Zulip server URL |
allowFrom | string[] | - | DM allowlist (user emails) |
groupAllowFrom | string[] | - | Group/stream allowlist |
groupPolicy | string | "allowlist" | Group policy: "open", "allowlist" |
requireMention | boolean | true | Require @mention in streams |
oncharPrefixes | string[] | [">", "!"] | Trigger characters for onchar mode |
mediaMaxMb | number |
| Variable | Required | Description |
|---|---|---|
ZULIP_API_KEY | Yes | Bot API key from Zulip |
ZULIP_EMAIL | Yes | Bot email address |
ZULIP_URL | Yes | Zulip server URL (e.g., https://chat.example.com) |
After setup, verify the bridge works:
Check plugin status:
openclaw plugins doctor
Check Logs: Look for success marker:
zulip queue registered [accountId=default queueId=... lastEventId=...]
Test Direct Message: Send a DM to the bot
Test Stream: Mention @bot-name in a monitored stream
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OpenClaw Gateway β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Zulip Plugin (index.ts) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β ββββββββββββββββ βββββββββββββββ ββββββββββββββββββ β
β β monitor βββββΆβ client βββββΆβ Zulip API β β
β β (polling) β β (requests) β β (REST/WebSocket)β β
β ββββββββββββββββ βββββββββββββββ ββββββββββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β reply-handler.ts β β
β β - Markdown processing β β
β β - Text chunking β β
β β - Typing indicators β β
β β - Media handling β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Cause: The plugin was installed but "zulip" is not in plugins.allow.
Fix:
openclaw config set plugins.allow '["zulip","telegram","memory-core","exa","ollama"]'
openclaw gateway restart
Status: Harmless β the host calls registerFull twice during startup. The plugin deduplicates this.
Cause: The monitor's statusSink({ running: true }) wasn't called at the start of the monitor loop, so the host thinks the channel is dead.
Fix: Ensure statusSink is called at the top of the monitor function, not conditionally inside event handlers.
Cause: The manifest JSON Schema in openclaw.plugin.json was missing the streaming property that the host wizard writes.
Fix: Add "streaming": { "type": "boolean" } to both configSchema and channelConfigs.schema in the manifest.
Install from ClawHub:
openclaw plugins install clawhub:@niyazmft/openclaw-zulip
Or from source without --link:
rm -rf scripts/
openclaw plugins install ./ --force
openclaw gateway restartls ~/.openclaw/extensions/zulip/Ensure you cloned to a neutral directory and ran pnpm install && pnpm run build.
Verify credentials with openclaw channels add and re-enter them.
5| Maximum media upload size (MB) |
textChunkLimit | number | 4000 | Text chunk size limit |
chunkMode | string | "length" | Chunking mode: "length", "newline" |
reactions | boolean | true | Enable reaction-based status indicators |
streaming | boolean | true | Enable receiving streaming messages |
responsePrefix | string | - | Custom response prefix override |