feat: hermes-zulip-restore contract — restore Zulip on any Hermes agent
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
Deploys zulip-platform adapter to bundled plugin path, verifies env credentials, restarts gateway, and validates Zulip connection. Covers Mumuni (CT114), Tanko (CT112), Koby (CT111). Includes _strip_html slash-command fix, known failure modes, and owner-aware restart paths.
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
---
|
||||
kind: function
|
||||
name: hermes-zulip-restore
|
||||
description: >
|
||||
Restores Zulip connectivity for any Hermes agent (Mumuni CT114, Tanko CT112,
|
||||
Koby CT111). Deploys the zulip-platform adapter to the correct bundled plugin
|
||||
path, verifies env credentials, restarts the gateway, and confirms Zulip
|
||||
connects. Run this whenever a Hermes agent stops responding on Zulip or after
|
||||
a fresh agent deployment.
|
||||
agent: abiba
|
||||
version: 1.0.0
|
||||
status: active
|
||||
runtime_contract: 2
|
||||
---
|
||||
|
||||
# Hermes Zulip Restore — Bring Any Agent Back to Good State
|
||||
|
||||
Single-shot function that restores full Zulip connectivity for a Hermes agent.
|
||||
Covers adapter deployment, HTML stripping (slash command fix), env verification,
|
||||
gateway restart, and connection validation.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Param | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `target` | string | yes | — | Agent name: `mumuni`, `tanko`, or `koby` |
|
||||
|
||||
## Maintains
|
||||
|
||||
- adapter_deployed: bool — Whether `_strip_html` adapter is at correct bundled path
|
||||
- zulip_connected: bool — Whether gateway_state shows zulip.state = "connected"
|
||||
- env_valid: bool — Whether .env has ZULIP_SITE, ZULIP_EMAIL, ZULIP_API_KEY
|
||||
- gateway_running: bool — Whether gateway process is running
|
||||
|
||||
### Postconditions
|
||||
|
||||
- `_strip_html` function present in `<hermes-agent>/plugins/platforms/zulip/adapter.py`
|
||||
- All three adapter files (__init__.py, adapter.py, plugin.yaml) present at bundled path
|
||||
- Zulip env vars set in `~/.hermes/.env` (or `/home/jerome/.hermes/.env` for Tanko)
|
||||
- Gateway restarted and zulip platform reports state `connected`
|
||||
- HTML stripping enabled for `/approve` and `/deny` slash command support
|
||||
|
||||
## Requires
|
||||
|
||||
- SSH access to target host (direct or via amdpve for CTs)
|
||||
- Git repo at `https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git`
|
||||
- Python 3 with `httpx` installed on target
|
||||
- Zulip server accessible at `https://chat.sysloggh.net`
|
||||
|
||||
## Live-State Fields
|
||||
|
||||
| Host | CT | Proxmox | IP (direct) | Hermes Home | User |
|
||||
|------|-----|---------|-------------|-------------|------|
|
||||
| Mumuni | CT114 | — | 192.168.68.123 | /root/.hermes | root |
|
||||
| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome |
|
||||
| Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root |
|
||||
|
||||
| Field | Value | Trust |
|
||||
|-------|-------|-------|
|
||||
| Zulip server | https://chat.sysloggh.net | ✅ Verified |
|
||||
| Git repo (zulip-platform) | `https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git` | ✅ Verified |
|
||||
| Bundled adapter path | `<HERMES_HOME>/hermes-agent/plugins/platforms/zulip/` | ✅ Verified |
|
||||
| Git branch | `feat/zulip-streaming` | ✅ Verified (contains _strip_html fix) |
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 1: Locate Target
|
||||
|
||||
Map `target` to connectivity parameters from the live-state table above.
|
||||
For CT112 and CT111, route through `ssh root@amdpve` then `pct exec <id>`.
|
||||
|
||||
### Step 2: Deploy Zulip Adapter
|
||||
|
||||
On the target host:
|
||||
|
||||
```bash
|
||||
# Clone or update the plugin repo
|
||||
mkdir -p /tmp/zulip-deploy
|
||||
cd /tmp/zulip-deploy
|
||||
if [ -d zulip-platform-plugins ]; then
|
||||
cd zulip-platform-plugins && git pull origin feat/zulip-streaming
|
||||
else
|
||||
git clone --branch feat/zulip-streaming \
|
||||
https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git
|
||||
fi
|
||||
|
||||
# Ensure bundled plugin directory exists
|
||||
mkdir -p <HERMES_HOME>/hermes-agent/plugins/platforms/zulip
|
||||
|
||||
# Copy adapter files
|
||||
cp zulip-platform-plugins/plugins/platforms/zulip/adapter.py \
|
||||
zulip-platform-plugins/plugins/platforms/zulip/__init__.py \
|
||||
zulip-platform-plugins/plugins/platforms/zulip/plugin.yaml \
|
||||
<HERMES_HOME>/hermes-agent/plugins/platforms/zulip/
|
||||
|
||||
# Fix ownership (Tanko only)
|
||||
chown -R jerome:jerome <HERMES_HOME>/hermes-agent/plugins/platforms/zulip/ # Tanko only
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/zulip-deploy
|
||||
```
|
||||
|
||||
### Step 3: Verify _strip_html is Present
|
||||
|
||||
```bash
|
||||
grep -q "_strip_html" <HERMES_HOME>/hermes-agent/plugins/platforms/zulip/adapter.py
|
||||
```
|
||||
Expected: exit code 0. If not found → adapter is stale, re-run Step 2 with fresh clone.
|
||||
|
||||
### Step 4: Verify Env Credentials
|
||||
|
||||
```bash
|
||||
grep -E "ZULIP_SITE|ZULIP_EMAIL|ZULIP_API_KEY" <HERMES_HOME>/.env
|
||||
```
|
||||
|
||||
Expected: all three variables set with non-empty values. If any missing:
|
||||
- ZULIP_SITE: `https://chat.sysloggh.net`
|
||||
- ZULIP_EMAIL: `<agent>-bot@chat.sysloggh.net`
|
||||
- ZULIP_API_KEY: obtain from Zulip admin panel (Bots → show API key)
|
||||
|
||||
### Step 5: Restart Gateway
|
||||
|
||||
```bash
|
||||
cd <HERMES_HOME>/hermes-agent
|
||||
# Use venv if available
|
||||
python3 -m hermes_cli.main gateway restart # or: venv/bin/python -m hermes_cli.main gateway restart
|
||||
```
|
||||
|
||||
Wait for the restart to complete (up to 45s). Check:
|
||||
|
||||
```bash
|
||||
grep "Gateway running" <HERMES_HOME>/logs/gateway.log | tail -1
|
||||
```
|
||||
|
||||
Expected: "Gateway running with N platform(s)" where N > 1 (includes zulip).
|
||||
|
||||
### Step 6: Validate Zulip Connection
|
||||
|
||||
```bash
|
||||
python3 -c "
|
||||
import json
|
||||
d = json.load(open('$HERMES_HOME/gateway_state.json'))
|
||||
print('zulip:', d.get('platforms', {}).get('zulip', {}).get('state', 'NOT FOUND'))
|
||||
"
|
||||
```
|
||||
|
||||
Expected: `zulip: connected`. If not connected, check gateway log:
|
||||
|
||||
```bash
|
||||
grep -E "zulip|Zulip|ZULIP" <HERMES_HOME>/logs/gateway.log | tail -10
|
||||
```
|
||||
|
||||
### Step 7: Report
|
||||
|
||||
Compile results: `{ adapter_deployed, zulip_connected, env_valid, gateway_running }`.
|
||||
|
||||
| State | Action |
|
||||
|-------|--------|
|
||||
| All true | ✅ Agent restored — relay success to user |
|
||||
| `adapter_deployed: false` | Re-run Step 2 |
|
||||
| `env_valid: false` | Prompt for missing credentials |
|
||||
| `zulip_connected: false` | Check Zulip server reachability, verify API key |
|
||||
| `gateway_running: false` | Check process logs for crash cause |
|
||||
|
||||
## Known Failure Modes
|
||||
|
||||
| Symptom | Root Cause | Recovery |
|
||||
|---------|-----------|----------|
|
||||
| Gateway running with 1 platform(s) | Adapter at wrong path (user plugins vs bundled) | Deploy to `<hermes-agent>/plugins/platforms/zulip/` not `~/.hermes/plugins/` |
|
||||
| Queue expired / BAD_EVENT_QUEUE_ID | Idle for 10+ minutes → normal | Auto-reconnects — no action needed |
|
||||
| No events received for N seconds | No DMs or @mentions sent to this bot | Normal if nobody messaged the agent |
|
||||
| `httpx` not found | Missing dependency | `pip install httpx` in the Hermes venv or system Python |
|
||||
| Slash commands not matching | Missing `_strip_html` — Zulip sends `<p>/approve</p>` | Verify `_strip_html` in adapter (Step 3) |
|
||||
| Permission denied on gateway restart | Running as wrong user | Use `su - jerome` for Tanko; root for others |
|
||||
|
||||
## Git Branch Reference
|
||||
|
||||
The `_strip_html` fix lives on `feat/zulip-streaming` branch:
|
||||
```
|
||||
https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins/src/branch/feat/zulip-streaming
|
||||
```
|
||||
|
||||
Commit `55ca15d` — `fix(zulip): add _strip_html for slash command matching`
|
||||
Pull request #33 is the primary integration branch.
|
||||
|
||||
---
|
||||
|
||||
**Last verified good state**: 2026-07-08 — Mumuni, Tanko, Koby all connected with `_strip_html` applied.
|
||||
Reference in New Issue
Block a user