docs: comprehensive markdown update for v0.24

README.md:
- Features section rewritten: added voice input, profiles, auth/security,
  slash commands, mobile responsive, thinking display, session projects,
  workspace tree, code copy, safe HTML rendering sections
- Architecture tree updated with all current files and line counts
- Env var table: added HERMES_WEBUI_PASSWORD
- Test section: updated count (415 tests), corrected pytest command
- Docs section: added SPRINTS.md reference

ARCHITECTURE.md:
- File inventory: added profiles.py, Dockerfile, docker-compose.yml,
  .dockerignore; updated all line counts to current values
- Env vars: added HERMES_HOME to both server-level and per-request sections
- Test files: 21 files, 415 functions (was 17 files, 327)

ROADMAP.md:
- Header: v0.21 -> v0.24, 328 -> 415 tests
- Sprint history table: added Sprints 20-22
- Architecture table: updated line counts and added Docker row
- Feature checklist: marked voice, mobile, profiles as done; reorganized

TESTING.md:
- Header: Sprint 19/v0.21 -> Sprint 22/v0.24, updated test counts
- Footer: same updates
- Added manual test sections for Sprints 20 (voice + send button),
  21 (mobile + Docker), 22 (multi-profile)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nathan Esquenazi
2026-04-03 11:20:43 -07:00
parent f21b088a14
commit 28ac04da7d
4 changed files with 174 additions and 61 deletions

View File

@@ -26,32 +26,36 @@ This makes the code easy to modify from a terminal or by an agent.
## 2. File Inventory
<repo>/
server.py Thin routing shell + HTTP Handler + auth middleware. ~79 lines.
server.py Thin routing shell + HTTP Handler + auth middleware. ~81 lines.
Delegates all route handling to api/routes.py.
start.sh Discovery script: finds agent dir, Python, starts server.
Dockerfile python:3.12-slim container image (~23 lines)
docker-compose.yml Compose config with named volume and optional auth (~22 lines)
.dockerignore Excludes .git, tests/, .env* from Docker builds
api/
__init__.py Package marker
auth.py Optional password authentication, signed cookies (~149 lines)
routes.py All GET + POST route handlers (~1109 lines)
config.py Shared configuration, constants, global state, model discovery (~654 lines)
config.py Discovery, globals, model detection, reloadable config (~701 lines)
helpers.py HTTP helpers: j(), bad(), require(), safe_resolve(), security headers (~71 lines)
models.py Session model + CRUD (~132 lines)
models.py Session model + CRUD, per-session profile tracking (~137 lines)
profiles.py Profile state management, hermes_cli wrapper (~246 lines)
routes.py All GET + POST route handlers (~1180 lines)
streaming.py SSE engine, run_agent, cancel, HERMES_HOME save/restore (~236 lines)
upload.py Multipart parser, file upload handler (~78 lines)
workspace.py File ops: list_dir, read_file_content, workspace helpers (~77 lines)
upload.py Multipart parser, file upload handler (~77 lines)
streaming.py SSE engine, run_agent integration, cancel support (~222 lines)
static/
index.html HTML template (served from disk)
style.css All CSS (~590 lines)
ui.js DOM helpers, renderMd, tool cards, model dropdown, file tree (~957 lines)
index.html HTML template (~364 lines)
style.css All CSS incl. mobile responsive (~670 lines)
ui.js DOM helpers, renderMd, tool cards, model dropdown, file tree (~977 lines)
workspace.js File preview, file ops, loadDir, clearPreview (~185 lines)
sessions.js Session CRUD, list rendering, search, SVG icons, overlay actions (~532 lines)
sessions.js Session CRUD, list rendering, search, SVG icons, overlay actions (~533 lines)
messages.js send(), SSE event handlers, approval, transcript (~297 lines)
panels.js Cron, skills, memory, workspace, todo, switchPanel, settings (~813 lines)
panels.js Cron, skills, memory, workspace, profiles, todo, settings (~974 lines)
commands.js Slash command registry, parser, autocomplete dropdown (~156 lines)
boot.js Event wiring, keydown handlers, boot IIFE (~208 lines)
boot.js Event wiring, mobile nav, voice input, boot IIFE (~338 lines)
tests/
conftest.py Isolated test server (port 8788, separate HERMES_HOME) (~240 lines)
test_sprint{1-19}.py Feature tests per sprint (17 files, 327 test functions)
test_sprint{1-20b}.py Feature tests per sprint (21 files, 415 test functions)
test_regressions.py Permanent regression gate (23 tests)
AGENTS.md Instruction file for agents working in this directory.
ROADMAP.md Feature and product roadmap document.
@@ -95,6 +99,7 @@ Environment variables controlling behavior:
HERMES_CONFIG_PATH Path to ~/.hermes/config.yaml
HERMES_WEBUI_DEFAULT_MODEL Default LLM model string
HERMES_WEBUI_PASSWORD Optional: enable password auth (off by default)
HERMES_HOME Base directory for Hermes state (~/.hermes by default)
Test isolation environment variables (set by conftest.py):
@@ -113,6 +118,8 @@ Per-request environment variables (set by chat handler, restored after):
HERMES_EXEC_ASK Set to "1" to enable approval gate for dangerous commands.
HERMES_SESSION_KEY Set to session_id. The approval tool keys pending entries
by this value, enabling per-session approval state.
HERMES_HOME Set to the active profile's directory before running agent.
Saved and restored around each agent run.
WARNING: These env vars are process-global. Two concurrent chat requests will clobber
each other. This is safe only for single-user, single-concurrent-request use.

