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>
27 KiB
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):
hermesis 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.yamlbefore 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 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:
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.mdpointer. -
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 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:
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-controlis skipped.
Task 7: Trial hermes-ui (lightweight, no build)
Files:
-
Host: clone at
/storage1/hermes/workspace/clones/hermes-ui; optionalhermes-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
hermessubcommand 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.1host-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.