Files
prose-contracts/hermes-zulip-plugin.prose.md
T

8.4 KiB

kind, name, description, agent, version, status, runtime_contract
kind name description agent version status runtime_contract
function hermes-zulip-plugin Installs or updates the Zulip platform plugin for any Hermes agent from the canonical zulip-platform-plugins repo (master branch). Ensures the agent runs the latest adapter with all Zulip chat fixes (_strip_html, streaming, event recovery). Verifies the installation, restarts the gateway, and sends a relay success signal. abiba 1.0.0 active 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 is focused on the plugin layer and a targeted gateway restart. It does NOT verify env credentials or run a live Zulip connection test. Use hermes-zulip-restore for full connectivity recovery including end-to-end DM validation.

Parameters

Param Type Required Default Description
target string yes — Agent name: mumuni, koby, or shumba (Tanko excluded — on DSH since 2026-08-27, no Hermes plugin)
branch string no master 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 the guest's Proxmox node 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
Tanko CT112 amdpve 192.168.68.122 /home/jerome/.hermes jerome
Koby CT111 storepve 192.168.68.129 /root/.hermes root
Shumba — — 192.168.68.119 /home/lucky/.hermes lucky
Field Value Trust
Git repo https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git ✅ Verified
Default branch master (contains all merged fixes including 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 route through ssh root@amdpve; for CT111 route through ssh root@storepve — then pct exec <id>.

Step 2: Pull Latest Plugin Source

On the target host:

# 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

# 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 (was Tanko-only, runs as jerome user)
# RETIRED 2026-08-27: tanko no longer uses the Hermes Zulip plugin (DSH).
[ "{{target}}" = "tanko" ] && chown -R jerome:jerome \
  {{hermes_home}}/hermes-agent/plugins/platforms/zulip/

echo "Plugin files installed"

Step 4: Verify Installation

# 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: Restart Gateway

Plugin changes require a gateway restart to take effect:

cd {{hermes_home}}/hermes-agent
# Use venv if available
python3 -m hermes_cli.main gateway restart 2>&1 || \
  venv/bin/python -m hermes_cli.main gateway restart 2>&1

Wait for restart to complete (up to 45s), then confirm:

grep "Gateway running" {{hermes_home}}/logs/gateway.log | tail -1

Expected: Gateway running with N platform(s) where N > 1 (includes zulip).

Quick smoke check — confirm zulip platform loaded:

grep -E "zulip.*loaded|zulip.*registered" {{hermes_home}}/logs/gateway.log | tail -3

If gateway fails to restart, check logs for the crash cause before proceeding.

Step 6: 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 7: 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
Gateway restarted `{{yes
Signal sent `{{yes

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 ✅ Full restart + state validation ✅ Targeted restart + smoke check
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 — Switched default branch to master; added gateway restart step. If outstanding unmerged feature branches exist, address them in a follow-up merge after this contract completes.