121
README.md
View File

@@ -106,7 +106,8 @@ Full list of environment variables:
| `HERMES_WEBUI_STATE_DIR` | `~/.hermes/webui-mvp` | Where sessions and state are stored |
| `HERMES_WEBUI_DEFAULT_WORKSPACE` | `~/workspace` | Default workspace |
| `HERMES_WEBUI_DEFAULT_MODEL` | `openai/gpt-5.4-mini` | Default model |
| `HERMES_HOME` | `~/.hermes` | Base directory for Hermes state (affects all paths above) |
| `HERMES_WEBUI_PASSWORD` | *(unset)* | Set to enable password authentication |
| `HERMES_HOME` | `~/.hermes` | Base directory for Hermes state (affects all paths) |
| `HERMES_CONFIG_PATH` | `~/.hermes/config.yaml` | Path to Hermes config file |
---
@@ -158,17 +159,18 @@ Tests discover the repo and the Hermes agent dynamically -- no hardcoded paths.
```bash
cd hermes-webui
python -m pytest tests/ -v
pytest tests/ -v --timeout=60
```
Or using the agent venv explicitly:
```bash
/path/to/hermes-agent/venv/bin/python -m pytest tests/ -v # or any Python with deps installed
/path/to/hermes-agent/venv/bin/python -m pytest tests/ -v
```
Tests run against an isolated server on port 8788 with a separate state directory.
Production data and real cron jobs are never touched.
Production data and real cron jobs are never touched. Current count: **415 tests**
across 21 test files.
---
@@ -176,22 +178,27 @@ Production data and real cron jobs are never touched.
### Chat and agent
- Streaming responses via SSE (tokens appear as they are generated)
- Multi-provider model support -- any Hermes API provider (OpenAI, Anthropic, Google, DeepSeek, Nous Portal, OpenRouter); dynamic model dropdown populated from configured keys
- Multi-provider model support -- any Hermes API provider (OpenAI, Anthropic, Google, DeepSeek, Nous Portal, OpenRouter, MiniMax, Z.AI); dynamic model dropdown populated from configured keys
- Send a message while one is processing -- it queues automatically
- Edit any past user message inline and regenerate from that point
- Retry the last assistant response with one click
- Cancel a running task from the activity bar
- Tool call cards inline -- each shows the tool name, args, and result snippet
- Tool call cards inline -- each shows the tool name, args, and result snippet; expand/collapse all toggle for multi-tool turns
- Mermaid diagram rendering inline (flowcharts, sequence diagrams, gantt charts)
- Thinking/reasoning display -- collapsible gold-themed cards for Claude extended thinking and o3 reasoning blocks
- Approval card for dangerous shell commands (allow once / session / always / deny)
- SSE auto-reconnect on network blips (SSH tunnel resilience)
- File attachments persist across page reloads
- Message timestamps (HH:MM next to each message, full date on hover)
- Code block copy button with "Copied!" feedback
- Syntax highlighting via Prism.js (Python, JS, bash, JSON, SQL, and more)
- Safe HTML rendering in AI responses (bold, italic, code converted to markdown)
### Sessions
- Create, rename, duplicate, delete, search by title and message content
- Pin/star sessions to the top of the sidebar
- Pin/star sessions to the top of the sidebar (gold indicator)
- Archive sessions (hide without deleting, toggle to show)
- Session projects -- named groups with colors for organizing sessions
- Session tags -- add #tag to titles for colored chips and click-to-filter
- Grouped by Today / Yesterday / Earlier in the sidebar
- Download as Markdown transcript, full JSON export, or import from JSON
@@ -199,56 +206,105 @@ Production data and real cron jobs are never touched.
- Browser tab title reflects the active session name
### Workspace file browser
- Browse directory tree with type icons
- Directory tree with expand/collapse (single-click toggles, double-click navigates)
- Breadcrumb navigation with clickable path segments
- Preview text, code, Markdown (rendered), and images inline
- Edit, create, delete, and rename files; create folders
- Binary file download (auto-detected from server)
- File preview auto-closes on directory navigation (with unsaved-edit guard)
- Right panel is drag-resizable
- Syntax highlighted code preview (Prism.js)
### Voice input
- Microphone button in the composer (Web Speech API)
- Tap to record, tap again or send to stop
- Live interim transcription appears in the textarea
- Auto-stops after ~2s of silence
- Appends to existing textarea content (doesn't replace)
- Hidden when browser doesn't support Web Speech API (Chrome, Edge, Safari)
### Profiles
- Profile picker in the topbar -- purple chip with dropdown showing all profiles
- Gateway status dots (green = running), model info, skill count per profile
- Profiles management panel -- create, switch, and delete profiles from the sidebar
- Clone config from active profile on create
- Seamless switching -- no server restart; reloads config, skills, memory, cron, models
- Per-session profile tracking (records which profile was active at creation)
### Authentication and security
- Optional password auth -- off by default, zero friction for localhost
- Enable via `HERMES_WEBUI_PASSWORD` env var or Settings panel
- Signed HMAC HTTP-only cookie with 24h TTL
- Minimal dark-themed login page at `/login`
- Security headers on all responses (X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
- 20MB POST body size limit
- CDN resources pinned with SRI integrity hashes
### Settings and configuration
- Settings panel (gear icon in topbar) -- persist default model and default workspace server-side
- Settings panel (gear icon) -- default model, default workspace, send key preference
- Send key: Enter (default) or Ctrl/Cmd+Enter
- Cron completion alerts -- toast notifications and unread badge on Tasks tab
- Background agent error alerts -- banner when a non-active session encounters an error
### Slash commands
- Type `/` in the composer for autocomplete dropdown
- Built-in: `/help`, `/clear`, `/model <name>`, `/workspace <name>`, `/new`
- Arrow keys navigate, Tab/Enter select, Escape closes
- Unrecognized commands pass through to the agent
### Panels
- **Chat** -- session list, search, pin, archive, new conversation
- **Tasks** -- view, create, edit, run, pause/resume, delete cron jobs; completion alerts
- **Chat** -- session list, search, pin, archive, projects, new conversation
- **Tasks** -- view, create, edit, run, pause/resume, delete cron jobs; run history; completion alerts
- **Skills** -- list all skills by category, search, preview, create/edit/delete
- **Memory** -- view and edit MEMORY.md and USER.md inline
- **Profiles** -- create, switch, delete agent profiles; clone config
- **Todos** -- live task list from the current session
- **Spaces** -- add, rename, remove workspaces; quick-switch from topbar
### Mobile responsive
- Hamburger sidebar -- slide-in overlay on mobile (<640px)
- Bottom navigation bar -- 5-tab iOS-style fixed bar
- Files slide-over panel from right edge
- Touch targets minimum 44px on all interactive elements
- Composer positioned above bottom nav
- Desktop layout completely unchanged
---
## Architecture
```
server.py HTTP routing shell (~76 lines)
server.py HTTP routing shell + auth middleware (~81 lines)
api/
routes.py All GET + POST route handlers
config.py Discovery + globals + model provider detection
helpers.py HTTP helpers: j(), bad(), require(), safe_resolve()
models.py Session model + CRUD
workspace.py File ops: list_dir, read_file_content, workspace helpers
upload.py Multipart parser, file upload handler
streaming.py SSE engine, run_agent integration, cancel support
auth.py Optional password authentication, signed cookies (~149 lines)
config.py Discovery, globals, model detection, reloadable config (~701 lines)
helpers.py HTTP helpers, security headers (~71 lines)
models.py Session model + CRUD (~137 lines)
profiles.py Profile state management, hermes_cli wrapper (~246 lines)
routes.py All GET + POST route handlers (~1180 lines)
streaming.py SSE engine, run_agent, cancel support (~236 lines)
upload.py Multipart parser, file upload handler (~78 lines)
workspace.py File ops, workspace helpers (~77 lines)
static/
index.html HTML template
style.css All CSS
ui.js DOM helpers, renderMd, Mermaid, tool cards, file tree
workspace.js File tree, preview, file ops
sessions.js Session CRUD, list rendering, search, tags, archive
messages.js send(), SSE event handlers, approval, transcript
panels.js Cron, skills, memory, workspace, todo, switchPanel, alerts
boot.js Event wiring + boot IIFE
index.html HTML template (~364 lines)
style.css All CSS incl. mobile responsive (~670 lines)
ui.js DOM helpers, renderMd, tool cards, file tree (~977 lines)
workspace.js File preview, file ops (~185 lines)
sessions.js Session CRUD, list rendering, search (~533 lines)
messages.js send(), SSE handlers, approval, transcript (~297 lines)
panels.js Cron, skills, memory, profiles, settings (~974 lines)
commands.js Slash command autocomplete (~156 lines)
boot.js Mobile nav, voice input, boot IIFE (~338 lines)
tests/
conftest.py Isolated test server (port 8788, separate HERMES_HOME)
test_sprint1-14.py Feature tests per sprint
test_regressions.py Permanent regression gate
conftest.py Isolated test server (port 8788)
test_sprint{1-20b}.py 21 test files, 415 test functions
test_regressions.py Permanent regression gate (23 tests)
Dockerfile python:3.12-slim container image
docker-compose.yml Compose with named volume and optional auth
```
State lives outside the repo at `~/.hermes/webui-mvp/` by default
(sessions, workspaces, settings, last_workspace). Override with `HERMES_WEBUI_STATE_DIR`.
(sessions, workspaces, settings, projects, last_workspace). Override with `HERMES_WEBUI_STATE_DIR`.
---
@@ -257,7 +313,8 @@ State lives outside the repo at `~/.hermes/webui-mvp/` by default
- `ROADMAP.md` -- feature roadmap and sprint history
- `ARCHITECTURE.md` -- system design, all API endpoints, implementation notes
- `TESTING.md` -- manual browser test plan and automated coverage reference
- `CHANGELOG.md` -- release notes
- `CHANGELOG.md` -- release notes per sprint
- `SPRINTS.md` -- forward sprint plan with CLI + Claude parity targets
## Repo

View File

@@ -3,8 +3,8 @@
> Goal: Full 1:1 parity with the Hermes CLI experience via a clean dark web UI.
> Everything you can do from the CLI terminal, you can do from this UI.
>
> Last updated: Sprint 19 / v0.21 (April 3, 2026)
> Tests: 328 total (328 passing, 0 failures)
> Last updated: Sprint 22 / v0.24 (April 3, 2026)
> Tests: 415 total (392 passing, 23 pre-existing failures)
> Source: <repo>/
---
@@ -36,6 +36,9 @@
| Sprint 17 | Workspace polish + slash commands + settings | Breadcrumb navigation, slash command autocomplete, send key setting (#26) | 318 |
| Sprint 18 | Thinking display + workspace tree | File preview auto-close, thinking/reasoning cards, expandable directory tree (#22) | 318 |
| Sprint 19 | Auth + security hardening | Password auth (off by default), login page, security headers, 20MB body limit (#23) | 328 |
| Sprint 20 | Voice input + send button | Voice input (Web Speech API), send button icon-circle with pop-in animation | 415 |
| Sprint 21 | Mobile responsive + Docker | Hamburger sidebar, bottom nav, files slide-over, Docker support (#21, #7) | 415 |
| Sprint 22 | Multi-profile support | Profile picker, management panel, seamless switching, per-session tracking (#28) | 415 |
---
@@ -43,10 +46,11 @@
| Layer | Location | Status |
|-------|----------|--------|
| Python server | <repo>/server.py (~79 lines) + api/ modules (~2491 lines) | Thin shell + auth middleware + business logic in api/ |
| HTML template | <repo>/static/index.html | Served from disk |
| CSS | <repo>/static/style.css (~590 lines) | Served from disk |
| JavaScript | <repo>/static/{ui,workspace,sessions,messages,panels,boot,commands}.js | 7 modules, ~3148 lines total |
| Python server | <repo>/server.py (~81 lines) + api/ modules (~2876 lines) | Thin shell + auth middleware + business logic in api/ |
| HTML template | <repo>/static/index.html (~364 lines) | Served from disk |
| CSS | <repo>/static/style.css (~670 lines) | Served from disk, incl. mobile responsive |
| JavaScript | <repo>/static/{ui,workspace,sessions,messages,panels,boot,commands}.js | 7 modules, ~3460 lines total |
| Docker | Dockerfile, docker-compose.yml, .dockerignore | python:3.12-slim, named volume |
| Runtime state | ~/.hermes/webui-mvp/sessions/ | Session JSON files |
| Test server | Port 8788, state dir ~/.hermes/webui-mvp-test/ | Isolated, wiped per run |
| Production server | Port 8787 | SSH tunnel from Mac |
@@ -176,16 +180,22 @@
### Thinking / Reasoning
- [x] Collapsible thinking cards for extended-thinking models (Sprint 18)
### Voice
- [x] Voice input via Web Speech API (Sprint 20)
### Mobile
- [x] Mobile responsive layout — hamburger sidebar, bottom nav, files slide-over (Sprint 21)
### Profiles
- [x] Multi-profile support — create, switch, delete profiles (Sprint 22, Issue #28)
### Advanced / Future
- [ ] Voice input via Whisper (Sprint 20)
- [ ] TTS playback of responses (Sprint 20)
- [ ] TTS playback of responses (deferred)
- [ ] Subagent delegation cards (deferred)
- [x] Background task cancel (activity bar Cancel button)
- [ ] Code execution cell (deferred)
- [ ] Mobile responsive layout (Sprint 21)
- [ ] Multi-profile support (Sprint 22, Issue #28)
- [ ] Desktop application (Sprint 23)
- [ ] Extended slash command / skill integration (Sprint 24)
- [ ] Desktop application (deferred)
- [ ] Extended slash command / skill integration (deferred)
- [ ] Virtual scroll for large lists (deferred)
---

View File

@@ -1,14 +1,14 @@
# Hermes Web UI: Browser Testing Plan
> This document is for manual browser testing by you or by a Claude browser agent.
> It covers user-facing features of the UI through Sprint 19 (v0.21).
> It covers user-facing features of the UI through Sprint 22 (v0.24).
> Each section is written as a step-by-step test procedure with expected outcomes.
> A browser agent (e.g. Claude with Chrome access) can execute this plan directly.
>
> Prerequisites: SSH tunnel is active on port 8787. Open http://localhost:8787 in browser.
> Server health check: curl http://127.0.0.1:8787/health should return {"status":"ok"}.
>
> Automated tests: 328 total (328 passing, 0 failures).
> Automated tests: 415 total (392 passing, 23 pre-existing failures).
> Run: `pytest tests/ -v --timeout=60`
---
@@ -1667,10 +1667,49 @@ Each has automated API-level tests in `tests/test_sprint{N}.py`.
- API calls without auth cookie → 401 JSON response.
- Check response headers: `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`.
### Sprint 20: Voice Input + Send Button
- Mic button visible in composer (Chrome/Edge). Hidden in Firefox.
- Tap mic → button turns red with pulse, "Listening..." indicator appears.
- Speak → live transcription appears in textarea.
- Stop speaking → auto-stops after ~2s silence. Text stays editable.
- Tap mic again or Send → stops recording, sends text.
- Type text, then tap mic → spoken text appends to existing text (doesn't replace).
- Send button hidden when textarea is empty. Appears with pop-in animation when typing.
- Send button is icon-only circle (no "Send" text label). Blue with glow.
- Attach a file with no text → send button appears.
- Send message → button disappears after textarea clears.
- While agent is responding → send button hidden.
### Sprint 21: Mobile Responsive + Docker
- Open on mobile viewport (<640px): hamburger icon visible in topbar.
- Tap hamburger → sidebar slides in from left with backdrop overlay.
- Tap outside sidebar → closes. Tap a session → closes and loads session.
- Bottom navigation bar: 5 tabs (Chat, Tasks, Skills, Memory, Spaces).
- Tap "Tasks" in bottom nav → sidebar opens showing Tasks panel.
- Tap "Chat" in bottom nav → sidebar closes (chat is in main area).
- Files button in topbar → right panel slides in from right.
- All touch targets are at least 44px (session items, buttons, icons).
- Desktop viewport (>640px): no hamburger, no bottom nav, no mobile elements.
- Docker: `docker compose up -d` starts server on port 8787.
- Docker: session data persists across container restarts (named volume).
### Sprint 22: Multi-Profile Support
- Profile chip in topbar (purple accent). Click → dropdown with all profiles.
- Dropdown shows gateway status dots, model info, skill count per profile.
- Click a profile → switches; model dropdown, skills, memory, cron refresh.
- "Manage profiles" link opens Profiles sidebar panel.
- Profiles panel: cards with name, model, provider, skill count, API key status.
- "Use" button switches profile. Delete button removes non-default profiles.
- "+ New profile" form: name validation (lowercase + hyphens), clone config checkbox.
- Create profile → appears in list and dropdown.
- Delete profile → confirm dialog. Auto-switches to default if deleting active.
- Attempt switch while agent busy → blocked with toast message.
- With hermes-agent not installed → only default profile shown, graceful fallback.
---
*Last updated: Sprint 19 / v0.21, April 3, 2026*
*Total automated tests: 328 (328 passing, 0 failures)*
*Last updated: Sprint 22 / v0.24, April 3, 2026*
*Total automated tests: 415 (392 passing, 23 pre-existing failures)*
*Regression gate: tests/test_regressions.py (23 tests)*
*Run: pytest tests/ -v --timeout=60*
*Source: <repo>/*