Files
prose-contracts/hermes-zulip-plugin.prose.md
T
root 09efbdf4e5
PR Pipeline — Authorize → Validate → Review → Merge / auth (push) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / validate (push) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (push) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (push) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (push) Successful in 1s
feat: add hermes-zulip-plugin (install & repair) and relocate hermes-zulip-restore to repo
- hermes-zulip-plugin.prose.md: installs latest zulip-platform plugin from
  canonical repo, verifies _strip_html fix, sends relay success signal.
  Distinct from restore — plugin-layer only, no env/gateway/connection checks.
- hermes-zulip-restore.prose.md: relocated from /root/ into prose-contracts repo.
- Removed duplicate zulip-platform-verification from /root/vault/contracts/.
2026-07-08 17:47:23 +00:00

208 lines
7.1 KiB
Markdown

---
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_HOME>/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_HOME>/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 <id>`.
### 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.