docs: resolve Hermes integration decisions (both UIs, report-only, eagle-eye)

UI: trial hermes-ui + hermes-workspace in parallel, keep winner (new Task 9).
Curator stays report-only. eagle-eye trial confirmed (only direct skill-router
in the ecosystem; llmtrim noted as complementary). camofox minimal 2-tool skill.
All phases now ungated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ginnoir
2026-06-27 05:30:37 -05:00
co-authored by Claude Opus 4.8
parent 98c4a2a02b
commit 3cd843072d
2 changed files with 198 additions and 49 deletions
@@ -26,9 +26,9 @@ host steps use `ssh -o BatchMode=yes ginnoir@valhalla "..."`.
- **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.
**Decisions (RESOLVED 2026-06-27 — all phases actionable):** trial **both** UIs and keep the winner
(Phase 3); curator stays **report-only** (Task 3); **trial eagle-eye** — it's the only direct
skill-router in the ecosystem (Task 6); camofox wired as a **minimal 2-tool skill** (Task 5 Step 8).
---
@@ -209,9 +209,9 @@ No code commit required (memory files live outside the repo). Phase 1 complete a
---
# PHASE 2 — New capability + experiment (GATED on spec §6.3 / §6.4)
# PHASE 2 — New capability + experiment
> Start only after ginnoir confirms: trial eagle-eye (§6.3) and camofox wiring choice (§6.4).
> Decisions resolved (spec §6.3 eagle-eye trial; §6.4 camofox minimal). Actionable.
## Task 5: `camofox-browser` as a homelab stack (Class B)
@@ -335,6 +335,12 @@ Repo changes are committed (Step 5). Update `memory/hermes-extensions.md` + the
## Task 6: Trial `eagle-eye` skill pre-filter (Class A, behind a switch)
> Confirmed the chosen tool: eagle-eye is the **only** direct skill-router in the Hermes ecosystem
> (per `awesome-hermes-agent` / Hermes Atlas). It directly serves the goal of "many skills installed,
> few injected per turn." Complementary (not a substitute) and worth a later look on the *tool* side:
> `llmtrim` (compresses tool schemas + MCP output before each request). `hermes-motif` overlaps
> curator-evolver (trace→micro-skill), not this router.
**Files:**
- Host: `~/.hermes/plugins/eagle-eye/` (or skills dir per its README), config toggle in `~/.hermes/config.yaml`.
@@ -376,10 +382,11 @@ No repo commit (host-side). Document the A/B result and final state (kept/cut) i
---
# PHASE 3 — UI decision (GATED on spec §6.1)
# PHASE 3 — UI trial: stand up BOTH, keep the winner
> 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.
> Decision resolved (spec §6.1): trial `hermes-ui` (Task 7) **and** `hermes-workspace` (Task 8) in
> parallel, compare head-to-head against the bundled webui (Task 9), keep one and tear down the
> rest. `mission-control` is skipped.
## Task 7: Trial `hermes-ui` (lightweight, no build)
@@ -394,46 +401,180 @@ ssh -o BatchMode=yes ginnoir@valhalla "git -C /storage1/hermes/workspace/clones
```
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**
- [ ] **Step 2: Expose it on the LAN for evaluation (don't finalize yet)**
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.
Bind the proxy to the host IP so Caddy can reach it, add a temporary internal-only Caddy block, and
keep it running for the Task 9 comparison:
```caddy
hermes-ui.ginnoir.com {
import internal_only
reverse_proxy 172.20.0.1:3333
}
```
Run `serve_lite.py` bound appropriately (edit its bind host if it defaults to `127.0.0.1`), regenerate
bookmarks, push the Caddyfile change. **Do not** create the persistent `hermes-ui.service` yet — that
happens in Task 9 only for the winner.
- [ ] **Step 3: If keeping — make it boot-persistent and gate it**
- [ ] **Step 3: Checkpoint**
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.
hermes-ui is reachable at `https://hermes-ui.ginnoir.com` (LAN) for the head-to-head. Leave the
final keep/revert + boot-persistence to Task 9.
---
## Task 8: (Alternative) Evaluate `hermes-workspace` as a stack — scoping only
## Task 8: Deploy `hermes-workspace` as a stack (Class B) — for evaluation
> 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.
**Files:**
- Create: `stacks/hermes-workspace/docker-compose.yml`, `stacks/hermes-workspace/stack.env`.
- Modify: `Caddyfile` (Authentik-gated site block), `bookmarks-domains.html` + `bookmarks-ports.html`.
- Host (image): build under `/storage1/hermes/workspace/clones/hermes-workspace`.
- [ ] **Step 1: Confirm the swarm caveat before investing in a build**
- [ ] **Step 1: Clone and read its deployment docs (get exact build, ports, env)**
`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.
Run:
```bash
ssh -o BatchMode=yes ginnoir@valhalla "git -C /storage1/hermes/workspace/clones clone https://github.com/outsourc-e/hermes-workspace && sed -n '1,200p' /storage1/hermes/workspace/clones/hermes-workspace/README.md && ls /storage1/hermes/workspace/clones/hermes-workspace/{Dockerfile,docker-compose*.yml,.env*} 2>&1"
```
Expected: README + a `Dockerfile`/compose appear. Record the exact image build command, the served
port, and the env var(s) that point the frontend at the gateway (`:8642`) and dashboard (`:9119`).
**Note the swarm caveat for Task 9:** Swarm Mode (tmux worker pools) can't parallelize inference on
one P100 — evaluate the workspace/observability features, not swarm.
- [ ] **Step 2: Checkpoint**
- [ ] **Step 2: Resolve container→host-service reachability**
Decision recorded in the vault. No implementation here without a dedicated follow-up plan.
hermes-workspace (a container) must reach the host's gateway `:8642` and dashboard `:9119`. Check
what interface those bind to:
```bash
ssh -o BatchMode=yes ginnoir@valhalla "ss -ltnp | grep -E ':8642|:9119'"
```
Expected: shows the bind address. **If bound to `127.0.0.1`**, the container can't reach them — pick
one: (a) add `extra_hosts: ["host.docker.internal:host-gateway"]` and target `host.docker.internal`,
or (b) rebind the Hermes services to the docker-bridge host IP `172.20.0.1` (config change + gateway
restart, with backup). Default recommendation: **(a)** (no Hermes config change; reversible).
- [ ] **Step 3: Build the image on-host**
Run (use the build command discovered in Step 1; tag locally since there's no published image):
```bash
ssh -o BatchMode=yes ginnoir@valhalla "cd /storage1/hermes/workspace/clones/hermes-workspace && docker build -t hermes-workspace:local . 2>&1 | tail -20 && docker image ls hermes-workspace:local"
```
Expected: `hermes-workspace:local` is built and listed.
- [ ] **Step 4: Write the stack compose**
Create `stacks/hermes-workspace/docker-compose.yml` (adjust the served port and gateway/dashboard env
keys to Step 1's findings; this uses host.docker.internal per Step 2 option (a)):
```yaml
# hermes-workspace stack — full web command center for the Hermes agent (trial).
# No published image: built on-host as hermes-workspace:local (see plan Task 8).
# Human-facing UI → Authentik-gated. Reaches host gateway :8642 + dashboard :9119
# via host.docker.internal.
services:
hermes-workspace:
image: hermes-workspace:local
container_name: hermes-workspace
restart: unless-stopped
labels:
- "com.centurylabs.watchtower.enable=false"
env_file:
- stack.env
networks: [edge]
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "172.20.0.1:8088:8088"
networks:
edge:
external: true
```
- [ ] **Step 5: Write `stack.env` (gateway/dashboard targets; LF endings)**
Create `stacks/hermes-workspace/stack.env` using the real env keys from Step 1, e.g.:
```
HERMES_GATEWAY_URL=http://host.docker.internal:8642
HERMES_DASHBOARD_URL=http://host.docker.internal:9119
PORT=8088
```
Verify LF endings before committing.
- [ ] **Step 6: Add an Authentik-gated Caddy block**
Unlike camofox (machine-to-machine), this is a human UI → gate with Authentik forward_auth (Pattern B):
```caddy
workspace.ginnoir.com {
import internal_only
route {
import authentik_outpost
import authentik_forward_auth
reverse_proxy hermes-workspace:8088
}
}
```
- [ ] **Step 7: Deploy and verify**
Run:
```powershell
./scripts/gen-bookmarks.ps1
git add stacks/hermes-workspace/ Caddyfile bookmarks-domains.html bookmarks-ports.html
git commit -m "feat(hermes-workspace): trial command-center stack (eval vs hermes-ui)"
git push
```
Register the stack in Portainer if new, then:
```bash
ssh -o BatchMode=yes ginnoir@valhalla "docker ps --filter name=hermes-workspace --format '{{.Names}} {{.Status}}' && curl -fsS http://172.20.0.1:8088/ | head -5"
```
Expected: container `Up`; the workspace HTML serves; logging into `https://workspace.ginnoir.com`
via Authentik shows live chat/memory/skills wired to your gateway.
- [ ] **Step 8: Checkpoint**
Repo changes committed (Step 7). Leave the keep/tear-down decision to Task 9.
---
## Task 9: Head-to-head UI decision — keep one, tear down the rest
**Files:**
- Modify (on tear-down): `Caddyfile`, `stacks/...` (remove the loser), bookmarks; host unit for the winner.
- [ ] **Step 1: Compare bundled webui vs hermes-ui vs hermes-workspace**
Use all three live for representative work (chat/streaming, tasks/kanban, files, terminal, skills,
MCP browser, cron, memory, health). Score against: does it surface your curated tools cleanly, does
it stay responsive against the P100's latency, and does it add real value over the bundled webui.
Record the verdict in the vault.
- [ ] **Step 2: Make the winner permanent**
- If **hermes-ui** wins: create host unit `hermes-ui.service` (host-managed, like `obsidian.service`
— NOT in this repo), `After=hermes-gateway.service`, `Restart=on-failure`; keep its Caddy block.
- If **hermes-workspace** wins: keep its stack + Authentik block as-is.
- If **bundled webui** wins: keep status quo.
- [ ] **Step 3: Tear down the losers (reversible, clean)**
- Remove the hermes-workspace stack if it lost: delete `stacks/hermes-workspace/`, its Caddy block,
regenerate bookmarks, commit + push, then delete the stack in Portainer and
`docker rm -f hermes-workspace`, `docker image rm hermes-workspace:local`.
- Stop/remove hermes-ui if it lost: `pkill -f 'serve_lite[.]py'` (bracket trick), remove its Caddy
block + clone, commit the Caddyfile change.
- [ ] **Step 4: Checkpoint**
One UI kept and documented in memory + vault; losers fully removed; repo reflects the final state.
---
## 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.
eagle-eye (T6), hermes-ui (T7), hermes-workspace (T8 deploy), with the head-to-head keep-one
decision in T9; 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 decisions (all resolved 2026-06-27) are 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
@@ -21,13 +21,14 @@ also installed), and triaged them into adopt / trial / decide / skip.
| **1** | `hermes-curator-evolver` | **ADOPT (dry-run first)** | Closes Hermes' self-improvement loop; read-only by default; aligns with your curation habit. |
| **2** | `camofox-browser` | **ADOPT (new homelab stack)** | Gives the local agent real web browsing; clean Docker/Caddy fit; independent of Hermes internals. |
| **2** | `eagle-eye` | **TRIAL / DEFER** | Solves the exact tool-overload pain you already hit — but very early (5★, 1 commit) and carries a required Chinese-tokenizer dep. Trial behind a flag; don't depend on it. |
| **3** | `hermes-ui` | **TRIAL (low-cost UI upgrade)** | Single-HTML + stdlib proxy; trivial to stand up next to the bundled webui. |
| **3** | `hermes-workspace` | **DECISION** | The full "command center," but a real React build + a swarm model your single P100 can't actually parallelize. |
| **3** | `mission-control` | **SKIP / DEFER** | Not Hermes-native (built for OpenClaw/CrewAI/LangGraph/AutoGen). Redundant with the two Hermes UIs unless you want a framework-agnostic ops plane. |
| **3** | `hermes-ui` | **ADOPT (trial)** | Single-HTML + stdlib proxy; stood up next to the bundled webui to evaluate. |
| **3** | `hermes-workspace` | **ADOPT (trial)** | Full command center; stood up in parallel to compare head-to-head, then keep one. Swarm Mode won't parallelize on one P100 — value is the workspace/observability features. |
| **3** | `mission-control` | **SKIP** | Not Hermes-native (built for OpenClaw/CrewAI/LangGraph/AutoGen). Redundant with the two Hermes UIs. |
**Decisions I need from you (Section 6):** (1) which UI, if any; (2) whether curator-evolver may
ever run in `--approve` mode or stays report-only; (3) whether to trial eagle-eye at all given its
maturity/dependency profile.
**Decisions — RESOLVED 2026-06-27 (see Section 6):** (1) trial **both** UIs, keep the winner;
(2) curator-evolver stays **report-only** for now; (3) **trial eagle-eye** — it's the only direct
skill-router in the ecosystem, no more-mature equivalent exists; (4) wire camofox as a **minimal
2-tool skill**.
---
@@ -230,17 +231,24 @@ Each phase is independently shippable and independently reversible. Stop after a
---
## 6. OPEN DECISIONS — please answer in the morning
## 6. DECISIONS — RESOLVED 2026-06-27
1. **UI direction.** (a) Stay on bundled webui; (b) trial `hermes-ui` first *(my rec)*; (c) go
straight to `hermes-workspace` as a stack; (d) something else. → gates Phase 3.
2. **Curator autonomy.** Keep `hermes-curator-evolver` **report-only forever**, or allow eventual
`--approve` auto-edits after a trust period? *(My rec: report-only first, revisit.)*
3. **eagle-eye.** Trial it despite 1-commit maturity + the `jieba` dependency, or skip until it
matures? *(My rec: short A/B trial, keep only if measurably better.)*
4. **camofox wiring.** MCP shim vs. a Hermes skill that curls the REST API? *(My rec: minimal
2-tool skill to respect the tool budget.)*
5. **Scope confirmation.** Happy with the Phase 1 → 3 ordering, or want to cut/reorder anything?
1. **UI direction → trial BOTH.** Stand up `hermes-ui` *and* `hermes-workspace` in parallel,
evaluate head-to-head against the bundled webui, then keep the winner and remove the other.
(Phase 3 now builds both.)
2. **Curator autonomy → report-only for now.** `hermes-curator-evolver` runs dry-run/report only;
no `--approve` / `--apply-low-risk` / `--approve-auto-apply`. Revisit after a trust period.
3. **eagle-eye → trial it.** Rationale (ginnoir): wants a large skill library available without
weighting every turn — which is exactly eagle-eye's pre-LLM skill-selection job. **Research
result:** eagle-eye is the *only* direct skill-router in the Hermes ecosystem (per
`awesome-hermes-agent` / Hermes Atlas); the nominal "alternatives" do different jobs —
`llmtrim` (compresses tool schemas + MCP output; **complementary**, worth a later look for the
tool side), `rtk-hermes` (shell-output compression), `hermes-snow-search` (faster session
search), `hermes-motif` (mines traces into micro-skills; a curator-evolver *rival*, not a
router). So eagle-eye stands, with the trial caveat (1-commit maturity, `jieba` dep): keep only
if it measurably improves selection; run L1+L2 only (no P100 embeddings).
4. **camofox wiring → minimal.** A small 2-tool Hermes skill (`browse`, `search`) over the REST
API, not the full surface or an MCP shim — protects the curated tool budget.
The implementation plan that follows this spec details **Phase 1** concretely (it's unambiguous and
safe), with Phase 2/3 sketched pending your answers above.
All four resolved ⇒ **Phases 1, 2, and 3 are all actionable.** The implementation plan that
follows details every phase.