- infrastructure-control: add Section 5.3 (Network Verification & Routing) with dual-path checks, NetBird ingress health, DNS drift detection, and routing regression alerts. Add Section 7 (Configuration Doctrine — IP-First) mandating LAN IPs for all configs/agents, URLs reserved for human browser access only. Also enrich access matrix (Mumuni, Koonimo, LiteLLM Admin, Grafana entries), reachability matrix, and CT 116 nginx routing + Prometheus targets. - build-zulip-plugin: fold Success Criteria into Maintains postconditions. - pi-approval-architecture: new reference doc — pi approval model vs Hermes, architectural limits, /approve and /deny stub commands. - zulip-approval-fix: new responsibility — documents the Zulip HTML/prefix bug that broke /approve and /deny, and the one-line fix applied.
2.6 KiB
2.6 KiB
kind, name, description, agent, version, status
| kind | name | description | agent | version | status |
|---|---|---|---|---|---|
| responsibility | zulip-approval-fix | Fixes broken /approve and /deny slash commands for Hermes agents in Zulip. Zulip delivers messages as HTML (<p>/approve</p>), but the gateway's slash command parser expects plain text. HTML tags prevent command matching. | abiba | 2.0.0 | deployed |
Root Cause
The Hermes gateway ALREADY has native /approve and /deny handling via
slash_commands.py:_handle_approve_command(). No custom approval interception
is needed in the platform adapter.
The bug: Zulip's API returns message content as rendered HTML
(<p>/approve session</p>), but the gateway's slash command prefix matcher
checks text.startswith("/approve"). The <p> tag prevents matching.
Fix (Applied)
One line added to ~/.hermes/plugins/platforms/zulip/adapter.py:
content = msg.get("content", "")
content = _strip_html(content) # Strip Zulip HTML for /commands
Plus a small _strip_html() helper that strips HTML tags and decodes entities.
How the Full Flow Works
- Agent tries dangerous command →
check_all_command_guards() - Gateway's
_approval_notify_syncsends approval prompt viasend() - User sees: "⚠️ Dangerous command requires approval — Reply /approve or /deny"
- User types
/approve sessionin Zulip - Zulip API returns
<p>/approve session</p> - Adapter strips HTML →
/approve session - Gateway's slash command handler matches
/approve _handle_approve_commandcallsresolve_gateway_approval(session_key, "session")- Agent thread unblocks, command executes
Gateway Slash Commands Supported
| Command | Effect |
|---|---|
/approve |
Approve once |
/approve session |
Approve for this session |
/approve always |
Permanently approve this pattern |
/approve all |
Approve ALL pending commands |
/approve all session |
Approve all + remember session |
/deny |
Deny oldest pending |
/deny all |
Deny all pending |
Files Changed
| File | Host | Change |
|---|---|---|
~/.hermes/plugins/platforms/zulip/adapter.py |
.122, .123 | +_strip_html() helper + HTML stripping in message handler |
Deployed
- ✅ Mumuni (.123) — patched + gateway restarted
- ✅ Tanko (.122) — patched (jerome user), gateway restart pending
Verification
- Send DM: "run rm /tmp/test" to Mumuni/Tanko in Zulip
- Agent should respond with approval prompt: "⚠️ Dangerous command requires approval"
- Reply
/approve— agent should execute and respond - Reply
/deny— agent should block and explain why