svrnty-hermes-webui-plugin/CLAUDE.md
Svrnty 0b19fdd7d0
Some checks failed
plugin-tests / test (push) Failing after 5s
feat(plugin): Adwright + BTE Command Center panels (v0.4.0)
Two new tool panels surfaced inside hermes-webui via inject_script/
inject_stylesheet. Both vanilla JS + CSS, no frameworks, WebUI CSS-vars
only (no hardcoded colors), light/dark inherits free.

## Adwright panel (static/adwright.{js,css} + routes/adwright.py)

5 tabs: Overview · Cycles · Audience · Targeting · Connections.
Layout: 60/40 panel/chat split via CSS :has() selector.
Always-visible, soft-disabled when active profile isn't `cmo*`.

Action wiring (READ path — agent-mediated per governance):
1. Panel button → fires custom event
2. Handler synthesizes /adwright <cmd> chat message
3. Posts via existing btnSend pathway → message visible in chat
4. CMO sees + calls mcp_adwright_<tool>
5. Panel polls /api/adwright/last-panel-update for structured payload
6. Mock payload returned v1; real session-DB reader plugs in when
   adwright-mcp gains writer

Connections WRITE path (governance exception, NO secrets in chat):
- POST /api/adwright/provision-creds with form fields
- Plugin invokes credctl set <key> via stdin (value never on argv)
- Allowlist enforced (defense-in-depth on key names)
- Auth-gated by WebUI session cookie

Skin: .svrnty-aw-* class prefix, window.SvrntyAdwright JS namespace,
guard against double-load, scoped MutationObserver.

## BTE Command Center panel (static/bte.{js,css} + routes/bte_proxy.py)

Content-mode pills (Polished/UGC/Photorealistic/Artistic) × media toggle
(Image/Video — Video disabled v1 pending Phase 4e) × recipe family picker
(Hero Shot/Lifestyle Shot/Photoshoot/Recipe Sheet/Montage Catalog) per
canonical PLANB-RECIPE-TAXONOMY. SKU picker, variant stepper 1-12,
single/batch toggle, [Generate] button.

Asset grid with streaming thumbnails, asset detail (full-res + rate +
comment + "Use in Adwright cycle" deep link). Embedded CMO chat right rail
for re-orienting generations ("make next batch warmer / less white space").

BTE proxy route (/api/bte/proxy) with whitelisted paths
(requestPhotoshoot, assetGrid, recipeStats, assets/{id}/thumb, etc.)
prevents browser-side CORS to BTE :6001.

Skin: .svrnty-bte-* class prefix, window.SvrntyBTE JS namespace.

## Wiring

manifest_version: 0.2.0 → 0.4.0
assets registered:
- /plugins/svrnty/adwright.{js,css} + static/adwright/
- /plugins/svrnty/bte.{js,css} + static/bte/
routes registered:
- GET /api/adwright/last-panel-update (panel update channel)
- POST /api/adwright/provision-creds (governance-exception write)
- GET/POST /api/bte/proxy (BTE REST proxy with allowlist)

Karpathy 4 rules: agents reported every deviation with rationale (Python
venv interp for hermes mcp add, missing aggregate connections-status RPC
composed from two verifies, mock panel-update v1 with locked frontend
protocol so real session-DB reader is a drop-in swap), verified asset
serving + plugin route registration before claiming complete, surfaced
open questions instead of silently choosing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 12:12:27 -04:00

76 lines
4.3 KiB
Markdown

