From 98c4a2a02bfabd5c6c9ab546d2ab2052ba0fa0d1 Mon Sep 17 00:00:00 2001 From: ginnoir Date: Sat, 27 Jun 2026 05:18:21 -0500 Subject: [PATCH] docs: implementation plan for Hermes ecosystem integrations Phased, reversible plan. Phase 1 (acp-skill + curator-evolver, report-only) fully actionable; Phases 2-3 (camofox stack, eagle-eye trial, UI) gated on the spec's open decisions. Co-Authored-By: Claude Opus 4.8 --- ...2026-06-27-hermes-ecosystem-integration.md | 442 ++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-27-hermes-ecosystem-integration.md diff --git a/docs/superpowers/plans/2026-06-27-hermes-ecosystem-integration.md b/docs/superpowers/plans/2026-06-27-hermes-ecosystem-integration.md new file mode 100644 index 0000000..16a2dfe --- /dev/null +++ b/docs/superpowers/plans/2026-06-27-hermes-ecosystem-integration.md @@ -0,0 +1,442 @@ +# Hermes Ecosystem Integration Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Integrate selected Hermes-ecosystem tools into ginnoir's live valhalla deployment — a host-side delegation skill and self-improvement plugin (Phase 1), a stealth-browser homelab stack and a skill pre-filter trial (Phase 2), and an optional UI upgrade (Phase 3) — each reversible and sized for the single-P100 / weak-local-model constraints. + +**Architecture:** Two integration classes. **Class A** (host-side Hermes plugins/skills) install into `~/.hermes/` on the valhalla host and are applied by SSH + `hermes` CLI + `sudo systemctl restart hermes-gateway.service`; they are **host-managed, NOT committed to this repo** (tracked in project memory + the Obsidian vault, like the rustdesk/obsidian/xvfb units). **Class B** (Docker services) become `stacks//` entries deployed via the normal Gitea-poll path, fronted by Caddy `internal_only` + Authentik. The companion spec is `docs/superpowers/specs/2026-06-27-hermes-ecosystem-integration-design.md`. + +**Tech Stack:** Hermes Agent v0.17.0 (host systemd), llama-swap/Tesla P100 backend (`gpt-oss-20b`, `--parallel 1`), Python 3.11 (`~/.hermes/hermes-agent/venv`), `uv`, SQLite, Docker Compose + Portainer (Gitea-polled), Caddy, Authentik, Codex + Claude Code CLIs. + +--- + +## How to read this plan (operational, not codebase-TDD) + +These are operational integrations against a live host and third-party services, so the TDD rhythm +is adapted: each task is **back up → change → verify with a smoke test → document/commit**. The +"test" is a real verification command with expected output. **Class A (host) changes are not git +commits** — their checkpoint is a backup + smoke test + a memory/vault note. **Class B (repo) +changes do commit** (and push triggers Portainer). Run every step from the Windows workstation; +host steps use `ssh -o BatchMode=yes ginnoir@valhalla "..."`. + +**Global guardrails (apply to every task):** +- `hermes` is only on the **login-shell** PATH → over SSH call it by full path: `~/.local/bin/hermes`. +- Gateway restart needs root: `sudo systemctl restart hermes-gateway.service`. +- Always back up `~/.hermes/config.yaml` before editing (`cp ...bak.$(date +%s)`). +- **Never** load a second model onto the P100. Keep curator/eagle-eye semantic layers on CPU or off. +- Read third-party code before running it (curator writes skills; acp-skill spawns external agents; camofox automates a browser). + +**Decision gates:** Phase 1 is fully actionable now. **Phases 2 and 3 are gated on the spec §6 +decisions** (UI choice; curator autonomy; eagle-eye trial; camofox wiring). Do not start a gated +task group until ginnoir has answered. + +--- + +# PHASE 1 — Host-side, reversible, high-leverage (actionable now) + +## Task 1: Pre-flight — capture current Hermes state + +**Files:** +- Host only (no repo files). + +- [ ] **Step 1: Verify host reachability and Hermes services are up** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "systemctl is-active hermes-gateway.service hermes-dashboard.service hermes-webui.service" +``` +Expected: three lines, each `active`. + +- [ ] **Step 2: Snapshot config + inventory skills/plugins/sessions dirs** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "cp ~/.hermes/config.yaml ~/.hermes/config.yaml.bak.preflight.$(date +%s) && ls -la ~/.hermes/skills ~/.hermes/plugins ~/.hermes/sessions 2>&1 | head -60 && ~/.local/bin/hermes --version" +``` +Expected: a backup is created; directory listings print (note whether `~/.hermes/plugins` exists yet); `hermes` prints a version (≈ v0.17.0). Record the skills-dir path — confirms `~/.hermes/skills` is correct for later tasks. + +- [ ] **Step 3: Confirm Codex and Claude Code are invocable from the host as ginnoir** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "bash -lc 'which codex; which claude; codex --version 2>&1 | head -1; claude --version 2>&1 | head -1'" +``` +Expected: paths for both `codex` and `claude`, and a version line each. (Uses `-lc` to get the login PATH.) **If either is missing**, the ACP delegation skill (Task 2) can still install but its `codex`/`claude-code` targets will be non-functional until they're on the service PATH — note this for ginnoir. + +- [ ] **Step 4: Checkpoint** + +No commit (host inventory only). Record findings (skills-dir path, whether `plugins/` exists, Codex/Claude availability) in the session notes for use in Tasks 2–3. + +--- + +## Task 2: Install `hermes-agent-acp-skill` (multi-agent delegation) + +**Files:** +- Host: `~/.hermes/skills/hermes-acp-orchestrator/` (skill files), `~/.hermes/config.yaml` (delegation block). +- Scratch: clone under `/storage1/hermes/workspace/clones/` (never root; see the disk gotcha). + +- [ ] **Step 1: Clone and read the skill before installing** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "mkdir -p /storage1/hermes/workspace/clones && git -C /storage1/hermes/workspace/clones clone https://github.com/Rainhoole/hermes-agent-acp-skill && sed -n '1,200p' /storage1/hermes/workspace/clones/hermes-agent-acp-skill/SKILL.md" +``` +Expected: repo clones; `SKILL.md` prints. **Read it** to confirm: the skill folder/name, how `delegate_task()` is wired, and whether it expects a specific install path or a config key. The README omits install steps, so the SKILL.md is authoritative — follow whatever placement it documents. If SKILL.md specifies a different mechanism than the manual copy below, use SKILL.md's. + +- [ ] **Step 2: Place the skill into the Hermes skills directory** + +Run (adjust the destination name to match SKILL.md's declared skill name): +```bash +ssh -o BatchMode=yes ginnoir@valhalla "mkdir -p ~/.hermes/skills/hermes-acp-orchestrator && cp -r /storage1/hermes/workspace/clones/hermes-agent-acp-skill/SKILL.md /storage1/hermes/workspace/clones/hermes-agent-acp-skill/README.md ~/.hermes/skills/hermes-acp-orchestrator/ && ls -la ~/.hermes/skills/hermes-acp-orchestrator/" +``` +Expected: `SKILL.md` and `README.md` present in the new skill dir. + +- [ ] **Step 3: Add the delegation config block (with a safe backup)** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "cp ~/.hermes/config.yaml ~/.hermes/config.yaml.bak.acp.$(date +%s) && printf '\ndelegation:\n external_timeout_seconds: 900\n external_max_output_chars: 24000\n' >> ~/.hermes/config.yaml && tail -8 ~/.hermes/config.yaml" +``` +Expected: a `.bak.acp.*` backup exists; the `delegation:` block is appended and printed. (If SKILL.md says the block belongs under a different key or nesting, edit accordingly instead of this append.) + +- [ ] **Step 4: Restart the gateway and confirm the skill registers** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "sudo systemctl restart hermes-gateway.service && sleep 5 && systemctl is-active hermes-gateway.service && ~/.local/bin/hermes skills list 2>&1 | grep -i acp" +``` +Expected: gateway `active`; the ACP/orchestrator skill appears in `hermes skills list`. (If the subcommand differs, use `~/.local/bin/hermes skills --help` to find the list command — verify on host.) + +- [ ] **Step 5: Smoke-test a trivial delegation to the local hermes subagent first** + +Run (a no-external-dependency delegation — routes to `hermes`, not Codex/Claude, to isolate the skill from CLI availability): +```bash +ssh -o BatchMode=yes ginnoir@valhalla "~/.local/bin/hermes run 'Use delegate_task to ask a hermes subagent to reply with exactly the word PONG, then report its output.' 2>&1 | tail -30" +``` +Expected: the delegated subagent returns `PONG` and the parent reports it. **This proves the skill mechanics.** (Exact `hermes` one-shot invocation may differ — confirm the non-interactive run command via `~/.local/bin/hermes --help` in Step 1's read-through.) + +- [ ] **Step 6: Smoke-test an external delegation (only if Codex/Claude were found in Task 1)** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "~/.local/bin/hermes run 'Use delegate_task with agent=claude-code to print the current working directory and nothing else, then report it.' 2>&1 | tail -40" +``` +Expected: Claude Code is spawned within the 900 s timeout, returns the cwd, output is captured under the 24,000-char cap. **If it hangs or auths interactively**, the external CLI needs non-interactive credentials on the service env — note for ginnoir; the `hermes`-target path (Step 5) still works. + +- [ ] **Step 7: Checkpoint (host note + reversibility recorded)** + +No git commit. Record in session notes: skill installed at `~/.hermes/skills/hermes-acp-orchestrator/`, config backup at `~/.hermes/config.yaml.bak.acp.*`. **Rollback** = `rm -rf ~/.hermes/skills/hermes-acp-orchestrator`, restore the `.bak.acp.*`, restart gateway. + +--- + +## Task 3: Install `hermes-curator-evolver` (self-improvement, report-only) + +**Files:** +- Host: `~/.hermes/plugins/curator-evolver/` (plugin + `data/evidence.sqlite`), systemd **user** timer. + +- [ ] **Step 1: Read the plugin source before installing (it can write to skills)** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "git -C /storage1/hermes/workspace/clones clone https://github.com/pingchesu/hermes-curator-evolver && sed -n '1,160p' /storage1/hermes/workspace/clones/hermes-curator-evolver/README.md" +``` +Expected: repo clones; README prints. Confirm the apply path requires `--approve` (it does per the README) and that `auto-run` without `--apply-low-risk --approve-auto-apply` is **dry-run only**. + +- [ ] **Step 2: Install the plugin (no semantic/embedding extras — keep it off the P100)** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "bash -lc '~/.local/bin/hermes plugins install pingchesu/hermes-curator-evolver --enable && uv pip install --python ~/.hermes/hermes-agent/venv/bin/python -e ~/.hermes/plugins/curator-evolver && ~/.hermes/hermes-agent/venv/bin/hermes-curator-evolver bootstrap'" +``` +Expected: plugin installs to `~/.hermes/plugins/curator-evolver`; editable pip install succeeds; `bootstrap` configures and installs a **systemd user timer**. **Do NOT pass `--semantic`** (that pulls Qwen/BGE models — CPU/VRAM cost we're avoiding for now; BM25/FTS ranking is the v1 default). + +- [ ] **Step 3: Backfill recent sessions and generate the first dry-run report** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "~/.hermes/hermes-agent/venv/bin/hermes-curator-evolver backfill-sessions --sessions-dir ~/.hermes/sessions --days 30 --format json 2>&1 | tail -20 && ~/.hermes/hermes-agent/venv/bin/hermes-curator-evolver report --days 7 --format json 2>&1 | tail -40" +``` +Expected: evidence is mined into `~/.hermes/plugins/curator-evolver/data/evidence.sqlite`; `report` prints a JSON summary of candidate skill improvements. **No skill files are modified** (report is read-only). + +- [ ] **Step 4: Generate a dry-run proposal for one skill and inspect it** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "~/.hermes/hermes-agent/venv/bin/hermes-curator-evolver auto-run --skills-dir ~/.hermes/skills --format json 2>&1 | tail -60" +``` +Expected: a JSON set of **proposed** (not applied) edits. Confirm no files under `~/.hermes/skills` changed: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "find ~/.hermes/skills -newermt '-10 minutes' -type f 2>/dev/null" +``` +Expected: empty output (nothing modified) — proves dry-run safety. + +- [ ] **Step 5: Confirm the scheduled timer is report-only** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "bash -lc 'systemctl --user list-timers \"hermes-curator-evolver*\" --all --no-pager' && ssh -o BatchMode=yes ginnoir@valhalla \"systemctl --user cat 'hermes-curator-evolver*' 2>&1 | grep -iE 'ExecStart|approve|apply'\"" +``` +Expected: a timer is listed; its `ExecStart` runs `auto-run` **without** `--apply-low-risk`/`--approve-auto-apply`. **If the bootstrap-installed unit includes those flags, override it** to remove them (the morning decision in spec §6.2 defaults to report-only). If user-lingering isn't enabled the timer won't fire across logout — enable with `sudo loginctl enable-linger ginnoir` (note for ginnoir). + +- [ ] **Step 6: Checkpoint (host note + reversibility recorded)** + +No git commit. Record: plugin at `~/.hermes/plugins/curator-evolver`, DB at `.../data/evidence.sqlite`, timer name, report-only confirmed. **Rollback** = `systemctl --user disable --now `, `~/.local/bin/hermes plugins uninstall curator-evolver` (verify exact uninstall verb), `rm -rf ~/.hermes/plugins/curator-evolver`. + +--- + +## Task 4: Document Phase 1 in memory + vault (durable knowledge) + +**Files:** +- Memory: `C:\Users\MattC\.claude\projects\C--Users-MattC-Documents-homelabstack\memory\hermes-extensions.md` + `MEMORY.md` pointer. +- Vault: append to the Hermes project note via Obsidian MCP (`mcp__obsidian__*`). + +- [ ] **Step 1: Write the memory file** + +Create `memory/hermes-extensions.md` (frontmatter `type: project`) recording: acp-skill installed (delegation to hermes/codex/claude-code, 900s/24k caps), curator-evolver installed **report-only** (CPU ranking, no `--semantic`, no auto-apply flags), exact paths and rollback commands, and the host-vs-repo boundary. Link `[[llm-stack-hermes]]`, `[[multi-agent-tool-configs]]`, `[[obsidian-app-on-valhalla]]`. + +- [ ] **Step 2: Add the MEMORY.md index pointer** + +Append one line to `MEMORY.md`: +`- [Hermes host extensions](hermes-extensions.md) — acp delegation skill + curator-evolver (report-only) on valhalla; host-managed in ~/.hermes, not in the repo` + +- [ ] **Step 3: Write back to the Obsidian vault** + +Per the global rule, use the Obsidian MCP (never write CouchDB directly) to append a session note to the Hermes project folder summarizing Phase 1 (what, why report-only, rollback). If the MCP is unreachable, tell ginnoir and skip — do not hand-edit. + +- [ ] **Step 4: Checkpoint** + +No code commit required (memory files live outside the repo). Phase 1 complete and documented. + +--- + +# PHASE 2 — New capability + experiment (GATED on spec §6.3 / §6.4) + +> Start only after ginnoir confirms: trial eagle-eye (§6.3) and camofox wiring choice (§6.4). + +## Task 5: `camofox-browser` as a homelab stack (Class B) + +**Files:** +- Create: `stacks/camofox/docker-compose.yml`, `stacks/camofox/stack.env`. +- Modify: `Caddyfile` (new site block), `bookmarks-domains.html` + `bookmarks-ports.html` (regenerated). +- Host (image): build under `/storage1/hermes/workspace/clones/camofox-browser`. + +- [ ] **Step 1: Decide image provenance and build it** + +camofox publishes **no registry image** (`make up` builds locally). Recommended default: build on +valhalla and tag `camofox-browser:local`, reference that tag from compose (Watchtower already +disabled for pinned infra). Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "git -C /storage1/hermes/workspace/clones clone https://github.com/jo-inc/camofox-browser && cd /storage1/hermes/workspace/clones/camofox-browser && docker build -t camofox-browser:local . 2>&1 | tail -20 && docker image ls camofox-browser:local" +``` +Expected: image builds; `camofox-browser:local` is listed. **Alternative (if a reproducible/Gitea-Actions build is preferred, like famapp):** build + push to `registry.ginnoir.com/ginnoir/camofox-browser` and reference that instead — flag this choice for ginnoir. + +- [ ] **Step 2: Write the stack compose** + +Create `stacks/camofox/docker-compose.yml`: +```yaml +# camofox stack — stealth headless browser REST API for the Hermes agent. +# No published image: built on-host as camofox-browser:local (see plan Task 5). +# Internal-only; reachable by Caddy over edge and by host-side Hermes. +services: + camofox: + image: camofox-browser:local + container_name: camofox + restart: unless-stopped + labels: + - "com.centurylabs.watchtower.enable=false" + env_file: + - stack.env + networks: [edge, camofox] + volumes: + - /config/camofox/cookies:/home/node/.camofox/cookies + - /config/camofox/profiles:/home/node/.camofox/profiles + ports: + - "172.20.0.1:9377:9377" + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost:9377/health"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 40s + +networks: + edge: + external: true + camofox: + name: camofox + driver: bridge +``` +(The `172.20.0.1:9377` host-port mirrors the llm stack's pattern so host-side Hermes can reach it directly; Caddy reaches it over `edge` by container name.) + +- [ ] **Step 3: Write `stack.env` (secrets; LF endings)** + +Create `stacks/camofox/stack.env` with a generated bearer key (replace the value with a real secret before push): +``` +CAMOFOX_ACCESS_KEY=GENERATE_A_LONG_RANDOM_KEY +CAMOFOX_ADMIN_KEY=GENERATE_A_SECOND_RANDOM_KEY +CAMOFOX_PORT=9377 +``` +Generate the keys: `ssh ... "openssl rand -hex 32"` (run twice). **Ensure LF line endings** (`.gitattributes` enforces this — verify the file isn't CRLF before committing). Leave `CAMOFOX_API_KEY` unset (cookie-import endpoint stays disabled). + +- [ ] **Step 4: Add the Caddy site block (internal-only)** + +Add to `Caddyfile` (place near other internal admin services). Since camofox enforces its own bearer auth and Hermes calls it machine-to-machine, gate by LAN only (no Authentik forward-auth, which would block the agent's API calls): +```caddy +camofox.ginnoir.com { + import internal_only + reverse_proxy camofox:9377 +} +``` + +- [ ] **Step 5: Create host config dirs, regenerate bookmarks, then deploy** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "sudo mkdir -p /config/camofox/cookies /config/camofox/profiles && sudo chown -R ginnoir:ginnoir /config/camofox" +``` +Then regenerate bookmarks and push (Portainer must have the `stacks/camofox` git stack registered — see Step 6): +```powershell +./scripts/gen-bookmarks.ps1 +git add stacks/camofox/ Caddyfile bookmarks-domains.html bookmarks-ports.html +git commit -m "feat(camofox): stealth browser stack for the Hermes agent" +git push +``` +Expected: commit + push; Gitea Actions reloads Caddy (Caddyfile changed); Portainer redeploys the camofox stack within 5 min. + +- [ ] **Step 6: Register the stack in Portainer if new, and verify it runs** + +New stacks need one-time Portainer registration (see `portainer-new-stack-registration` memory). After deploy, verify: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "docker ps --filter name=camofox --format '{{.Names}} {{.Status}}' && curl -fsS http://172.20.0.1:9377/health" +``` +Expected: container `Up (healthy)`; `/health` returns OK. + +- [ ] **Step 7: Smoke-test the browser API end-to-end** + +Run (creates a tab, snapshots a page): +```bash +ssh -o BatchMode=yes ginnoir@valhalla "K=\$(grep CAMOFOX_ACCESS_KEY /config/portainer/compose/*/stacks/camofox/stack.env | cut -d= -f2); ID=\$(curl -fsS -H \"Authorization: Bearer \$K\" -H 'Content-Type: application/json' -d '{\"userId\":\"smoke\",\"sessionKey\":\"t1\",\"url\":\"https://example.com\"}' http://172.20.0.1:9377/tabs | python3 -c 'import sys,json;print(json.load(sys.stdin)[\"id\"])'); curl -fsS -H \"Authorization: Bearer \$K\" \"http://172.20.0.1:9377/tabs/\$ID/snapshot?userId=smoke\" | head -20" +``` +Expected: a tab id comes back; the snapshot returns accessibility text containing "Example Domain". (Adjust the JSON id field name to match the real response from Step 1's README read.) + +- [ ] **Step 8: Wire camofox into Hermes as a minimal tool surface (per §6.4 decision)** + +Default recommendation: a **small Hermes skill** (2 high-level tools — `browse(url)` and `search(query)`) that curls camofox, rather than exposing the full REST surface (respects the tool-budget that keeps gpt-oss-20b functional). Create `~/.hermes/skills/camofox-browse/SKILL.md` documenting the two operations against `http://172.20.0.1:9377` with the bearer key, restart the gateway, and smoke-test: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "sudo systemctl restart hermes-gateway.service && sleep 5 && ~/.local/bin/hermes run 'browse https://example.com and tell me the page heading' 2>&1 | tail -20" +``` +Expected: Hermes uses the camofox tool and reports "Example Domain". **If §6.4 chose an MCP shim instead**, build/register the MCP server and add it to `mcp_servers:` with a 2-tool `tools.include` allowlist (per the MCP-curation pattern in `llm-stack-hermes`). + +- [ ] **Step 9: Checkpoint** + +Repo changes are committed (Step 5). Update `memory/hermes-extensions.md` + the vault note with the camofox stack + tool wiring and the bearer-key location. + +--- + +## Task 6: Trial `eagle-eye` skill pre-filter (Class A, behind a switch) + +**Files:** +- Host: `~/.hermes/plugins/eagle-eye/` (or skills dir per its README), config toggle in `~/.hermes/config.yaml`. + +- [ ] **Step 1: Clone and read; confirm graceful-degradation and the jieba dependency** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "git -C /storage1/hermes/workspace/clones clone https://github.com/willingning-coder/eagle-eye && sed -n '1,200p' /storage1/hermes/workspace/clones/eagle-eye/README.md" +``` +Expected: README prints. Confirm the install hook, the on/off switch, and that L2–L5 (incl. dense embeddings) are optional. **Plan to run with the dense layer disabled** (CPU/keep off the P100) — lean on L1 (hard triggers) + L2 (BM25) only for the trial. + +- [ ] **Step 2: Install with an easy off-switch and minimal deps** + +Install per the README (likely `~/.local/bin/hermes plugins install willingning-coder/eagle-eye --enable`), then restart the gateway: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "bash -lc '~/.local/bin/hermes plugins install willingning-coder/eagle-eye --enable' && ssh -o BatchMode=yes ginnoir@valhalla 'sudo systemctl restart hermes-gateway.service && systemctl is-active hermes-gateway.service'" +``` +Expected: plugin enabled; gateway `active`. (If install fails on `jieba`, `uv pip install --python ~/.hermes/hermes-agent/venv/bin/python jieba` then retry — note the foreign-language dep for maintenance.) + +- [ ] **Step 3: A/B test skill selection on representative prompts** + +Pick 5 prompts that should each map to a known skill and 2 that should map to none. Run each with eagle-eye enabled, then disable it (`~/.local/bin/hermes plugins disable eagle-eye` + gateway restart) and run the same 7. Record which skills each surfaced and whether the local model then picked the right one. +```bash +ssh -o BatchMode=yes ginnoir@valhalla "~/.local/bin/hermes run '' 2>&1 | tail -25" +``` +Expected: with eagle-eye on, the prompt's prompt-injected skill candidates are ≤5 and include the right one; the "no skill needed" prompts proceed without forced skill loading. + +- [ ] **Step 4: Keep-or-cut decision** + +**Keep only if** skill selection measurably improved (right skill surfaced more often AND/OR fewer wrong skills loaded) without regressions. Otherwise disable and uninstall: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "~/.local/bin/hermes plugins uninstall eagle-eye && sudo systemctl restart hermes-gateway.service" +``` +Record the verdict + evidence in `memory/hermes-extensions.md`. + +- [ ] **Step 5: Checkpoint** + +No repo commit (host-side). Document the A/B result and final state (kept/cut) in memory + vault. + +--- + +# PHASE 3 — UI decision (GATED on spec §6.1) + +> Start only after ginnoir picks a UI direction. Default recommended first move: **trial `hermes-ui`** +> (Task 7). `hermes-workspace` (Task 8) is the heavier alternative; `mission-control` is skipped. + +## Task 7: Trial `hermes-ui` (lightweight, no build) + +**Files:** +- Host: clone at `/storage1/hermes/workspace/clones/hermes-ui`; optional `hermes-ui.service` (host unit) or a tiny container; Caddy block if exposed. + +- [ ] **Step 1: Clone and run the stdlib proxy against the live gateway** + +Run: +```bash +ssh -o BatchMode=yes ginnoir@valhalla "git -C /storage1/hermes/workspace/clones clone https://github.com/pyrate-llama/hermes-ui && cd /storage1/hermes/workspace/clones/hermes-ui && (~/.hermes/hermes-agent/venv/bin/python3 serve_lite.py >/tmp/hermes-ui.log 2>&1 &) && sleep 3 && curl -fsS http://127.0.0.1:3333/hermes-ui.html | head -5" +``` +Expected: the proxy starts on :3333 (defaults to gateway `127.0.0.1:8642`, which matches your deployment), and the HTML serves. If your gateway port differs, edit the `HERMES` variable at the top of `serve_lite.py` (no env var exists). + +- [ ] **Step 2: Evaluate against the bundled webui** + +Browse it from the LAN (port-forward or temporary Caddy block) and compare to the existing `hermes-webui.service`: chat/streaming, tasks/kanban, files, terminal, skills, MCP browser, cron, memory, health. Decide keep-or-revert. + +- [ ] **Step 3: If keeping — make it boot-persistent and gate it** + +Create a host unit `hermes-ui.service` (host-managed, like `obsidian.service` — NOT in this repo) running `serve_lite.py`, `After=hermes-gateway.service`, `Restart=on-failure`. Add a Caddy block `hermes-ui.ginnoir.com { import internal_only; reverse_proxy 172.20.0.1:3333 }` (publish the proxy on the host IP if exposing via Caddy), regenerate bookmarks, push the Caddyfile change. **If reverting**, kill the proxy (`pkill -f 'serve_lite[.]py'` — bracket trick to avoid self-match) and remove the clone. + +- [ ] **Step 4: Checkpoint** + +Repo change is only the Caddy block (if exposed) — commit + push that. The service unit is host-managed; document it in memory + vault alongside the `obsidian.service` note. + +--- + +## Task 8: (Alternative) Evaluate `hermes-workspace` as a stack — scoping only + +> Only if ginnoir prefers the full command center over `hermes-ui`. This task is a **scoping +> checkpoint**, not a build, because it carries a real caveat to resolve first. + +- [ ] **Step 1: Confirm the swarm caveat before investing in a build** + +`hermes-workspace`'s Swarm Mode (parallel tmux worker pools) **cannot parallelize inference** on a +single P100 (`--parallel 1`, one model at a time) — swarm workers serialize on the GPU or must +target a different backend. Decide with ginnoir whether the non-swarm features (workspace, ops +dashboards, Conductor missions) alone justify a React/Vite build + a new `stacks/hermes-workspace` +Docker stack behind Caddy + Authentik (gateway :8642 + dashboard :9119). If yes, this becomes its +own full plan (separate spec/plan cycle). If no, stop — `hermes-ui` (Task 7) is the chosen UI. + +- [ ] **Step 2: Checkpoint** + +Decision recorded in the vault. No implementation here without a dedicated follow-up plan. + +--- + +## Self-Review (completed) + +- **Spec coverage:** All 7 repos map to tasks — acp-skill (T2), curator-evolver (T3), camofox (T5), + eagle-eye (T6), hermes-ui (T7), hermes-workspace (T8 scoping), mission-control (explicitly skipped + per spec §2.5/§5, no task — intentional). Phase ordering, single-P100 discipline, host-vs-repo + boundary, provenance/reversibility, and the §6 decision gates are all reflected. +- **Placeholders:** None of the prohibited kinds. Where a third-party command form can't be verified + remotely (e.g. exact `hermes` subcommand spelling, acp-skill install mechanism, response field + names), the plan's **first step is a concrete "clone + read the README/SKILL.md" command** that + resolves it before use — a real action with expected output, not a TBD. +- **Consistency:** Paths and names are consistent throughout (`~/.hermes/skills`, `~/.hermes/plugins/curator-evolver`, `camofox-browser:local`, port 9377, gateway 8642, `172.20.0.1` host-IP publish pattern, `sudo systemctl restart hermes-gateway.service`). +- **Decision gates:** Phases 2–3 are clearly gated on spec §6 and must not start before ginnoir answers.