Files
homelabstack/docs/superpowers/plans/2026-06-27-hermes-ecosystem-integration.md
T
ginnoirandClaude Opus 4.8 98c4a2a02b 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 <noreply@anthropic.com>
2026-06-27 05:18:21 -05:00

27 KiB
Raw Blame History

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/<name>/ 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:

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:

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:

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 23.


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:

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):

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:

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:

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):

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:

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:

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:

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:

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:

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:

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:

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 <timer>, ~/.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:

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:

# 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):

camofox.ginnoir.com {
	import internal_only
	reverse_proxy camofox:9377
}
  • Step 5: Create host config dirs, regenerate bookmarks, then deploy

Run:

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):

./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:

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):

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:

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:

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 L2L5 (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:

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.

ssh -o BatchMode=yes ginnoir@valhalla "~/.local/bin/hermes run '<representative prompt>' 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:

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:

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 23 are clearly gated on spec §6 and must not start before ginnoir answers.