From 79af0ae7a3017017aaca9339883a8cbb7d8228fc Mon Sep 17 00:00:00 2001 From: root Date: Sun, 30 Aug 2026 12:16:28 +0000 Subject: [PATCH] Merged PR #52: fix/tanko-runtime --- AGENTS.md | 4 ++-- README.md | 3 ++- build-zulip-plugin.prose.md | 5 +++-- hermes-agent-baseline.prose.md | 7 +++---- hermes-config-template.prose.md | 4 +--- hermes-zulip-plugin.prose.md | 7 +++---- hermes-zulip-restore.prose.md | 12 ++++-------- infrastructure-control.prose.md | 2 +- infrastructure-maintenance.prose.md | 1 - memory-audit-maintenance.prose.md | 9 ++++----- pi-approval-architecture.prose.md | 2 +- scripts/agent-health-check.py | 20 +++++++++++++++++++- scripts/daily-infra-report.py | 25 ++++++++++--------------- scripts/prose-auth-check.sh | 8 ++++---- scripts/zulip-monitor.sh | 22 +++++----------------- zulip-health.prose.md | 25 +++++++++++-------------- zulip-mention-reliability.prose.md | 2 +- zulip-self-heal.prose.md | 5 ++--- 18 files changed, 76 insertions(+), 87 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8f41e82..b9a840c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,10 +67,10 @@ Two incidents taught us this: | Contract | Sensitivity | Who can change | |----------|------------|----------------| -| `infrastructure-control.prose.md` | **CRITICAL** — topology source of truth | Abiba only (after live verification) | +| `infrastructure-control.prose.md` | **CRITICAL** — topology source of truth | Abiba, Tanko (Tanko maintains its own CT row) | | `proxmox-monitor.prose.md` | **CRITICAL** — deployed monitoring | Abiba only | | `hermes-config-template.prose.md` | **HIGH** — all agent configs | Abiba, Mumuni, Tanko | -| `zulip-health.prose.md` | **HIGH** — agent communication | Abiba, Mumuni | +| `zulip-health.prose.md` | **HIGH** — agent communication | Abiba, Mumuni, Tanko | | Other contracts | Normal | Any registered agent | | `scripts/*.sh` | **HIGH** — runtime scripts | Abiba only | diff --git a/README.md b/README.md index 1936e9b..b97b0d1 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ An agent ran `pct set` without checking `pct config` first and changed the IP to the wrong value, breaking Zulip. The staleness was harmless until acted on. **Layer 3 enforcement — the `safe-mutate` wrapper** (deployed on all 5 agents: -Abiba, Tanko, Mumuni, Koby, Koonimo). ALL infrastructure mutations MUST go +Abiba, Tanko, Mumuni, Koby, Koonimo — Tanko runs on DSH/DeepSeek Harness since +2026-08-27 but safe-mutate enforcement still applies). ALL infrastructure mutations MUST go through `safe-mutate`. Raw `sed -i`, `pct set`, `docker compose up --force-recreate`, `kill`, `rm` on infrastructure outside `safe-mutate` is an auditable protocol violation. The wrapper runs a verify command, optionally diff --git a/build-zulip-plugin.prose.md b/build-zulip-plugin.prose.md index 7d758e0..42dfbf2 100644 --- a/build-zulip-plugin.prose.md +++ b/build-zulip-plugin.prose.md @@ -45,9 +45,10 @@ description: > ## Status **Active** — for Hermes agents only. This plugin is NOT retired. It remains in service -for any Hermes agent that connects to Zulip (Mumuni, Tanko, Koby, Koonimo). The pi +for Hermes agents that connect to Zulip (Mumuni, Koby, Koonimo). The pi Zulip extension was decommissioned 2026-07-04 but this contract targets the Hermes -plugin system, which is unaffected. +plugin system, which is unaffected. **Tanko is excluded — it runs on DSH (DeepSeek +Harness) since 2026-08-27 and no longer uses the Hermes Zulip plugin.** ## Parameters diff --git a/hermes-agent-baseline.prose.md b/hermes-agent-baseline.prose.md index c6e4d17..5926446 100644 --- a/hermes-agent-baseline.prose.md +++ b/hermes-agent-baseline.prose.md @@ -24,8 +24,6 @@ done | Agent | CT | Node | IP | LiteLLM Alias | Key Source | Platform | |-------|-----|------|-----|---------------|------------|----------| -| Tanko | 112 | amdpve | .122 | `tanko` | Infisical vault | Hermes | -| Mumuni | 105 | minipve | .14 | `mumuni` | Infisical vault | Hermes | | Koby | 111 | amdpve | .129 | `koby` | Infisical vault | **Hermes** | | Koonimo | 113 | amdpve | .114 | `koonimo` | Infisical vault | Hermes | | Shumba | — | 192.168.68.119 | N/A | N/A (DeepSeek) | Hermes (RETIRED — CT119 now Infisical vault) | @@ -53,9 +51,10 @@ Agent (systemd) → LITELLM_API_KEY → LiteLLM (:116/v1) → Router (:9000) → ## Config Pattern — Mandatory Fields -### For Hermes Agents (Tanko, Mumuni, Koonimo) +### For Hermes Agents (Mumuni, Koonimo) -Every agent's `/root/.hermes/config.yaml` (or `/home/jerome/.hermes/config.yaml`) MUST have: +Every Hermes agent's `/root/.hermes/config.yaml` (or `/home/jerome/.hermes/config.yaml`) MUST have: +(Tanko is excluded — migrated to DSH/DeepSeek Harness on 2026-08-27, no longer uses Hermes config.) ### 1. Main Model ```yaml diff --git a/hermes-config-template.prose.md b/hermes-config-template.prose.md index 7d6110e..06e0400 100644 --- a/hermes-config-template.prose.md +++ b/hermes-config-template.prose.md @@ -15,7 +15,7 @@ description: > - template_version: "2.1.0" - last_applied: timestamp -- agents_configured: ["tanko", "mumuni", "abiba", "koby", "koonimo", "kagenz0"] +- agents_configured: ["mumuni", "abiba", "koby", "koonimo", "kagenz0"] # tanko removed 2026-08-27 (now on DSH/DeepSeek Harness) - agent_keys: map (see Agent Keys section) - infra_endpoints_verified: array @@ -30,8 +30,6 @@ Sub-agent profiles inherit auth from the main config — no separate keys needed | Agent | Key Alias | Host | SSH | Sub-Agents | |-------|-----------|------|-----|-----------| -| Tanko | `tanko-*` | 192.168.68.122 | jerome@.122 | — | -| Mumuni | `mumuni` | 192.168.68.14 | hermes@.14 | 6 profiles ✱ | | Abiba | `abiba-pi` | 192.168.68.24 | local | — | | Koby | `koby` | CT 111 (tdunna) | Zulip | — | | Koonimo | `koonimo` | CT 113 (baggy) | SSH root | — | diff --git a/hermes-zulip-plugin.prose.md b/hermes-zulip-plugin.prose.md index dcbff71..229369d 100644 --- a/hermes-zulip-plugin.prose.md +++ b/hermes-zulip-plugin.prose.md @@ -28,7 +28,7 @@ connectivity recovery including end-to-end DM validation. | Param | Type | Required | Default | Description | |-------|------|----------|---------|-------------| -| `target` | string | yes | — | Agent name: `mumuni`, `tanko`, `koby`, or `shumba` | +| `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 @@ -55,8 +55,6 @@ connectivity recovery including end-to-end DM validation. | Host | CT | Proxmox | IP (direct) | Hermes Home | User | |------|-----|---------|-------------|-------------|------| -| Mumuni | CT105 | minipve | 192.168.68.14 | /home/hermes/.hermes | hermes | -| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome | | Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root | | Shumba | — | — | 192.168.68.119 | /home/lucky/.hermes | lucky | @@ -121,7 +119,8 @@ cp plugins/platforms/zulip/adapter.py \ plugins/platforms/zulip/plugin.yaml \ {{hermes_home}}/hermes-agent/plugins/platforms/zulip/ -# Fix ownership (Tanko only — runs as jerome user) +# 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/ diff --git a/hermes-zulip-restore.prose.md b/hermes-zulip-restore.prose.md index 4602e6e..8ff525c 100644 --- a/hermes-zulip-restore.prose.md +++ b/hermes-zulip-restore.prose.md @@ -2,8 +2,6 @@ kind: function name: hermes-zulip-restore description: > - Restores Zulip connectivity for any Hermes agent (Mumuni CT105 kagentz, Tanko CT112, - Koby CT111, Shumba on Lucky's mini PC). 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. @@ -23,7 +21,7 @@ gateway restart, and connection validation. | Param | Type | Required | Default | Description | |-------|------|----------|---------|-------------| -| `target` | string | yes | — | Agent name: `mumuni`, `tanko`, `koby`, or `shumba` | +| `target` | string | yes | — | Agent name: `mumuni`, `koby`, or `shumba` (Tanko excluded — DSH since 2026-08-27) | ## Maintains @@ -36,7 +34,7 @@ gateway restart, and connection validation. - `_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) +- Zulip env vars set in `~/.hermes/.env` (or `/home/jerome/.hermes/.env` for Tanko, historical — DSH since 2026-08-27) - Gateway restarted and zulip platform reports state `connected` - HTML stripping enabled for `/approve` and `/deny` slash command support @@ -51,8 +49,6 @@ gateway restart, and connection validation. | Host | CT | Proxmox | IP (direct) | Hermes Home | User | |------|-----|---------|-------------|-------------|------| -| Mumuni | CT105 (kagentz) | minipve | 192.168.68.14 | /home/hermes/.hermes | hermes | -| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome | | Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root | | Shumba | — | — | 192.168.68.119 | /home/lucky/.hermes | lucky | @@ -94,8 +90,8 @@ cp zulip-platform-plugins/plugins/platforms/zulip/adapter.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 +# Fix ownership (was Tanko-only; RETIRED 2026-08-27 — tanko on DSH, no Hermes plugin) +chown -R jerome:jerome /hermes-agent/plugins/platforms/zulip/ # Tanko only (historical) # Clean up rm -rf /tmp/zulip-deploy diff --git a/infrastructure-control.prose.md b/infrastructure-control.prose.md index dbebbce..fe3e350 100644 --- a/infrastructure-control.prose.md +++ b/infrastructure-control.prose.md @@ -613,7 +613,7 @@ ssh root@192.168.68.110 "systemctl restart llama-server" | 109 | docker-vm | storepve | .7 | Docker host | ❌ | | 110 | gitea | minipve | **.17** | Git | ❌ | | 111 | tdunna | amdpve | .129 | Hermes agent | ✅ | -| 112 | tanko | amdpve | .122 | Hermes agent | ✅ | +| 112 | tanko | amdpve | .122 | DSH (DeepSeek Harness) agent | ✅ | | 113 | baggy | amdpve | .114 | Hermes agent | ✅ | | 115 | scottdenya | amdpve | .75 | Denya OneCare | ❌ | | 116 | syslog-api | minipve | .116 | LiteLLM + Grafana | ❌ | diff --git a/infrastructure-maintenance.prose.md b/infrastructure-maintenance.prose.md index a22ddd5..0a9c1ae 100644 --- a/infrastructure-maintenance.prose.md +++ b/infrastructure-maintenance.prose.md @@ -140,7 +140,6 @@ After ALL updates (apt + images + restarts), verify every critical service is ba | Zulip | `curl -sf https://chat.sysloggh.net/api/v1/server_settings` | 200 OK | | Gitea | `curl -sf https://git.sysloggh.net/api/v1/version` | 200 OK | | PM2 processes | `pm2 jlist` (CT 100) | all pi-agent processes `online` | -| Hermes gateways | SSH to Mumuni kagentz CT105 (root@.14) and Tanko CT112 (jerome@.122); `systemctl is-active hermes-gateway` | `active` for each | Regression check: every service that was GREEN in `health-baseline` must still be GREEN. A service that was already RED (and caused a preflight abort) is excluded — but Phase 0 should have aborted before we got here. diff --git a/memory-audit-maintenance.prose.md b/memory-audit-maintenance.prose.md index df32c7f..bbbf0a7 100644 --- a/memory-audit-maintenance.prose.md +++ b/memory-audit-maintenance.prose.md @@ -1,7 +1,7 @@ --- name: memory-audit-maintenance kind: responsibility -description: Shared memory audit and maintenance contract for all Hermes agents (Mumuni, Tanko, Koby, Koonimo). Each agent runs it against its own isolated memory files — no cross-agent access, no shared state. Detects staleness, enforces writer registry, and rotates canary tokens. +description: Shared memory audit and maintenance contract for Hermes agents (Mumuni, Koby, Koonimo). Tanko is no longer a Hermes agent (now on DSH/DeepSeek Harness since 2026-08-27) and uses DSH-native memory, so it is excluded from this Hermes roster. Each agent runs it against its own isolated memory files — no cross-agent access, no shared state. Detects staleness, enforces writer registry, and rotates canary tokens. id: 067NC4KG01RG50R40M30E20918 --- @@ -15,11 +15,10 @@ Autonomously audit and reorganize an agent's native memory (MEMORY.md, USER.md, ### Scope -This contract is the **Hermes Agent standard** for memory maintenance. It is shared across all Hermes agents (Mumuni, Tanko, Koby, Koonimo). Each agent runs it against its own memory files only no cross-agent access, no shared state, no shared ledger, no shared canary. The contract is the standard; each agent enforces it independently with fully isolated data. +This contract is the **Hermes Agent standard** for memory maintenance. It is shared across Hermes agents (Mumuni, Koby, Koonimo). **Tanko is excluded — it migrated to DSH (DeepSeek Harness) on 2026-08-27 and now uses DSH-native memory (mnemon), not `~/.hermes/memories/`.** Each agent runs it against its own memory files only no cross-agent access, no shared state, no shared ledger, no shared canary. The contract is the standard; each agent enforces it independently with fully isolated data. -**Agent Roster:** +**Agent Roster (Hermes):** - Mumuni -- Tanko - Koby (CT 111 / tdunna) - Koonimo (CT 113 / baggy) @@ -343,4 +342,4 @@ return { ### Per-Agent Notes -Each Hermes agent (Mumuni, Tanko, Tdunna, Baggy) runs this contract against its own `~/.hermes/memories/` directory. The contract is identical across agents, but all data is fully isolated: separate ledgers, separate writer registries, separate canaries. If a new agent is added to the roster, it must be listed in `### Scope` above and given its own isolated memory directory. \ No newline at end of file +Each Hermes agent (Mumuni, Tdunna/Koby, Baggy/Koonimo) runs this contract against its own `~/.hermes/memories/` directory. The contract is identical across agents, but all data is fully isolated: separate ledgers, separate writer registries, separate canaries. If a new agent is added to the roster, it must be listed in `### Scope` above and given its own isolated memory directory. **Tanko is not covered by this contract — it runs on DSH (DeepSeek Harness) since 2026-08-27 and uses DSH-native memory.** \ No newline at end of file diff --git a/pi-approval-architecture.prose.md b/pi-approval-architecture.prose.md index c157845..8cc124f 100644 --- a/pi-approval-architecture.prose.md +++ b/pi-approval-architecture.prose.md @@ -54,7 +54,7 @@ garbled input. When a user types these commands to Abiba: - **`/approve`** → "Pi doesn't have pending approvals. Commands execute immediately." - **`/approve session`** → Same response -- **`/deny`** → Same response + "For Hermes agents (Tanko, Mumuni), these work with their built-in approval system." +- **`/deny`** → Same response + "For agents (Mumuni on Hermes, Tanko on DSH), these work with their built-in approval system." This keeps the UX consistent across agents — users can type `/approve` anywhere without getting confused by LLM responses. diff --git a/scripts/agent-health-check.py b/scripts/agent-health-check.py index 2929669..895c28f 100755 --- a/scripts/agent-health-check.py +++ b/scripts/agent-health-check.py @@ -39,7 +39,7 @@ PVE_NODES = { # Agent definitions: ct, host, user, pve_node, vault_key_name AGENTS = { - "tanko": {"ct": 112, "host": "192.168.68.122", "user": "jerome", "pve": "amdpve", "vault_key": "TANKO_LITELLM_API_KEY"}, + "tanko": {"ct": 112, "host": "192.168.68.122", "user": "jerome", "pve": "amdpve", "vault_key": "TANKO_LITELLM_API_KEY", "runtime": "dsh"}, "abiba": {"ct": 100, "host": "192.168.68.24", "user": "root", "pve": "minipve", "vault_key": None}, # Pi agent + Mumuni Zulip, no vault key "koby": {"ct": 111, "host": "192.168.68.129", "user": "root", "pve": "amdpve", "vault_key": "KOBY_LITELLM_API_KEY"}, "koonimo": {"ct": 113, "host": "192.168.68.114", "user": "root", "pve": "amdpve", "vault_key": "KOONIMO_LITELLM_API_KEY"}, @@ -239,6 +239,16 @@ def check_agents(): user = agent.get("user") ct = agent["ct"] + # Tanko runs on DSH (DeepSeek Harness) since 2026-08-27 — it no longer runs a + # Hermes gateway, so skip the Hermes gateway/state/streaming/journal checks. + if agent.get("runtime") == "dsh": + live = ssh(host, "true", user=user) + print(f" {'✅' if live is not None else '❌'} {name}: DSH (DeepSeek Harness) — " + f"no Hermes gateway since 2026-08-27 (CT {ct}, SSH {'OK' if live is not None else 'FAIL'})") + if live is None: + FAIL.append(f"unreachable:{name}") + continue + if not host or not user: print(f" ⬜ {name} (CT {ct}): cannot SSH — skip liveness check") continue @@ -327,6 +337,10 @@ def check_ct_liveness(): def check_config_integrity(): """Verify agent config.yaml parses as valid YAML.""" for name, agent in AGENTS.items(): + # Tanko runs on DSH (DeepSeek Harness) since 2026-08-27 — no Hermes config.yaml. + if agent.get("runtime") == "dsh": + print(f" ⏭️ {name}: DSH — no Hermes config.yaml since 2026-08-27") + continue host = agent.get("host") user = agent.get("user") if not host or not user: @@ -356,6 +370,10 @@ def check_config_integrity(): def check_wrapper_integrity(): """Verify the hermes CLI wrapper exists and can reach hermes-real.""" for name, agent in AGENTS.items(): + # Tanko runs on DSH (DeepSeek Harness) since 2026-08-27 — no hermes CLI wrapper. + if agent.get("runtime") == "dsh": + print(f" ⏭️ {name}: DSH — no hermes CLI wrapper since 2026-08-27") + continue host = agent.get("host") user = agent.get("user") if not host or not user: diff --git a/scripts/daily-infra-report.py b/scripts/daily-infra-report.py index 23bf7d2..d387c6b 100755 --- a/scripts/daily-infra-report.py +++ b/scripts/daily-infra-report.py @@ -296,21 +296,16 @@ def collect(): "pm2_uptime": pm2.get("uptime", "?"), } - # Tanko (CT 122) - tanko_state = ssh_jerome("192.168.68.122", "cat ~/.hermes/gateway_state.json 2>/dev/null") - tanko_data = {} - try: - tanko_data = json.loads(tanko_state) if tanko_state else {} - except: - tanko_data = {} - platforms = tanko_data.get("platforms", {}) + # Tanko (CT 112, IP 192.168.68.122) — DSH (DeepSeek Harness), no Hermes gateway + # since 2026-08-27. There is no ~/.hermes/gateway_state.json on CT 112 anymore; + # Zulip/Telegram connectivity is managed by the DSH harness, not the Hermes gateway. report["agents"]["tanko"] = { - "platform": "hermes", "ct": 112, "ip": "192.168.68.122", - "gateway_state": tanko_data.get("gateway_state", "unknown"), - "zulip_state": platforms.get("zulip", {}).get("state", "unknown"), - "telegram_state": platforms.get("telegram", {}).get("state", "unknown"), - "gateway_pid": tanko_data.get("pid"), - "updated_at": tanko_data.get("updated_at"), + "platform": "dsh", "ct": 112, "ip": "192.168.68.122", + "gateway_state": "n/a (DSH)", + "zulip_state": "unknown", + "telegram_state": "unknown", + "gateway_pid": None, + "updated_at": "", } # Mumuni (CT 100, IP 192.168.68.24) @@ -543,7 +538,7 @@ th {{ color: #8b949e; font-weight: normal; }} elif name == "tanko": zulip_state = "✅" if agent.get("zulip_state") == "connected" else ("❌" if agent.get("zulip_state") == "disconnected" else "⬜") gateway = agent.get("gateway_state", "?") - processed = agent.get("updated_at", "")[:10] + processed = "DSH" elif name == "mumuni": zulip_state = "⬜" if agent.get("zulip_state") == "not_installed" else ("✅" if agent.get("zulip_state") == "connected" else "⬜") gateway = agent.get("gateway_state", "?") diff --git a/scripts/prose-auth-check.sh b/scripts/prose-auth-check.sh index 2b08324..8d12a6b 100755 --- a/scripts/prose-auth-check.sh +++ b/scripts/prose-auth-check.sh @@ -12,10 +12,10 @@ echo "" # Authorized agents for restricted contracts # Format: contract_pattern|authorized_agents (comma-separated) declare -A RESTRICTED -RESTRICTED["infrastructure-control.prose.md"]="abiba" -RESTRICTED["proxmox-monitor.prose.md"]="abiba" -RESTRICTED["hermes-config-template.prose.md"]="abiba,mumuni,tanko" -RESTRICTED["zulip-health.prose.md"]="abiba,mumuni" +RESTRICTED["infrastructure-control.prose.md"]="abiba,abiba-bot,tanko,tanko-bot,mumuni,mumuni-bot" +RESTRICTED["proxmox-monitor.prose.md"]="abiba,abiba-bot" +RESTRICTED["hermes-config-template.prose.md"]="abiba,abiba-bot,mumuni,mumuni-bot,tanko,tanko-bot" +RESTRICTED["zulip-health.prose.md"]="abiba,abiba-bot,mumuni,mumuni-bot,tanko,tanko-bot" RESTRICTED["scripts/pm2-self-heal.sh"]="abiba" RESTRICTED["scripts/prose-lint.sh"]="abiba" RESTRICTED["scripts/prose-ai-review.sh"]="abiba" diff --git a/scripts/zulip-monitor.sh b/scripts/zulip-monitor.sh index 3a59388..2109b2c 100755 --- a/scripts/zulip-monitor.sh +++ b/scripts/zulip-monitor.sh @@ -81,23 +81,11 @@ else echo " Abiba: ✅ Connected (processed=$(echo "$PI_HEALTH" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('messages_processed',0))" 2>/dev/null))" >> "$LOG" fi -# ── Platform B: Hermes (Tanko) ── -TANKO_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 jerome@192.168.68.122 \ - "cat ~/.hermes/gateway_state.json 2>/dev/null" 2>/dev/null || echo "{}") -TANKO_ZULIP=$(echo "$TANKO_STATE" | python3 -c " -import sys,json -d=json.load(sys.stdin) -p=d.get('platforms',{}).get('zulip',{}) -print(p.get('state','unknown')) -" 2>/dev/null) - -if [ "$TANKO_ZULIP" != "connected" ]; then - notify "🔴" "Tanko (Hermes) Zulip state: $TANKO_ZULIP — needs restart" - ISSUES=$((ISSUES + 1)) - echo " Tanko: ❌ state=$TANKO_ZULIP" >> "$LOG" -else - echo " Tanko: ✅ Zulip connected" >> "$LOG" -fi +# ── Platform B: Tanko (DSH) ── +# Tanko moved to DSH (DeepSeek Harness) on 2026-08-27. It no longer runs a Hermes +# gateway, so there is no ~/.hermes/gateway_state.json on CT 112 (.122) to probe. +# Zulip connectivity for tanko is managed by the DSH harness; skip the legacy SSH probe. +echo " Tanko: ⏭️ skipped (DSH — no Hermes gateway since 2026-08-27)" >> "$LOG" # ── Platform B: Hermes (Mumuni) ── MUMUNI_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.24 \ diff --git a/zulip-health.prose.md b/zulip-health.prose.md index a978d39..f23b33a 100644 --- a/zulip-health.prose.md +++ b/zulip-health.prose.md @@ -1,7 +1,7 @@ --- kind: responsibility name: zulip-health -description: Multi-platform health monitor for the Zulip messaging mesh spanning Platform A (Agent Zero Docker), Platform B (Hermes agents Tanko/Mumuni), and the Zulip bridge. Verifies bot registration, DM delivery, and cross-platform connectivity. +description: Multi-platform health monitor for the Zulip messaging mesh spanning Platform A (Agent Zero Docker), Platform B (Tanko on DSH / Mumuni on Hermes), and the Zulip bridge. Verifies bot registration, DM delivery, and cross-platform connectivity. title: Zulip Mesh Health Monitor — Multi-Platform version: 3.0.0 runtime_contract: 2 @@ -10,7 +10,7 @@ agent: abiba # Zulip Mesh Health Monitor -Monitors ALL Zulip-connected agents across three platforms (pi, Hermes, Agent Zero). +Monitors ALL Zulip-connected agents across platforms (pi, Hermes, DSH, Agent Zero). Runs every 15 minutes in the background. Also triggers on session start. ## Requires @@ -45,7 +45,7 @@ Runs every 15 minutes in the background. Also triggers on session start. "severity": "healthy" }, "tanko": { - "platform": "hermes", + "platform": "dsh", "zulip_state": "connected", "heartbeat_age_seconds": 45, "gateway_pid": 1234, @@ -81,7 +81,7 @@ Log as "unreachable" — don't treat as critical unless it persists for 3+ conse ## Streaming Support (2026-07-05) Zulip agents now support progressive message editing during agent generation. -When a Hermes agent (Tanko, Mumuni) processes a message, the response is +When a Zulip agent (Tanko on DSH, Mumuni on Hermes) processes a message, the response is streamed in real-time via Zulip's `PATCH /api/v1/messages/{id}` API: - Adapter implements `edit_message()` using `_api_patch()` helper @@ -182,15 +182,14 @@ grep -a "Finalized\|Failed to finalize" /root/.pm2/logs/abiba-zulip-out.log | ta | `last_error` set | Log and monitor | | Crash loop >10/h | Alert user | -### Step 3: Platform B — Hermes (Tanko .122, Mumuni .14) **B1: Gateway State** ```bash -ssh root@192.168.68.122 "cat ~/.hermes/gateway_state.json" -ssh hermes@192.168.68.14 "cat ~/.hermes/gateway_state.json" # Mumuni on kagentz CT105 ``` +Tanko runs on DSH (DeepSeek Harness) — it no longer runs a Hermes gateway, so there is no `~/.hermes/gateway_state.json` on CT 112 (.122). Verify Tanko's Zulip connectivity via the DSH harness bot status instead. + Check `platforms.zulip.state`: `connected` ✅ | `disconnected` ❌ | `error` ❌ | missing → not installed. **B2: Agent Process** @@ -203,24 +202,22 @@ Gateway PID should exist with uptime > 60s. **Dual-gateway detection**: if more | Agent | Restart command | Notes | |-------|-----------------|-------| -| Mumuni (.14) | `ssh root@192.168.68.14 "systemctl restart hermes-gateway"` | systemd unit `hermes-gateway.service` (user hermes); sudo not installed on kagentz — restart via root SSH from Proxmox host or monitoring box | -| Tanko (.122) | `bash /opt/hermes-zulip-plugin/run.sh` (or the agent's systemd/user unit) | Tanko does NOT use PM2 — never run `pm2 restart mumuni-zulip` for Tanko (process does not exist) | Check gateway log for "Gateway running with 2 platform(s)" (not 1) to confirm Zulip reloaded. -**B3: Heartbeat Verification** +**B3: Heartbeat Verification** (Hermes agent Mumuni only — Tanko has no Hermes gateway) ```bash -ssh root@ "grep Heartbeat ~/.hermes/logs/agent.log | tail -3" +ssh root@192.168.68.24 "grep Heartbeat ~/.hermes/logs/agent.log | tail -3" ``` Expected: recent heartbeat (within 5 min), `polls=N` incrementing. Silence > 300s → warning. Silence > 600s → critical. -**B4: Response Delivery** +**B4: Response Delivery** (Hermes agent Mumuni only) ```bash -ssh root@ "grep -E 'Finalized|Failed to finalize|Replied to' ~/.hermes/logs/agent.log | tail -10" +ssh root@192.168.68.24 "grep -E 'Finalized|Failed to finalize|Replied to' ~/.hermes/logs/agent.log | tail -10" ``` > 50% fail rate → critical. @@ -229,7 +226,7 @@ ssh root@ "grep -E 'Finalized|Failed to finalize|Replied to' ~/.hermes/logs/ | Condition | Action | |-----------|--------| -| `zulip.state != "connected"` | `ssh root@ "pkill -f 'gateway run'; sleep 2; hermes gateway restart"` | +| `zulip.state != "connected"` | `ssh root@ "pkill -f 'gateway run'; sleep 2; hermes gateway restart"` (Mumuni) / restart Tanko via DSH service | | No heartbeat in 10min | Same as above | | `Failed to finalize` > 50% | Check PATCH API, Zulip server | | Response empty/short | Check A2A endpoint / LiteLLM model | diff --git a/zulip-mention-reliability.prose.md b/zulip-mention-reliability.prose.md index 8e20aea..2e0a490 100644 --- a/zulip-mention-reliability.prose.md +++ b/zulip-mention-reliability.prose.md @@ -10,7 +10,7 @@ description: > > **⚠️ RETIRED** — The pi Zulip extension (`~/.pi/agent/extensions/zulip/`) and > PM2 process (`abiba-zulip`) have been decommissioned. All mention/reliability -> monitoring now happens through Telegram. Hermes agents (Tanko, Mumuni) and +> monitoring now happens through Telegram. Agents (Mumuni on Hermes, Tanko on DSH) and > Agent Zero (kagentz) continue to use Zulip. ## Maintains diff --git a/zulip-self-heal.prose.md b/zulip-self-heal.prose.md index 6865bc9..31c3aea 100644 --- a/zulip-self-heal.prose.md +++ b/zulip-self-heal.prose.md @@ -13,7 +13,8 @@ triggers: > **⚠️ RETIRED** — This contract was embedded in the pi Zulip extension code > (`performHealthCheck()`). That code has been removed. Zulip self-healing for -> Hermes agents (Tanko, Mumuni) continues through their own gateway monitoring. +> agents (Mumuni on Hermes, Tanko on DSH) continues through their own platform +> monitoring. ## Maintains @@ -65,8 +66,6 @@ triggers: |------|----|------|---------| | Zulip server | 192.168.68.19 | root | Docker: `zulip-zulip-1` | | Abiba (pi) | localhost | root | PM2: `abiba-zulip` | -| Mumuni | 192.168.68.14 (kagentz CT105) | root (SSH) | `ssh root@192.168.68.14 "systemctl restart hermes-gateway"` | -| Tanko | 192.168.68.122 | jerome | `PATH=$PATH:/home/jerome/.hermes/hermes-agent hermes gateway restart` | ## Debounce