--- kind: function name: hermes-zulip-plugin description: > Installs or updates the Zulip platform plugin for any Hermes agent from the canonical zulip-platform-plugins repo. Ensures the agent runs the latest adapter with all Zulip chat fixes (_strip_html, streaming, event recovery). Runs a post-install verification and sends a relay success signal. agent: abiba version: 1.0.0 status: active runtime_contract: 2 --- # Hermes Zulip Plugin — Install & Repair Single-shot function that pulls the latest zulip-platform plugin from the canonical git repo, installs it to the correct Hermes bundled plugin path, verifies the installation, and signals completion. Distinct from `hermes-zulip-restore`: this contract only touches the plugin layer. It does NOT verify env credentials, restart the gateway, or validate the live Zulip connection. Use `hermes-zulip-restore` for full connectivity recovery. ## Parameters | Param | Type | Required | Default | Description | |-------|------|----------|---------|-------------| | `target` | string | yes | — | Agent name: `mumuni`, `tanko`, or `koby` | | `branch` | string | no | `feat/zulip-streaming` | Git branch to pull (overridable for pinning) | ## Maintains - plugin_installed: bool — Whether all three adapter files exist at the bundled path - plugin_version: string — Git commit SHA of the installed version - strip_html_present: bool — Whether `_strip_html` fix is in the installed adapter - signal_sent: bool — Whether relay success message was dispatched ### Postconditions - All three adapter files (`__init__.py`, `adapter.py`, `plugin.yaml`) present in `/hermes-agent/plugins/platforms/zulip/` - `_strip_html` function exists in `adapter.py` (slash-command fix, commit `55ca15d`+) - Installed version matches HEAD of the requested branch - Relay success signal sent to Hermes agent's inbox ## 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 ## 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 | |-------|-------|-------| | Git repo | `https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git` | ✅ Verified | | Default branch | `feat/zulip-streaming` | ✅ Verified | | Bundled adapter path | `/hermes-agent/plugins/platforms/zulip/` | ✅ Verified | | Adapter files | `__init__.py`, `adapter.py`, `plugin.yaml` | ✅ Verified | | Strip-html commit | `55ca15d` (minimum) | ✅ Verified | ## Execution ### Step 1: Resolve Target Map `target` to host, CT ID, hermes_home, and user from the live-state table. For CT112 and CT111, route through `ssh root@amdpve` then `pct exec `. ### Step 2: Pull Latest Plugin Source On the target host: ```bash # Ensure deploy scratch space mkdir -p /tmp/zulip-deploy cd /tmp/zulip-deploy # Clone or pull if [ -d zulip-platform-plugins ]; then cd zulip-platform-plugins git fetch origin git checkout {{branch}} git pull origin {{branch}} else git clone --branch {{branch}} \ https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git cd zulip-platform-plugins fi # Capture installed version INSTALLED_SHA=$(git rev-parse HEAD) echo "Installed SHA: $INSTALLED_SHA" # Verify we're at HEAD HEAD_SHA=$(git rev-parse origin/{{branch}}) if [ "$INSTALLED_SHA" = "$HEAD_SHA" ]; then echo "At latest commit on {{branch}}" else echo "WARNING: not at HEAD — $INSTALLED_SHA vs $HEAD_SHA" fi ``` ### Step 3: Install Plugin Files ```bash # Ensure target directory exists mkdir -p {{hermes_home}}/hermes-agent/plugins/platforms/zulip # Copy adapter files cp plugins/platforms/zulip/adapter.py \ plugins/platforms/zulip/__init__.py \ plugins/platforms/zulip/plugin.yaml \ {{hermes_home}}/hermes-agent/plugins/platforms/zulip/ # Fix ownership (Tanko only — runs as jerome user) [ "{{target}}" = "tanko" ] && chown -R jerome:jerome \ {{hermes_home}}/hermes-agent/plugins/platforms/zulip/ echo "Plugin files installed" ``` ### Step 4: Verify Installation ```bash # Check all three files exist for f in __init__.py adapter.py plugin.yaml; do if [ -f "{{hermes_home}}/hermes-agent/plugins/platforms/zulip/$f" ]; then echo "✅ $f present" else echo "❌ $f MISSING" exit 1 fi done # Verify _strip_html fix grep -q "_strip_html" {{hermes_home}}/hermes-agent/plugins/platforms/zulip/adapter.py \ && echo "✅ _strip_html fix present" \ || echo "❌ _strip_html MISSING — plugin may be stale" # Show installed plugin.yaml version grep "^version:" {{hermes_home}}/hermes-agent/plugins/platforms/zulip/plugin.yaml || true ``` ### Step 5: Send Relay Success Signal On the Abiba host (local), dispatch a relay message to the target agent: ``` ra-h-os-createRelayNode: title: "Zulip plugin updated — {{target}}" source: | Plugin installed from {{branch}} @ {{INSTALLED_SHA}} All 3 adapter files verified at {{hermes_home}}/hermes-agent/plugins/platforms/zulip/ _strip_html fix: PRESENT Timestamp: {{timestamp}} description: "hermes-zulip-plugin completed for {{target}} — plugin layer healthy" ``` ### Step 6: Report Compile results into a single status block: | Field | Value | |-------|-------| | Target | `{{target}}` | | Branch | `{{branch}}` | | Commit SHA | `{{INSTALLED_SHA}}` | | Files installed | `__init__.py`, `adapter.py`, `plugin.yaml` | | `_strip_html` | `{{present|missing}}` | | Signal sent | `{{yes|no}}` | ## Known Failure Modes | Symptom | Root Cause | Recovery | |---------|-----------|----------| | Git clone fails | No network or repo unreachable | Check VPN/network, verify repo URL | | Permission denied on copy | Wrong user for target | Use correct user (jerome for Tanko, root for others) | | `_strip_html` missing after install | Branch doesn't include commit `55ca15d` | Switch to `feat/zulip-streaming` branch | | Plugin files missing after copy | Target directory doesn't exist | Ensure `mkdir -p` ran successfully | | Relay signal fails | MCP bridge unreachable | Signal manually via `ra-h-os-createRelayNode` | ## Edge Differences from hermes-zulip-restore | Concern | hermes-zulip-restore | hermes-zulip-plugin | |---------|---------------------|---------------------| | Env credential check | ✅ Full ZULIP_* verification | ❌ Out of scope | | Gateway restart | ✅ Restarts the gateway process | ❌ Out of scope | | Live connection test | ✅ Validates `zulip.state = connected` | ❌ Out of scope | | Plugin deploy | ✅ Includes deploy as one step | ✅ Primary purpose | | Version tracking | ❌ Implicit | ✅ Explicit SHA capture | | Signal dispatch | ❌ None | ✅ Relay message to target | For full connectivity recovery after a plugin install, chain this contract with `hermes-zulip-restore` (skip its Step 2 to avoid redundant deploy). --- **Last updated**: 2026-07-08 — Created to separate plugin lifecycle from restore workflow.