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:
co-authored by
Claude Opus 4.8
parent
98c4a2a02b
commit
3cd843072d
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user