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. - **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). - 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 (RESOLVED 2026-06-27 — all phases actionable):** trial **both** UIs and keep the winner
decisions** (UI choice; curator autonomy; eagle-eye trial; camofox wiring). Do not start a gated (Phase 3); curator stays **report-only** (Task 3); **trial eagle-eye** — it's the only direct
task group until ginnoir has answered. 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) ## 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) ## 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:** **Files:**
- Host: `~/.hermes/plugins/eagle-eye/` (or skills dir per its README), config toggle in `~/.hermes/config.yaml`. - 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`** > Decision resolved (spec §6.1): trial `hermes-ui` (Task 7) **and** `hermes-workspace` (Task 8) in
> (Task 7). `hermes-workspace` (Task 8) is the heavier alternative; `mission-control` is skipped. > 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) ## 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). 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. 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.
- [ ] **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 ## 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 **Files:**
> checkpoint**, not a build, because it carries a real caveat to resolve first. - 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 Run:
single P100 (`--parallel 1`, one model at a time) — swarm workers serialize on the GPU or must ```bash
target a different backend. Decide with ginnoir whether the non-swarm features (workspace, ops 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"
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 Expected: README + a `Dockerfile`/compose appear. Record the exact image build command, the served
own full plan (separate spec/plan cycle). If no, stop — `hermes-ui` (Task 7) is the chosen UI. 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) ## Self-Review (completed)
- **Spec coverage:** All 7 repos map to tasks — acp-skill (T2), curator-evolver (T3), camofox (T5), - **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 eagle-eye (T6), hermes-ui (T7), hermes-workspace (T8 deploy), with the head-to-head keep-one
per spec §2.5/§5, no task — intentional). Phase ordering, single-P100 discipline, host-vs-repo decision in T9; mission-control (explicitly skipped per spec §2.5/§5, no task — intentional).
boundary, provenance/reversibility, and the §6 decision gates are all reflected. 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 - **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 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 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. | | **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** | `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. | | **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-ui` | **ADOPT (trial)** | Single-HTML + stdlib proxy; stood up next to the bundled webui to evaluate. |
| **3** | `hermes-workspace` | **DECISION** | The full "command center," but a real React build + a swarm model your single P100 can't actually parallelize. | | **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 / 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** | `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 **Decisions — RESOLVED 2026-06-27 (see Section 6):** (1) trial **both** UIs, keep the winner;
ever run in `--approve` mode or stays report-only; (3) whether to trial eagle-eye at all given its (2) curator-evolver stays **report-only** for now; (3) **trial eagle-eye** — it's the only direct
maturity/dependency profile. 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 1. **UI direction → trial BOTH.** Stand up `hermes-ui` *and* `hermes-workspace` in parallel,
straight to `hermes-workspace` as a stack; (d) something else. → gates Phase 3. evaluate head-to-head against the bundled webui, then keep the winner and remove the other.
2. **Curator autonomy.** Keep `hermes-curator-evolver` **report-only forever**, or allow eventual (Phase 3 now builds both.)
`--approve` auto-edits after a trust period? *(My rec: report-only first, revisit.)* 2. **Curator autonomy → report-only for now.** `hermes-curator-evolver` runs dry-run/report only;
3. **eagle-eye.** Trial it despite 1-commit maturity + the `jieba` dependency, or skip until it no `--approve` / `--apply-low-risk` / `--approve-auto-apply`. Revisit after a trust period.
matures? *(My rec: short A/B trial, keep only if measurably better.)* 3. **eagle-eye → trial it.** Rationale (ginnoir): wants a large skill library available without
4. **camofox wiring.** MCP shim vs. a Hermes skill that curls the REST API? *(My rec: minimal weighting every turn — which is exactly eagle-eye's pre-LLM skill-selection job. **Research
2-tool skill to respect the tool budget.)* result:** eagle-eye is the *only* direct skill-router in the Hermes ecosystem (per
5. **Scope confirmation.** Happy with the Phase 1 → 3 ordering, or want to cut/reorder anything? `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 All four resolved ⇒ **Phases 1, 2, and 3 are all actionable.** The implementation plan that
safe), with Phase 2/3 sketched pending your answers above. follows details every phase.