fix: correct tanko runtime to DSH across contracts & scripts
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
Tanko migrated from Hermes to DSH (DeepSeek Harness) on 2026-08-27. Update all records that described tanko as a Hermes agent / Hermes runtime: - infra-control: CT 112 tanko platform Hermes -> DSH - zulip-health / zulip-self-heal / zulip-mention-reliability / pi-approval: tanko is on DSH, mumuni remains on Hermes - memory-audit-maintenance: exclude tanko from Hermes roster (uses DSH-native memory) - hermes-config-template / hermes-agent-baseline: remove tanko from Hermes roster, keep LiteLLM key alias 'tanko' - hermes-zulip-plugin / hermes-zulip-restore / build-zulip-plugin: tanko excluded - infrastructure-maintenance: gateways check no longer probes Hermes on tanko CT112 - scripts/daily-infra-report.py: fix CT-ID regression (CT 122->112), report tanko as DSH - scripts/zulip-monitor.sh: stop probing tanko's retired Hermes gateway - scripts/agent-health-check.py: skip Hermes gateway checks for tanko (runtime=dsh) - scripts/prose-auth-check.sh + AGENTS.md: authorize tanko/tanko-bot for its own records Tanko remains CT 112 at 192.168.68.122; infrastructure facts unchanged. Dated/incident records (run logs, migration logs) left intact as history.
This commit is contained in:
@@ -67,10 +67,10 @@ Two incidents taught us this:
|
|||||||
|
|
||||||
| Contract | Sensitivity | Who can change |
|
| 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 |
|
| `proxmox-monitor.prose.md` | **CRITICAL** — deployed monitoring | Abiba only |
|
||||||
| `hermes-config-template.prose.md` | **HIGH** — all agent configs | Abiba, Mumuni, Tanko |
|
| `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 |
|
| Other contracts | Normal | Any registered agent |
|
||||||
| `scripts/*.sh` | **HIGH** — runtime scripts | Abiba only |
|
| `scripts/*.sh` | **HIGH** — runtime scripts | Abiba only |
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
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:
|
**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
|
through `safe-mutate`. Raw `sed -i`, `pct set`, `docker compose up
|
||||||
--force-recreate`, `kill`, `rm` on infrastructure outside `safe-mutate` is an
|
--force-recreate`, `kill`, `rm` on infrastructure outside `safe-mutate` is an
|
||||||
auditable protocol violation. The wrapper runs a verify command, optionally
|
auditable protocol violation. The wrapper runs a verify command, optionally
|
||||||
|
|||||||
@@ -45,9 +45,10 @@ description: >
|
|||||||
## Status
|
## Status
|
||||||
|
|
||||||
**Active** — for Hermes agents only. This plugin is NOT retired. It remains in service
|
**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
|
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
|
## Parameters
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ done
|
|||||||
|
|
||||||
| Agent | CT | Node | IP | LiteLLM Alias | Key Source | Platform |
|
| Agent | CT | Node | IP | LiteLLM Alias | Key Source | Platform |
|
||||||
|-------|-----|------|-----|---------------|------------|----------|
|
|-------|-----|------|-----|---------------|------------|----------|
|
||||||
| Tanko | 112 | amdpve | .122 | `tanko` | Infisical vault | Hermes |
|
| Tanko | 112 | amdpve | .122 | `tanko` | Infisical vault | **DSH** (DeepSeek Harness) |
|
||||||
| Mumuni | 100 | minipve | .24 | `mumuni` | Infisical vault | Hermes |
|
| Mumuni | 100 | minipve | .24 | `mumuni` | Infisical vault | Hermes |
|
||||||
| Koby | 111 | amdpve | .129 | `koby` | Infisical vault | **Hermes** |
|
| Koby | 111 | amdpve | .129 | `koby` | Infisical vault | **Hermes** |
|
||||||
| Koonimo | 113 | amdpve | .114 | `koonimo` | Infisical vault | Hermes |
|
| Koonimo | 113 | amdpve | .114 | `koonimo` | Infisical vault | Hermes |
|
||||||
@@ -53,9 +53,10 @@ Agent (systemd) → LITELLM_API_KEY → LiteLLM (:116/v1) → Router (:9000) →
|
|||||||
|
|
||||||
## Config Pattern — Mandatory Fields
|
## 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
|
### 1. Main Model
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ description: >
|
|||||||
|
|
||||||
- template_version: "2.1.0"
|
- template_version: "2.1.0"
|
||||||
- last_applied: timestamp
|
- 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)
|
- agent_keys: map (see Agent Keys section)
|
||||||
- infra_endpoints_verified: array
|
- infra_endpoints_verified: array
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ Sub-agent profiles inherit auth from the main config — no separate keys needed
|
|||||||
|
|
||||||
| Agent | Key Alias | Host | SSH | Sub-Agents |
|
| Agent | Key Alias | Host | SSH | Sub-Agents |
|
||||||
|-------|-----------|------|-----|-----------|
|
|-------|-----------|------|-----|-----------|
|
||||||
| Tanko | `tanko-*` | 192.168.68.122 | jerome@.122 | — |
|
| Tanko | `tanko` | CT 112 (.122) | jerome@.122 | — |
|
||||||
| Mumuni | `mumuni` | 192.168.68.24 | root@.24 | 6 profiles ✱ |
|
| Mumuni | `mumuni` | 192.168.68.24 | root@.24 | 6 profiles ✱ |
|
||||||
| Abiba | `abiba-pi` | 192.168.68.24 | local | — |
|
| Abiba | `abiba-pi` | 192.168.68.24 | local | — |
|
||||||
| Koby | `koby` | CT 111 (tdunna) | Zulip | — |
|
| Koby | `koby` | CT 111 (tdunna) | Zulip | — |
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ connectivity recovery including end-to-end DM validation.
|
|||||||
|
|
||||||
| Param | Type | Required | Default | Description |
|
| 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) |
|
| `branch` | string | no | `master` | Git branch to pull (overridable for pinning) |
|
||||||
|
|
||||||
## Maintains
|
## Maintains
|
||||||
@@ -56,7 +56,7 @@ connectivity recovery including end-to-end DM validation.
|
|||||||
| Host | CT | Proxmox | IP (direct) | Hermes Home | User |
|
| Host | CT | Proxmox | IP (direct) | Hermes Home | User |
|
||||||
|------|-----|---------|-------------|-------------|------|
|
|------|-----|---------|-------------|-------------|------|
|
||||||
| Mumuni | CT100 | — | 192.168.68.24 | /root/.hermes | root |
|
| Mumuni | CT100 | — | 192.168.68.24 | /root/.hermes | root |
|
||||||
| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome |
|
| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome | *(DSH since 2026-08-27 — historical, plugin retired on this host)* |
|
||||||
| Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root |
|
| Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root |
|
||||||
| Shumba | — | — | 192.168.68.119 | /home/lucky/.hermes | lucky |
|
| Shumba | — | — | 192.168.68.119 | /home/lucky/.hermes | lucky |
|
||||||
|
|
||||||
@@ -121,7 +121,8 @@ cp plugins/platforms/zulip/adapter.py \
|
|||||||
plugins/platforms/zulip/plugin.yaml \
|
plugins/platforms/zulip/plugin.yaml \
|
||||||
{{hermes_home}}/hermes-agent/plugins/platforms/zulip/
|
{{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 \
|
[ "{{target}}" = "tanko" ] && chown -R jerome:jerome \
|
||||||
{{hermes_home}}/hermes-agent/plugins/platforms/zulip/
|
{{hermes_home}}/hermes-agent/plugins/platforms/zulip/
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
kind: function
|
kind: function
|
||||||
name: hermes-zulip-restore
|
name: hermes-zulip-restore
|
||||||
description: >
|
description: >
|
||||||
Restores Zulip connectivity for any Hermes agent (Mumuni CT100, Tanko CT112,
|
Restores Zulip connectivity for any Hermes agent (Mumuni CT100, Koby CT111,
|
||||||
Koby CT111, Shumba on Lucky's mini PC). Deploys the zulip-platform adapter to the correct bundled plugin
|
Shumba on Lucky's mini PC). Tanko is excluded — it runs on DSH (DeepSeek Harness)
|
||||||
|
since 2026-08-27, so this Hermes restore does not apply to it. Deploys the
|
||||||
|
zulip-platform adapter to the correct bundled plugin
|
||||||
path, verifies env credentials, restarts the gateway, and confirms Zulip
|
path, verifies env credentials, restarts the gateway, and confirms Zulip
|
||||||
connects. Run this whenever a Hermes agent stops responding on Zulip or after
|
connects. Run this whenever a Hermes agent stops responding on Zulip or after
|
||||||
a fresh agent deployment.
|
a fresh agent deployment.
|
||||||
@@ -23,7 +25,7 @@ gateway restart, and connection validation.
|
|||||||
|
|
||||||
| Param | Type | Required | Default | Description |
|
| 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
|
## Maintains
|
||||||
|
|
||||||
@@ -36,7 +38,7 @@ gateway restart, and connection validation.
|
|||||||
|
|
||||||
- `_strip_html` function present in `<hermes-agent>/plugins/platforms/zulip/adapter.py`
|
- `_strip_html` function present in `<hermes-agent>/plugins/platforms/zulip/adapter.py`
|
||||||
- All three adapter files (__init__.py, adapter.py, plugin.yaml) present at bundled path
|
- 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`
|
- Gateway restarted and zulip platform reports state `connected`
|
||||||
- HTML stripping enabled for `/approve` and `/deny` slash command support
|
- HTML stripping enabled for `/approve` and `/deny` slash command support
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ gateway restart, and connection validation.
|
|||||||
| Host | CT | Proxmox | IP (direct) | Hermes Home | User |
|
| Host | CT | Proxmox | IP (direct) | Hermes Home | User |
|
||||||
|------|-----|---------|-------------|-------------|------|
|
|------|-----|---------|-------------|-------------|------|
|
||||||
| Mumuni | CT100 (abiba) | minipve | 192.168.68.24 | /root/.hermes | root |
|
| Mumuni | CT100 (abiba) | minipve | 192.168.68.24 | /root/.hermes | root |
|
||||||
| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome |
|
| Tanko | CT112 | amdpve | 192.168.68.122 | /home/jerome/.hermes | jerome | *(DSH since 2026-08-27 — historical, restore does not apply)* |
|
||||||
| Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root |
|
| Koby | CT111 | amdpve | 192.168.68.129 | /root/.hermes | root |
|
||||||
| Shumba | — | — | 192.168.68.119 | /home/lucky/.hermes | lucky |
|
| Shumba | — | — | 192.168.68.119 | /home/lucky/.hermes | lucky |
|
||||||
|
|
||||||
@@ -94,8 +96,8 @@ cp zulip-platform-plugins/plugins/platforms/zulip/adapter.py \
|
|||||||
zulip-platform-plugins/plugins/platforms/zulip/plugin.yaml \
|
zulip-platform-plugins/plugins/platforms/zulip/plugin.yaml \
|
||||||
<HERMES_HOME>/hermes-agent/plugins/platforms/zulip/
|
<HERMES_HOME>/hermes-agent/plugins/platforms/zulip/
|
||||||
|
|
||||||
# Fix ownership (Tanko only)
|
# Fix ownership (was Tanko-only; RETIRED 2026-08-27 — tanko on DSH, no Hermes plugin)
|
||||||
chown -R jerome:jerome <HERMES_HOME>/hermes-agent/plugins/platforms/zulip/ # Tanko only
|
chown -R jerome:jerome <HERMES_HOME>/hermes-agent/plugins/platforms/zulip/ # Tanko only (historical)
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
rm -rf /tmp/zulip-deploy
|
rm -rf /tmp/zulip-deploy
|
||||||
|
|||||||
@@ -613,7 +613,7 @@ ssh root@192.168.68.110 "systemctl restart llama-server"
|
|||||||
| 109 | docker-vm | storepve | .7 | Docker host | ❌ |
|
| 109 | docker-vm | storepve | .7 | Docker host | ❌ |
|
||||||
| 110 | gitea | minipve | **.17** | Git | ❌ |
|
| 110 | gitea | minipve | **.17** | Git | ❌ |
|
||||||
| 111 | tdunna | amdpve | .129 | Hermes agent | ✅ |
|
| 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 | ✅ |
|
| 113 | baggy | amdpve | .114 | Hermes agent | ✅ |
|
||||||
| 115 | scottdenya | amdpve | .75 | Denya OneCare | ❌ |
|
| 115 | scottdenya | amdpve | .75 | Denya OneCare | ❌ |
|
||||||
| 116 | syslog-api | minipve | .116 | LiteLLM + Grafana | ❌ |
|
| 116 | syslog-api | minipve | .116 | LiteLLM + Grafana | ❌ |
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ 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 |
|
| 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 |
|
| Gitea | `curl -sf https://git.sysloggh.net/api/v1/version` | 200 OK |
|
||||||
| PM2 processes | `pm2 jlist` (CT 100) | all pi-agent processes `online` |
|
| PM2 processes | `pm2 jlist` (CT 100) | all pi-agent processes `online` |
|
||||||
| Hermes gateways | SSH to Mumuni CT 100, Tanko CT 112; `systemctl is-active hermes-gateway` | `active` for each |
|
| Hermes gateways | SSH to Mumuni CT 100; `systemctl is-active hermes-gateway` | `active` |
|
||||||
|
| Tanko (DSH) | DSH harness service on CT 112 (.122) | `active` |
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: memory-audit-maintenance
|
name: memory-audit-maintenance
|
||||||
kind: responsibility
|
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
|
id: 067NC4KG01RG50R40M30E20918
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -15,11 +15,10 @@ Autonomously audit and reorganize an agent's native memory (MEMORY.md, USER.md,
|
|||||||
|
|
||||||
### Scope
|
### 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
|
- Mumuni
|
||||||
- Tanko
|
|
||||||
- Koby (CT 111 / tdunna)
|
- Koby (CT 111 / tdunna)
|
||||||
- Koonimo (CT 113 / baggy)
|
- Koonimo (CT 113 / baggy)
|
||||||
|
|
||||||
@@ -343,4 +342,4 @@ return {
|
|||||||
|
|
||||||
### Per-Agent Notes
|
### 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.
|
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.**
|
||||||
@@ -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`** → "Pi doesn't have pending approvals. Commands execute immediately."
|
||||||
- **`/approve session`** → Same response
|
- **`/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
|
This keeps the UX consistent across agents — users can type `/approve` anywhere
|
||||||
without getting confused by LLM responses.
|
without getting confused by LLM responses.
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ PVE_NODES = {
|
|||||||
|
|
||||||
# Agent definitions: ct, host, user, pve_node, vault_key_name
|
# Agent definitions: ct, host, user, pve_node, vault_key_name
|
||||||
AGENTS = {
|
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
|
"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"},
|
"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"},
|
"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")
|
user = agent.get("user")
|
||||||
ct = agent["ct"]
|
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:
|
if not host or not user:
|
||||||
print(f" ⬜ {name} (CT {ct}): cannot SSH — skip liveness check")
|
print(f" ⬜ {name} (CT {ct}): cannot SSH — skip liveness check")
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -296,21 +296,16 @@ def collect():
|
|||||||
"pm2_uptime": pm2.get("uptime", "?"),
|
"pm2_uptime": pm2.get("uptime", "?"),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Tanko (CT 122)
|
# Tanko (CT 112, IP 192.168.68.122) — DSH (DeepSeek Harness), no Hermes gateway
|
||||||
tanko_state = ssh_jerome("192.168.68.122", "cat ~/.hermes/gateway_state.json 2>/dev/null")
|
# since 2026-08-27. There is no ~/.hermes/gateway_state.json on CT 112 anymore;
|
||||||
tanko_data = {}
|
# Zulip/Telegram connectivity is managed by the DSH harness, not the Hermes gateway.
|
||||||
try:
|
|
||||||
tanko_data = json.loads(tanko_state) if tanko_state else {}
|
|
||||||
except:
|
|
||||||
tanko_data = {}
|
|
||||||
platforms = tanko_data.get("platforms", {})
|
|
||||||
report["agents"]["tanko"] = {
|
report["agents"]["tanko"] = {
|
||||||
"platform": "hermes", "ct": 112, "ip": "192.168.68.122",
|
"platform": "dsh", "ct": 112, "ip": "192.168.68.122",
|
||||||
"gateway_state": tanko_data.get("gateway_state", "unknown"),
|
"gateway_state": "n/a (DSH)",
|
||||||
"zulip_state": platforms.get("zulip", {}).get("state", "unknown"),
|
"zulip_state": "unknown",
|
||||||
"telegram_state": platforms.get("telegram", {}).get("state", "unknown"),
|
"telegram_state": "unknown",
|
||||||
"gateway_pid": tanko_data.get("pid"),
|
"gateway_pid": None,
|
||||||
"updated_at": tanko_data.get("updated_at"),
|
"updated_at": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Mumuni (CT 100, IP 192.168.68.24)
|
# Mumuni (CT 100, IP 192.168.68.24)
|
||||||
@@ -543,7 +538,7 @@ th {{ color: #8b949e; font-weight: normal; }}
|
|||||||
elif name == "tanko":
|
elif name == "tanko":
|
||||||
zulip_state = "✅" if agent.get("zulip_state") == "connected" else ("❌" if agent.get("zulip_state") == "disconnected" else "⬜")
|
zulip_state = "✅" if agent.get("zulip_state") == "connected" else ("❌" if agent.get("zulip_state") == "disconnected" else "⬜")
|
||||||
gateway = agent.get("gateway_state", "?")
|
gateway = agent.get("gateway_state", "?")
|
||||||
processed = agent.get("updated_at", "")[:10]
|
processed = "DSH"
|
||||||
elif name == "mumuni":
|
elif name == "mumuni":
|
||||||
zulip_state = "⬜" if agent.get("zulip_state") == "not_installed" else ("✅" if agent.get("zulip_state") == "connected" else "⬜")
|
zulip_state = "⬜" if agent.get("zulip_state") == "not_installed" else ("✅" if agent.get("zulip_state") == "connected" else "⬜")
|
||||||
gateway = agent.get("gateway_state", "?")
|
gateway = agent.get("gateway_state", "?")
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ echo ""
|
|||||||
# Authorized agents for restricted contracts
|
# Authorized agents for restricted contracts
|
||||||
# Format: contract_pattern|authorized_agents (comma-separated)
|
# Format: contract_pattern|authorized_agents (comma-separated)
|
||||||
declare -A RESTRICTED
|
declare -A RESTRICTED
|
||||||
RESTRICTED["infrastructure-control.prose.md"]="abiba"
|
RESTRICTED["infrastructure-control.prose.md"]="abiba,abiba-bot,tanko,tanko-bot,mumuni,mumuni-bot"
|
||||||
RESTRICTED["proxmox-monitor.prose.md"]="abiba"
|
RESTRICTED["proxmox-monitor.prose.md"]="abiba,abiba-bot"
|
||||||
RESTRICTED["hermes-config-template.prose.md"]="abiba,mumuni,tanko"
|
RESTRICTED["hermes-config-template.prose.md"]="abiba,abiba-bot,mumuni,mumuni-bot,tanko,tanko-bot"
|
||||||
RESTRICTED["zulip-health.prose.md"]="abiba,mumuni"
|
RESTRICTED["zulip-health.prose.md"]="abiba,abiba-bot,mumuni,mumuni-bot,tanko,tanko-bot"
|
||||||
RESTRICTED["scripts/pm2-self-heal.sh"]="abiba"
|
RESTRICTED["scripts/pm2-self-heal.sh"]="abiba"
|
||||||
RESTRICTED["scripts/prose-lint.sh"]="abiba"
|
RESTRICTED["scripts/prose-lint.sh"]="abiba"
|
||||||
RESTRICTED["scripts/prose-ai-review.sh"]="abiba"
|
RESTRICTED["scripts/prose-ai-review.sh"]="abiba"
|
||||||
|
|||||||
@@ -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"
|
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
|
fi
|
||||||
|
|
||||||
# ── Platform B: Hermes (Tanko) ──
|
# ── Platform B: Tanko (DSH) ──
|
||||||
TANKO_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 jerome@192.168.68.122 \
|
# Tanko moved to DSH (DeepSeek Harness) on 2026-08-27. It no longer runs a Hermes
|
||||||
"cat ~/.hermes/gateway_state.json 2>/dev/null" 2>/dev/null || echo "{}")
|
# gateway, so there is no ~/.hermes/gateway_state.json on CT 112 (.122) to probe.
|
||||||
TANKO_ZULIP=$(echo "$TANKO_STATE" | python3 -c "
|
# Zulip connectivity for tanko is managed by the DSH harness; skip the legacy SSH probe.
|
||||||
import sys,json
|
echo " Tanko: ⏭️ skipped (DSH — no Hermes gateway since 2026-08-27)" >> "$LOG"
|
||||||
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: Hermes (Mumuni) ──
|
# ── Platform B: Hermes (Mumuni) ──
|
||||||
MUMUNI_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.24 \
|
MUMUNI_STATE=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@192.168.68.24 \
|
||||||
|
|||||||
+13
-12
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
kind: responsibility
|
kind: responsibility
|
||||||
name: zulip-health
|
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
|
title: Zulip Mesh Health Monitor — Multi-Platform
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
runtime_contract: 2
|
runtime_contract: 2
|
||||||
@@ -10,7 +10,7 @@ agent: abiba
|
|||||||
|
|
||||||
# Zulip Mesh Health Monitor
|
# 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.
|
Runs every 15 minutes in the background. Also triggers on session start.
|
||||||
|
|
||||||
## Requires
|
## Requires
|
||||||
@@ -45,7 +45,7 @@ Runs every 15 minutes in the background. Also triggers on session start.
|
|||||||
"severity": "healthy"
|
"severity": "healthy"
|
||||||
},
|
},
|
||||||
"tanko": {
|
"tanko": {
|
||||||
"platform": "hermes",
|
"platform": "dsh",
|
||||||
"zulip_state": "connected",
|
"zulip_state": "connected",
|
||||||
"heartbeat_age_seconds": 45,
|
"heartbeat_age_seconds": 45,
|
||||||
"gateway_pid": 1234,
|
"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)
|
## Streaming Support (2026-07-05)
|
||||||
|
|
||||||
Zulip agents now support progressive message editing during agent generation.
|
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:
|
streamed in real-time via Zulip's `PATCH /api/v1/messages/{id}` API:
|
||||||
|
|
||||||
- Adapter implements `edit_message()` using `_api_patch()` helper
|
- Adapter implements `edit_message()` using `_api_patch()` helper
|
||||||
@@ -182,15 +182,16 @@ grep -a "Finalized\|Failed to finalize" /root/.pm2/logs/abiba-zulip-out.log | ta
|
|||||||
| `last_error` set | Log and monitor |
|
| `last_error` set | Log and monitor |
|
||||||
| Crash loop >10/h | Alert user |
|
| Crash loop >10/h | Alert user |
|
||||||
|
|
||||||
### Step 3: Platform B — Hermes (Tanko .122, Mumuni .24)
|
### Step 3: Platform B — Tanko (DSH, .122) & Mumuni (Hermes, .24)
|
||||||
|
|
||||||
**B1: Gateway State**
|
**B1: Gateway State**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh root@192.168.68.122 "cat ~/.hermes/gateway_state.json"
|
|
||||||
ssh root@192.168.68.24 "cat ~/.hermes/gateway_state.json" # Mumuni inside Abiba CT100
|
ssh root@192.168.68.24 "cat ~/.hermes/gateway_state.json" # Mumuni inside Abiba CT100
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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.
|
Check `platforms.zulip.state`: `connected` ✅ | `disconnected` ❌ | `error` ❌ | missing → not installed.
|
||||||
|
|
||||||
**B2: Agent Process**
|
**B2: Agent Process**
|
||||||
@@ -204,23 +205,23 @@ Gateway PID should exist with uptime > 60s. **Dual-gateway detection**: if more
|
|||||||
| Agent | Restart command | Notes |
|
| Agent | Restart command | Notes |
|
||||||
|-------|-----------------|-------|
|
|-------|-----------------|-------|
|
||||||
| Mumuni (.24) | `pm2 restart abiba-zulip` | Hermes gateway runs under PM2 as `abiba-zulip` |
|
| Mumuni (.24) | `pm2 restart abiba-zulip` | Hermes gateway runs under PM2 as `abiba-zulip` |
|
||||||
| 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) |
|
| Tanko (.122) | DSH harness — restart via its DSH service, not a Hermes gateway | Tanko runs on DSH (CT 112) since 2026-08-27; no longer a Hermes agent, no `~/.hermes` gateway, no PM2 `mumuni-zulip` process |
|
||||||
|
|
||||||
Check gateway log for "Gateway running with 2 platform(s)" (not 1) to confirm Zulip reloaded.
|
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
|
```bash
|
||||||
ssh root@<CT> "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.
|
Expected: recent heartbeat (within 5 min), `polls=N` incrementing.
|
||||||
Silence > 300s → warning. Silence > 600s → critical.
|
Silence > 300s → warning. Silence > 600s → critical.
|
||||||
|
|
||||||
**B4: Response Delivery**
|
**B4: Response Delivery** (Hermes agent Mumuni only)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh root@<CT> "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.
|
> 50% fail rate → critical.
|
||||||
@@ -229,7 +230,7 @@ ssh root@<CT> "grep -E 'Finalized|Failed to finalize|Replied to' ~/.hermes/logs/
|
|||||||
|
|
||||||
| Condition | Action |
|
| Condition | Action |
|
||||||
|-----------|--------|
|
|-----------|--------|
|
||||||
| `zulip.state != "connected"` | `ssh root@<CT> "pkill -f 'gateway run'; sleep 2; hermes gateway restart"` |
|
| `zulip.state != "connected"` | `ssh root@<CT> "pkill -f 'gateway run'; sleep 2; hermes gateway restart"` (Mumuni) / restart Tanko via DSH service |
|
||||||
| No heartbeat in 10min | Same as above |
|
| No heartbeat in 10min | Same as above |
|
||||||
| `Failed to finalize` > 50% | Check PATCH API, Zulip server |
|
| `Failed to finalize` > 50% | Check PATCH API, Zulip server |
|
||||||
| Response empty/short | Check A2A endpoint / LiteLLM model |
|
| Response empty/short | Check A2A endpoint / LiteLLM model |
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ description: >
|
|||||||
|
|
||||||
> **⚠️ RETIRED** — The pi Zulip extension (`~/.pi/agent/extensions/zulip/`) and
|
> **⚠️ RETIRED** — The pi Zulip extension (`~/.pi/agent/extensions/zulip/`) and
|
||||||
> PM2 process (`abiba-zulip`) have been decommissioned. All mention/reliability
|
> 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.
|
> Agent Zero (kagentz) continue to use Zulip.
|
||||||
|
|
||||||
## Maintains
|
## Maintains
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ triggers:
|
|||||||
|
|
||||||
> **⚠️ RETIRED** — This contract was embedded in the pi Zulip extension code
|
> **⚠️ RETIRED** — This contract was embedded in the pi Zulip extension code
|
||||||
> (`performHealthCheck()`). That code has been removed. Zulip self-healing for
|
> (`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
|
## Maintains
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ triggers:
|
|||||||
| Zulip server | 192.168.68.19 | root | Docker: `zulip-zulip-1` |
|
| Zulip server | 192.168.68.19 | root | Docker: `zulip-zulip-1` |
|
||||||
| Abiba (pi) | localhost | root | PM2: `abiba-zulip` |
|
| Abiba (pi) | localhost | root | PM2: `abiba-zulip` |
|
||||||
| Mumuni | 192.168.68.24 (CT100 abiba) | root | `hermes gateway restart` |
|
| Mumuni | 192.168.68.24 (CT100 abiba) | root | `hermes gateway restart` |
|
||||||
| Tanko | 192.168.68.122 | jerome | `PATH=$PATH:/home/jerome/.hermes/hermes-agent hermes gateway restart` |
|
| Tanko | 192.168.68.122 (CT 112) | jerome | DSH (DeepSeek Harness) — restart via DSH service, not `hermes gateway restart` (no longer a Hermes agent since 2026-08-27) |
|
||||||
|
|
||||||
## Debounce
|
## Debounce
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user