# svrnty-hermes-webui-plugin
**Classification:** Svrnty plugin for `nesquena/hermes-webui` (per `hermes/docs/SVRNTY-PLUGIN-PROTOCOL.md`)
*Inherits Karpathy 4 rules from `~/.claude/CLAUDE.md` — read them before coding.*
## What this is
THE single repo holding every Svrnty modification to hermes-webui: backend routes, brand skin (CSS/JS/fonts), assets, tests. Loaded at runtime via the plugin loader hook patched into the fork (ONE permanent fork commit).
**Replaces:**
- `hermes-ext/` (deprecated — brand skin migrating in)
- 4 prior fork commits in `hermes-webui/api/` (deprecated — migrated to `routes/`)
## Hard rules
- ONLY interact with hermes-webui via the public extension API: `api.register_route` · `api.register_static` · `api.inject_script` · `api.inject_stylesheet` · `api.config_get` · `api.logger` · `api.register_audio_attachment_processor`
- Any other upstream import → `CONNECTION-MAP.md` under **forced internal dependencies** with written justification + risk
- `CONNECTION-MAP.md` is **AST-generated**, never hand-edited
- Every PR regenerates `CONNECTION-MAP.md` (CI enforces)
- Secrets via credctl / env only — never in repo, never on argv, never in logs
- Plugin code = stateless wrappers; state lives in upstream (or in upstream-managed `state.db`)
## Structure
```
plugin.py # entry: register(api) wires everything
routes/<feature>.py # one file per /api/<feature> endpoint
static/{app.js,app.css,fonts/} # brand skin (subsumes hermes-ext)
CONNECTION-MAP.md # AST-generated dependency map (do NOT hand-edit)
manifest.yaml # plugin metadata + upstream version pin
pyproject.toml # pip-installable
scripts/
ast-connection-map.py # regenerates CONNECTION-MAP.md
upstream-sync.py # fetches upstream tags + runs CI matrix
boot-smoke.py # spin up + curl every plugin endpoint
tests/{unit,integration,evals}/
.github/workflows/
plugin-tests.yml # push: unit + integration
connection-map-check.yml # PR: regen + diff vs committed
upstream-drift.yml # daily cron: detect upstream tags + run matrix
```
## Sources
- Protocol PRD: `../docs/SVRNTY-PLUGIN-PROTOCOL.md` (the contract — 7 loader API methods, §10 validator assertions)
- Upstream fork: `../hermes-webui/` (holds ONLY the loader patch + pristine upstream)
- Deprecated: `../hermes-ext/` (migrating into `static/`)
## Gotchas
- Adding a route: drop file in `routes/`, register in `plugin.py` via `api.register_route`. Do NOT touch hermes-webui's `api/routes.py`
- After ANY structural change: `python3 scripts/ast-connection-map.py` then commit the regen. CI fails PR otherwise
- New loader API methods require: protocol PRD bump + `protocol-validate.sh` assertion + fork loader patch update
- Adding upstream imports: justify in `CONNECTION-MAP.md` BEFORE the import lands — the AST gen will flag it, but reviewer should see the rationale committed alongside
## Site map — where to find anything in cortex-os
Read these in order to ground any session:
| What | Where |
|---|---|
| **Karpathy 4 rules** | `~/.claude/CLAUDE.md` (auto-inherited every session) |
| **Workspace contract + repo map** | `~/workspaces/hermes/CLAUDE.md` |
| **SOT library orientation** | `~/workspaces/hermes/sot/README.md` |
| **Curator-generated SOT index** | `~/workspaces/hermes/sot/INDEX.md` |
| **Profile catalog (5 profiles + tool disclosure + governance)** | `~/workspaces/hermes/sot/06-REGISTRY/PROFILE-CATALOG.md` |
| **Profile distribution protocol (T1)** | `~/workspaces/hermes/sot/03-PROTOCOLS/PROFILE-DISTRIBUTION-PROTOCOL.md` |
| **Frontmatter spec (T1)** | `~/workspaces/hermes/sot/04-STANDARDS/FRONTMATTER-SPEC.md` |
| **SOT enforcement (pre-commit + curator + pre-push)** | `~/workspaces/hermes/sot/04-STANDARDS/SOT-ENFORCEMENT.md` |
| **Living graph artifact** | `~/workspaces/hermes/graph/umbrella.json` (curator-maintained) |
| **Living graph UI panel (planned)** | `/umbrella` route in hermes-webui per `sot/03-PROTOCOLS/CORTEX-OS-UMBRELLA-VIZ-PRD.md` |
| **This repo's CONTRACT.md** | `./CONTRACT.md` if present (T1 — wins over everything in this repo) |
If you're new to a session: read the workspace contract first, then this file, then the SOT orientation. Don't guess about cortex-os structure — anchor to these.