From c0191c9edc5f2d14e848f0ae57c6034537b9f84d Mon Sep 17 00:00:00 2001 From: Jerome Tabiri Date: Wed, 8 Jul 2026 03:19:01 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20hermes-zulip-restore=20contract=20?= =?UTF-8?q?=E2=80=94=20restore=20Zulip=20on=20any=20Hermes=20agent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- hermes-zulip-restore.prose.md | 188 ++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 hermes-zulip-restore.prose.md diff --git a/hermes-zulip-restore.prose.md b/hermes-zulip-restore.prose.md new file mode 100644 index 0000000..401468b --- /dev/null +++ b/hermes-zulip-restore.prose.md @@ -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 `/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-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 `. + +### 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-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-agent/plugins/platforms/zulip/ + +# Fix ownership (Tanko only) +chown -R jerome:jerome /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-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" /.env +``` + +Expected: all three variables set with non-empty values. If any missing: +- ZULIP_SITE: `https://chat.sysloggh.net` +- ZULIP_EMAIL: `-bot@chat.sysloggh.net` +- ZULIP_API_KEY: obtain from Zulip admin panel (Bots → show API key) + +### Step 5: Restart Gateway + +```bash +cd /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" /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" /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 `/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 `

/approve

` | 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.