diff --git a/ROADMAP.md b/ROADMAP.md index 663c270c..e6037424 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,363 +1,349 @@ -# Hermes Web UI: Full Parity Roadmap +# Hermes Web UI — Roadmap -> 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. +> Web companion to the Hermes Agent CLI. Same workflows, browser-native. > -> Last updated: v0.50.281 (May 03, 2026) — 3990 tests collected -> Tests: `pytest tests/ --collect-only -q` -> Source: / +> Last updated: v0.50.281 (May 03, 2026) — 3995 tests collected +> Test source: `pytest tests/ --collect-only -q` +> Per-version detail: see [CHANGELOG.md](./CHANGELOG.md) --- -## Sprint History (Completed) +## Status snapshot -| Sprint | Theme | Highlights | Tests | -|--------|-------|-----------|-------| -| Sprint 1 | Bug fixes + foundations | B1-B11 fixed, LOCK on SESSIONS, section headers, request logging | 19 | -| Sprint 2 | Rich file preview | Image preview, rendered markdown, table support, smart icons | 27 | -| Sprint 3 | Panel nav + viewers | Sidebar tabs, cron/skills/memory panels, B6/B10/B14, Phase D start | 48 | -| Sprint 4 | Relocation + power features | Source to /, CSS extracted, session rename/search, file ops | 68 | -| Sprint 5 | Phase A complete + workspace | JS extracted (server.py 1778->1042 lines), workspace management, copy message, file editor, session index | 86 | -| Test hardening | Isolated test environment | Port 8788 test server, conftest autouse, cleanup_zero_message, 5 test files rewritten | 90 | -| Sprint 6 | Polish + Phase E complete | HTML to static/, resizable panels, cron create, session JSON export, Escape from editor | 106 | -| Sprint 7 | Wave 2 Core: CRUD + Search | Cron edit/delete, skill create/edit/delete, memory write, session content search, health improvements, git init | 125 | -| Sprint 8 | Daily Driver Finish Line | Edit+regenerate user messages, regenerate last response, clear conversation, Prism.js syntax highlighting, reconnect banner fix, session list scroll fix | 139 | -| Sprint 8 hotfix | Message queue + INFLIGHT fix | Queue messages while busy (toast + badge + auto-drain), INFLIGHT-first loadSession (message stays on switch-away/back) | 139 | -| Sprint 9 | Codebase health + daily driver gaps | app.js deleted and replaced by 6 modules, tool call cards inline, attachment persistence on reload, todo list panel | 149 | -| Sprint 10 | Server health + operational polish | server.py split into api/ modules, background task cancel, cron run history viewer, tool card UX polish | 167 | -| Sprint 10 fixes | Import regressions + regression tests | uuid, AIAgent, has_pending, SSE cancel loop, Session.__init__ tool_calls; test_regressions.py | 177 | -| Concurrency sweeps | Multi-session correctness | Approval cross-session (R10), activity bar per-session (R11), live cards on switch-back (R12), tool cards after done (R13), session model authoritative (R14), newSession cards (R15) | 190 | -| Sprint 11 | Multi-provider models + streaming | Dynamic model dropdown (any Hermes provider), smooth scroll pinning, routes extracted to api/routes.py (server.py 704→76 lines) | 201 | -| Sprint 12 | Settings + reliability + session QoL | Settings panel (gear icon, settings.json), SSE auto-reconnect, pin sessions, import session from JSON | 211 | -| Sprint 13 | Alerts + polish | Cron completion alerts (polling + badge), background error banner, session duplicate, browser tab title | 221 | -| Sprint 14 | Visual polish + workspace ops | Mermaid diagrams, message timestamps, file rename, folder create, session tags, session archive | 233 | -| Sprint 15 | Session projects + code copy | Session projects/folders, code block copy button, tool card expand/collapse toggle | 237 | -| Sprint 16 | Session sidebar visual polish | SVG action icons, session action dropdown, pin indicator, project border, safe HTML rendering | 289 | -| 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, mobile 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 | -| Sprint 23 | Agentic transparency | Token/cost display, subagent cards, skill picker in cron, skill linked files, workspace tree persistence, timestamp fixes | 424 | -| v0.44.0 patch | Fix batch: approval card, login CSP, update diagnostics, Lucide icons | PRs #221 #225 #226 #227 #228 | 579 | -| v0.45.0 | Custom endpoint in new profile form | Base URL + API key fields; server-side URL validation; config.yaml merge; 9 new tests (PR #233, fixes #170) | 604 | -| v0.46.0 | Security, Docker UID/GID, model discovery, i18n, cancel fix | Credential redaction in API responses (PR #243); Docker UID/GID matching (PR #237); custom model API key discovery (PR #238); HTML entity decode + zh/zh-Hant i18n (PR #239); cancel interrupts agent (PR #244); +20 tests | 624 | -| v0.47.0 | Dialogs, session menu, skills command, mobile fixes, mobile QA | Shared app dialogs (#251); session ⋯ menu (#252); mobile QA suite (#254); custom provider slash routing fix (#255); Android Chrome mobile fixes (#256); /skills command (#257); +21 tests | 645 | -| v0.47.1 | Spanish locale | Full Spanish (es) locale, 175 keys, key-parity tests (#275 @gabogabucho); +3 tests | 648 | -| v0.48.0 | Gateway session sync | Real-time Telegram/Discord/Slack sessions in sidebar via SSE + DB polling (#274 @bergeouss); +10 tests | 658 | -| v0.48.1 | Table inline formatting | `inlineMd()` in table cells — **bold**, *italic*, `code`, links render correctly (PR #278); 0 new tests | 658 | -| v0.48.2 | Provider mismatch warning | Toast warning + auth_mismatch error type for provider/model mismatches (#283, fixes #266); +21 tests | 679 | -| v0.49.1 | Docker docs + mobile Profiles button | Two-container Docker compose (#291/#288); Profiles added to the mobile navigation flow with correct panel wiring and SVG sizing (#297/#265 @gabogabucho); +3 tests | 700 | -| v0.49.0 | First-run onboarding wizard + self-update hardening | One-shot bootstrap + guided setup wizard; provider config persisted to config.yaml + .env; OpenRouter/Anthropic/OpenAI/Custom; wizard hidden after completion (#285); self-update stderr/split-ref/conflict fixes (#287); skip flaky redaction test (#289); +18 tests | 697 | -| v0.32 | Auto-compaction handling | Compression detection, /compact command, real context window indicator | 424 | -| v0.33 | /insights sync | Opt-in state.db sync so `hermes /insights` includes WebUI sessions | 424 | -| v0.34 | Sprint 26 — Pluggable themes | Dark, Light, Slate, Solarized, Monokai, Nord; settings unsaved-changes guard; /theme command | 433 | -| v0.34.1 | Theme variable polish | 30+ hardcoded dark-navy colors replaced with theme-aware CSS variables | 433 | -| v0.34.2 | Theme text colors | 5 new per-theme typography variables (--strong, --em, --code-text, --code-inline-bg, --pre-text) | 433 | -| v0.34.3 | Light theme final polish | 46 light-scoped selector overrides for sidebar, roles, chips, interactive elements | 433 | -| v0.35 | Security hardening | Env race fix, random signing key, upload path traversal, PBKDF2 password hash | 433 | -| v0.36–v0.37 | Model routing, personality config, tool card reload, duplicate model fixes | Model routing by provider prefix, personality via config.yaml, tool cards reload on page refresh | 466 | -| v0.38.0–v0.38.6 | Model selector, custom endpoints, OLED theme, reasoning display, insights sync | Custom endpoint URL fix, OLED theme, top-level reasoning field fix, message_count sync to state.db | 466 | -| v0.39.0 | Security hardening (Sprint 29) | CSRF, PBKDF2, rate limiting, session ID validation, SSRF, ENV_LOCK, XSS, HMAC, skills traversal, secure cookie, error sanitization, startup warning | 499 | -| v0.40–v0.44.2 | Approval card + Lucide icons + sprint auth | Approval prompt surfaced in UI, emoji icons → Lucide SVG, login CSP inline fix, update diagnostics | 579 | -| v0.45–v0.46 | Custom endpoints + security + i18n + cancel | Custom endpoint Base URL + API key on profile create, credential redaction (PR #243), Docker UID/GID (PR #237), HTML entity decode + zh/zh-Hant i18n, cancel interrupts agent | 624 | -| v0.47–v0.47.1 | Dialogs + session menu + skills + mobile QA + Spanish | Shared app dialogs, session ⋯ menu, /skills command, mobile QA suite, Android Chrome fixes, Spanish locale (@gabogabucho) | 648 | -| v0.48–v0.48.2 | Gateway session sync + table formatting + provider warnings | Real-time Telegram/Discord/Slack sessions in sidebar (@bergeouss), inlineMd() in table cells, provider/model mismatch toast | 679 | -| v0.49–v0.49.1 | Onboarding wizard + Docker two-container | One-shot bootstrap + guided setup wizard, OpenRouter/Anthropic/OpenAI/Custom provider config, two-container Docker compose, mobile Profiles button | 700 | -| v0.50.0 | v0.50.0 UI overhaul (Sprint 34) | Composer-centric controls, Hermes Control Center modal, workspace panel state machine, collapsible date groups, rAF streaming throttle, context ring indicator (@aronprins) | 742 | -| v0.50.5–v0.50.10 | Think-tag edge cases + onboarding hardening + mobile fixes | MiniMax M2.5 leading-whitespace think-tag fix, skip-onboarding env var, OAuth provider path, Docker bridge networks fix, model dropdown dedup, title auto-generation fix, mobile close button | 802 | -| v0.50.11–v0.50.12 | Chat table styles + URL autolink + profile env isolation | .msg-body table borders, plain URL auto-linking, profile .env secret isolation on switch (prevents API key leakage across profiles, @Hinotoi-agent) | 815 | -| v0.50.13–v0.50.15 | session_search + security sweep + KaTeX math | SessionDB injection for session_search in WebUI (@DelightRun), bandit B310/B324/B110 + QuietHTTPServer (@lawrencel1ng), KaTeX math rendering with fence-before-math fix | 871 | -| v0.50.16–v0.50.17 | CSRF reverse proxy + Docker uv pre-install | Scheme-aware CSRF port normalization for non-standard ports (@lx3133584), Docker uv pre-installed at build time as root (fixes air-gapped startup, @mmartial-pattern) | 900 | -| v0.50.18–v0.50.19 | Workspace fallback + Unicode filenames | Cascading workspace path recovery (@Jordan-SkyLF), Unicode Content-Disposition headers with RFC 5987 filename* (@shaoxianbilly), silent auth error surfacing, stale model cleanup | 924 | -| v0.50.20–v0.50.21 | Silent errors + live model fetching + durable streaming recovery | apperror on empty agent response, /api/models/live endpoint with SSRF guard, live reasoning cards, tool_complete SSE events, SESSION_QUEUES, localStorage reload recovery (@Jordan-SkyLF) | 961 | -| v0.50.22–v0.50.36-local.1 | Upstream sync + minimal local patch retention | Synced to upstream `v0.50.36`; retained first-password session continuity in Settings/onboarding; removed local Assistant Reply Language enhancement; added legacy settings cleanup regression coverage | 1059 | -| v0.50.37–v0.50.40 | Sprint 40 — rendering fixes + KaTeX CSP + MEDIA images | Think-tag edge cases, renderMd link double-linking fix, MEDIA: inline image rendering, KaTeX CSP font-src fix | 1117 | -| v0.50.41–v0.50.43 | Sprint 41/42 — context ring, session polish, renderMd hardening | Context indicator live usage, session display fixes, renderMd bold+code stash, outer link pass ordering, _ob_stash, autolink double-link fixes (@multiple contributors) | 1150 | -| v0.50.44 | Renderer formatting bug fixes (#486, #487) | CSS: inline code sizing in table cells; JS: markdown image syntax ![alt](url) → in renderMd + inlineMd; _img_stash for autolink protection | 1195 | -| v0.50.45–v0.50.100 | Upstream sync + contributor sprint | Sidebar declutter, SKIP_ONBOARDING, runtime route details, subpath mount, bug batch (light theme/panel/model cache/Docker), Docker UID/GID auto-detect, chat transcript redesign, favicon SVG+PNG+ICO, Docker UID-mismatch crash fix, auto-title markdown strip | 1777 | -| v0.50.101–v0.50.139 | Contributor sprint wave | Custom providers, Russian locale, collapsed timestamps, IME composition fixes, model-switch toast, approval queue multi-slot, live model fetching SSRF guard, orphaned tool-message sanitization, profile polish sprint (model routing, workspace cross-profile, legacy session backfill), font-size CSS fix | 1777 | -| v0.50.140–v0.50.147 | Bug batch + appearance | Font size setting visibly scales UI text (#843), slash command echoed as user message (#840), scroll selected item into view (#838), tasks refresh button (#835), font size toggle (#833), stale model fix (#829), session search clear on boot (#822), gateway SSE polling fallback (#635) | 1858 | -| v0.50.148–v0.50.150 | Session index + read-path + profile | Prune stale _index.json ghost rows after session-id rotation (#847 @franksong2702), GET /api/session side-effect-free model resolution (#848 @franksong2702), profile switching cookie persist + syncTopbar fix (#849 @migueltavares) | 1858 | -| v0.50.151 | credential_pool + Ollama Cloud | Providers added via auth store credential_pool now visible in model dropdown; Ollama Cloud support; ambient gh-cli token suppression; _apply_provider_prefix helper (#820 @starship-s) | 1898 | -| v0.50.152 | Image rendering + auto-title | image_generate MEDIA: token renders all https:// URLs as img regardless of extension (closes #853); auto-title strips Qwen3-style plain-text thinking preambles (closes #857) | 1898 | -| v0.50.153 | Portal model routing | Live-fetched models from portal providers (Nous, OpenCode) now get @provider: prefix so they route correctly instead of falling through to OpenRouter (closes #854) | 1898 | -| v0.50.154 | Thinking card mirror fix | _streamDisplay() early return removed — thinking card and main response now show distinct content when provider double-emits (closes #852) | 1898 | -| v0.50.155 | Honcho session stability | gateway_session_key=session_id passed to AIAgent so Honcho per-session strategy maintains one Honcho session per WebUI chat instead of one per turn (closes #855) | 1903 | -| v0.50.156 | Auto-install security gate | auto_install_agent_deps() is now opt-in; set HERMES_WEBUI_AUTO_INSTALL=1 to enable; _trusted_agent_dir() checks ownership/permission bits before running pip (⚠️ breaking: default changed) | 1903 | +| Surface | Status | +|---|---| +| **Hermes CLI parity** | ✅ Complete — every CLI workflow has a web equivalent | +| **Streaming + tool transparency** | ✅ Live tool cards, reasoning cards, approval prompts, cancel | +| **Multi-provider model support** | ✅ Any provider configured in `config.yaml` shows in the picker | +| **Sessions + projects + search** | ✅ CRUD, content search, projects, tags, archive, fork, import | +| **Mobile + Docker + auth** | ✅ Hamburger nav, slide-overs, password auth, GHCR images | +| **Auxiliary surfaces** | ✅ Workspace tree + edit, cron CRUD, skills CRUD, memory write, MCP server UI | +| **Visual polish** | ✅ 8 themes (incl. light/system/OLED/Sienna), Mermaid, KaTeX, syntax highlighting | +| **Native distribution** | ✅ macOS desktop app (universal arm64+x86_64 DMG, signed) — separate repo | + +Remaining gaps and forward work live in [Forward Work](#forward-work) below. --- -## Current Architecture Status +## Architecture -| Layer | Location | Status | -|-------|----------|--------| -| Python server | /server.py (~165 lines) + api/ modules (~5000 lines) | Thin shell + QuietHTTPServer + auth middleware + business logic in api/ | -| HTML template | /static/index.html (~600 lines) | Served from disk | -| CSS | /static/style.css (~1050 lines) | Served from disk, incl. mobile responsive, KaTeX, table styles | -| JavaScript | /static/{ui,workspace,sessions,messages,panels,boot,commands,icons,i18n,login}.js | 10 modules, ~7100 lines total | -| Docker | Dockerfile, docker-compose.yml, .dockerignore | python:3.12-slim, multi-arch (amd64+arm64) | -| CI/CD | .github/workflows/release.yml | Auto-release + GHCR publish on tag push | -| Runtime state | ~/.hermes/webui-mvp/sessions/ | Session JSON files | -| Test server | Port 8788 (conftest.py), port 8789 (browser sanity) | Isolated, wiped per run | -| Production server | Port 8787 | SSH tunnel from Mac | +| Layer | Files | Status | +|---|---|---| +| Python server | `server.py` (~165 lines) + `api/` modules (~20k lines) | Thin shell + auth middleware + business logic | +| HTML template | `static/index.html` (~600 lines) | Served from disk | +| CSS | `static/style.css` (~3k lines) | Themes, mobile responsive, KaTeX, table styles | +| JavaScript | `static/{ui,sessions,messages,workspace,panels,boot,commands,icons,i18n,login,onboarding}.js` (~26k lines) | 11 modules served as static files | +| Service worker | `static/sw.js` | Offline shell cache, version-pinned assets | +| Docker | `Dockerfile`, `docker-compose.yml` | `python:3.12-slim`, multi-arch (amd64+arm64), HEALTHCHECK | +| CI/CD | `.github/workflows/release.yml` | Auto-release + GHCR publish on tag push | +| Test isolation | `tests/_pytest_port.py` | Per-worktree port + state-dir derivation, no collisions | --- -## Feature Parity Checklist +## Feature parity checklist -### Chat and Agent +### Chat and streaming - [x] Send messages, get SSE-streaming responses -- [x] Switch models per session (10 models, grouped by provider) -- [x] Composer-scoped model picker in footer (moved from sidebar to align with per-conversation model selection) -- [x] Multi-provider API support: use any Hermes agent API provider (OpenAI, Anthropic, Google, etc.) directly, not just OpenRouter (Sprint 11) -- [x] Custom endpoint model discovery: auto-detect models from Ollama, LM Studio, and other local LLM servers via base_url (PR #18) -- [x] Upload files to workspace (drag-drop, click, clipboard paste) -- [x] File tray with remove button -- [x] Tool progress shown inline in the conversation via live tool cards -- [x] Approval card for dangerous commands (Allow once/session/always, Deny) +- [x] Composer-scoped model picker (per-conversation model selection) +- [x] Multi-provider API support — OpenAI, Anthropic, Google, OpenRouter, xAI, GLM, DeepSeek, Mistral, MiniMax, Kimi, OpenCode, Nous Portal, custom OpenAI-compatible endpoints +- [x] Live custom-endpoint model discovery (Ollama, LM Studio, vLLM via `/v1/models`) +- [x] Free-form OpenRouter model name (autocomplete + custom input) +- [x] Tool progress shown inline via live tool cards +- [x] Approval card for dangerous commands (Allow once / session / always, Deny) - [x] Approval polling + SSE-pushed approval events +- [x] Clarify dialog — agent can ask blocking clarifying questions +- [x] Subagent delegation cards in tool view - [x] INFLIGHT guard: switch sessions mid-request without losing response - [x] Session restores from localStorage on page load - [x] Reconnect banner if page reloaded mid-stream +- [x] SSE auto-reconnect with stream replay +- [x] Token / cost estimate per message and per session +- [x] Context usage indicator (compact ring badge in composer footer) +- [x] Auto-compaction handling + `/compact` command +- [x] rAF-throttled token rendering (smooth, no DOM thrash) +- [x] Cancel / stop button in composer footer +- [x] Reasoning effort selector (low / medium / high / xhigh) + `/reasoning` +- [x] Pure-text streaming with crash-recovery — partial messages restored from localStorage on reload + +### Conversation controls - [x] Copy message to clipboard (hover icon on each bubble) - [x] Edit last user message and regenerate -- [ ] Branch/fork conversation (Wave 3) -- [x] Token/cost estimate per message (Sprint 23) - -### Tool Visibility -- [x] Tool progress in live tool cards (kept out of the composer/footer chrome) -- [x] Approval card with all 4 choices -- [x] Tool call cards inline (collapsed, show name/args/result) - -### Workspace / Files -- [x] Workspace panel defaults closed and opens only for active browsing or preview -- [x] Browse workspace directory tree with type icons -- [x] Preview text/code files (read-only) -- [x] Preview markdown files (rendered, tables supported) -- [x] Preview image files (PNG, JPG, GIF, SVG, WEBP inline) -- [x] Edit files inline (Edit button, Enter to save, Escape to cancel) -- [x] Create new file (+ button in panel header) -- [x] Delete file (hover trash, confirmation modal) -- [x] File name truncation with tooltip for long names -- [x] Right panel resizable (drag inner edge) -- [x] Syntax highlighted code preview (Prism.js) -- [x] Rename file (Sprint 14) -- [x] Create folder (Sprint 14) -- [x] Shared app modal for confirm/input flows (Sprint 33) +- [x] Regenerate last response +- [x] Clear conversation (wipe messages, keep session) +- [x] Branch / fork conversation from any message point (#465) +- [x] Pure-text + tool-call streams both recover ### Sessions - [x] Create session (+ button or Cmd/Ctrl+K) - [x] Load session (click in sidebar) -- [x] Delete session (hover trash, toast, correct fallback) -- [x] Auto-title from first user message -- [x] Rename session title (double-click in sidebar, Enter saves, Escape cancels) -- [x] Filter/search sessions by title (live filter box) -- [x] Date group headers (Today / Yesterday / Earlier) -- [x] Download session as Markdown transcript -- [x] Export session as JSON (full messages + metadata) -- [x] Session inherits last-used workspace on creation -- [x] Session content search (search message text across sessions) -- [x] Session tags / labels (Sprint 14) -- [x] Archive sessions (Sprint 14) -- [x] Clear conversation (wipe messages, keep session) (Wave 3) -- [x] Import session from JSON (Sprint 12) -- [x] Pin/star sessions to top of list (Sprint 12) -- [x] Duplicate session (Sprint 13) -- [x] Session projects / folders (Sprint 15) +- [x] Delete session (hover trash, toast undo, fallback) +- [x] Auto-title from first user message + adaptive title refresh (configurable cadence) +- [x] LLM-generated titles via auxiliary route (configurable model) +- [x] Rename session inline (double-click, Enter saves, Escape cancels) +- [x] Title search (live filter) +- [x] Content search (full-text across all sessions) +- [x] Date group headers (Today / Yesterday / Earlier) with collapsible groups +- [x] Pin / star sessions to top +- [x] Duplicate session +- [x] Import / Export session as JSON (full messages + metadata) +- [x] Download as Markdown transcript +- [x] Tags (`#tag` extraction + filter chips) +- [x] Archive sessions (hidden by default, "Show N archived" toggle) +- [x] Projects / folders (chip filter bar, "Unassigned" filter) +- [x] Per-session profile tracking +- [x] Per-session toolset override (`/toolsets`) +- [x] Batch select mode (multi-select, bulk delete / move / archive) +- [x] CLI session bridge — read CLI sessions from state.db, import as WebUI sessions -### Workspace Management -- [x] Add workspace with path validation (must be existing directory) -- [x] Remove workspace -- [x] Rename workspace display name -- [x] Quick-switch workspace from topbar dropdown -- [x] Sidebar live workspace display (name + path, updates in real time) -- [x] New sessions inherit last used workspace -- [x] Workspace list persists to workspaces.json -- [ ] Workspace reorder (drag) (Wave 2) +### Workspace and files +- [x] Add workspace with path validation (existing directory, follows symlinks) +- [x] Remove / rename workspace +- [x] Quick-switch from topbar dropdown +- [x] Sidebar live workspace display (name + path) +- [x] New sessions inherit last-used workspace +- [x] Browse workspace directory tree with type icons +- [x] Tree view with expand / collapse + lazy load (#22) +- [x] Breadcrumb navigation in subdirectories +- [x] Preview text / code (read-only) +- [x] Preview markdown (rendered + tables + Mermaid + KaTeX) +- [x] Preview images (PNG, JPG, GIF, SVG, WEBP, AVIF inline) +- [x] Preview PDF / SVG / audio / video / Excalidraw / CSV / JSON / YAML +- [x] Edit files inline (Edit button, Enter saves, Escape cancels) +- [x] Create / rename / delete files and folders (in current directory) +- [x] Drag-drop / click / clipboard paste upload +- [x] Archive upload (zip / tar) with extraction +- [x] Syntax highlighted code preview (Prism.js, language-aware) +- [x] File preview auto-close on directory navigation +- [x] Right panel resizable (drag inner edge) +- [x] Embedded workspace terminal (`/api/terminal/{start,input,output}`) +- [x] Git branch + dirty status badge in workspace header -### Scheduled Tasks (Cron) -- [x] View all cron jobs (Tasks sidebar tab) -- [x] View last run output per job (auto-loaded on expand) -- [x] Expand job to see prompt, schedule, last output -- [x] Run job manually (Run now button) -- [x] Pause / Resume job -- [x] Create cron job from UI (+ New job form with name, schedule, prompt, delivery) -- [x] Edit existing cron job -- [x] Delete cron job -- [x] View full cron run history (expandable per job) -- [x] Skill picker in cron create form (Sprint 23) +### Cron jobs +- [x] List all cron jobs (Tasks sidebar tab) +- [x] View job details (prompt, schedule, last run, output) +- [x] Run / pause / resume / delete +- [x] Create job from UI (name, schedule, prompt, delivery target) +- [x] Edit job inline (full create-form parity, including skills) +- [x] Skill picker in create + edit forms +- [x] Cron run history viewer (expandable per job) +- [x] Cron completion alerts (toast + badge) +- [x] Run-status tracking with live watch mode ### Skills -- [x] List all skills grouped by category (Skills sidebar tab) -- [x] Search/filter skills by name, description, category -- [x] View full SKILL.md content in right preview panel -- [x] Create skill -- [x] Edit skill -- [x] Delete skill -- [x] View skill linked files (Sprint 23) +- [x] List all skills grouped by category +- [x] Search / filter by name, description, category +- [x] View full SKILL.md content +- [x] View skill linked files +- [x] Create / edit / delete skill +- [x] `/skills` slash command ### Memory -- [x] View personal notes (MEMORY.md) rendered as markdown (Memory tab) -- [x] View user profile (USER.md) rendered as markdown (Memory tab) -- [x] Last-modified timestamp on each section -- [x] Add/edit memory entry inline - -### Configuration -- [x] Settings panel (default model, default workspace) (Sprint 12) -- [x] Send key preference (Enter or Ctrl+Enter) (Sprint 17) -- [x] Password authentication (Sprint 19) -- [ ] Enable/disable toolsets per session (deferred) - -### Notifications -- [x] Cron job completion alerts (Sprint 13) -- [x] Background agent error alerts (Sprint 13) - -### Workspace -- [x] Breadcrumb navigation in subdirectories (Sprint 17) -- [x] Workspace tree view with expand/collapse (Sprint 18, Issue #22) -- [x] File preview auto-close on directory navigation (Sprint 18) - -### Slash Commands -- [x] Command registry + autocomplete dropdown (Sprint 17) -- [x] Built-in: /help, /clear, /model, /workspace, /new (Sprint 17) - -### Security -- [x] Password auth with signed cookies (Sprint 19, Issue #23) -- [x] Security headers (X-Content-Type-Options, X-Frame-Options) (Sprint 19) -- [x] POST body size limit (20MB) (Sprint 19) - -### 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, sidebar tabs on phones, files slide-over (Sprint 21 + later mobile nav simplification) +- [x] View personal notes (MEMORY.md) rendered as markdown +- [x] View user profile (USER.md) rendered as markdown +- [x] Last-modified timestamp per section +- [x] Add / edit memory entries inline ### Profiles -- [x] Multi-profile support — create, switch, delete profiles (Sprint 22, Issue #28) +- [x] Multi-profile support — create, switch, delete (#28) +- [x] Topbar profile picker with gateway-status dots +- [x] Profile management panel (full CRUD) +- [x] Seamless switching (no server restart, refreshes models / skills / memory / cron / workspace) +- [x] Profile-local workspace storage +- [x] First-run onboarding wizard with provider config (OpenRouter / Anthropic / OpenAI / Custom) +- [x] In-app OAuth for Codex and Claude -### Advanced / Future -- [ ] Subagent session tree -- show subagent hierarchy in sidebar with expand/collapse (PR #75) -- [ ] Specialized tool card renderers -- diff viewer, terminal output, todo checklist views (PR #75) -- [x] Streaming performance -- rAF-throttled token rendering (Sprint 24, PR #81) -- [x] Workspace git detection -- branch name and dirty status badge (Sprint 24, PR #82) -- [x] Collapsible date groups -- click group headers to collapse (Sprint 24, PR #80) -- [x] Context usage indicator -- compact circular badge in composer footer (Sprint 24, PR #83; refreshed April 10, 2026) -- [ ] LLM-generated session titles -- auto-title via small model instead of first-message substring (PR #75) -- [ ] Workspace git detection -- show branch name, dirty status in workspace header (PR #75) -- [ ] Clarify dialog -- agent can ask clarifying questions that block until user responds (PR #75) -- [ ] Gateway approval polling -- support blocking approvals from messaging gateway (PR #75) -- [ ] Unified session storage -- SessionDB shared between webui and CLI (PR #75) -- [ ] TTS playback of responses (deferred) -- [x] Background task cancel (composer footer stop button) -- [ ] Code execution cell (deferred) -- [ ] Desktop application (Sprint 25, PLANNED) -- [x] Pluggable UI themes -- Dark, Light, Slate, Solarized, Monokai, Nord (Sprint 26, v0.34) -- [ ] Extended slash command / skill integration (deferred) -- [ ] Virtual scroll for large lists (deferred) +### Configuration +- [x] Settings panel (default model, default workspace, send key, theme, voice, font size) +- [x] Send key preference (Enter or Ctrl+Enter) +- [x] Password authentication (off by default) +- [x] Per-session toolset override +- [x] Personality config via `config.yaml` +- [x] Reasoning effort persistence + +### Notifications +- [x] Cron job completion alerts +- [x] Background agent error banner +- [x] Approval pending badge +- [x] Provider / model mismatch toast warning + +### Slash commands +- [x] Command registry + autocomplete dropdown +- [x] Built-ins: `/help`, `/clear`, `/model`, `/workspace`, `/new`, `/usage`, `/theme`, `/compact`, `/queue`, `/interrupt`, `/steer`, `/btw`, `/reasoning`, `/skills`, `/toolsets` +- [x] Transparent pass-through for unrecognized commands + +### Security +- [x] Password auth with signed HMAC HTTP-only cookies (24h TTL) +- [x] Security headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy) +- [x] CSRF protection (scheme-aware, port-normalized for reverse proxies) +- [x] PBKDF2 password hashing +- [x] Rate limiting on auth endpoints +- [x] Session ID validation +- [x] SSRF guard on `/api/models/live`, `cfg_base_url`, `custom_providers[]` +- [x] ENV_LOCK around env mutations +- [x] XSS sanitization on all rendered HTML +- [x] HMAC-signed signing keys (random per install) +- [x] Skills path-traversal guard +- [x] Secure cookie flags (HttpOnly, SameSite, Secure when HTTPS) +- [x] Error message sanitization (no stack traces in responses) +- [x] POST body size limit (20MB) +- [x] Upload path-traversal guard +- [x] Credential redaction in API responses +- [x] Profile `.env` secret isolation on switch +- [x] Auto-install gate (opt-in via `HERMES_WEBUI_AUTO_INSTALL=1`) + +### Visual / UX +- [x] 8 themes — Dark, Light, System (auto-sync), Slate, Solarized, Monokai, Nord, OLED, Sienna +- [x] 2-axis appearance model (theme + skin) for community theme contributions +- [x] Mermaid diagram rendering +- [x] KaTeX math rendering with fence-before-math fix +- [x] Syntax highlighting (Prism.js, language-aware, YAML newline preservation) +- [x] Markdown image syntax `![alt](url)` and inline MEDIA: tokens render as `` +- [x] Plain URL auto-linking +- [x] Inline markdown in table cells (bold, italic, code, links) +- [x] Code block copy button +- [x] Tool card expand / collapse toggle +- [x] Collapsible thinking / reasoning cards (Claude extended thinking, o3 reasoning tokens) +- [x] Message timestamps (subtle, full date on hover) +- [x] Empty composer hides send button (icon-circle with pop-in animation) +- [x] Pluggable Lucide SVG icons (no emoji rendering inconsistencies) +- [x] Composer-centric controls (v0.50.0 UI overhaul) +- [x] Hermes Control Center modal (centralized actions) +- [x] Workspace panel state machine (defaults closed, opens for browsing / preview) +- [x] PWA manifest + service worker (offline shell) +- [x] Favicon (SVG + PNG + ICO) +- [x] Branded onboarding wizard + +### Voice +- [x] Voice input via Web Speech API (push-to-talk dictation) +- [x] Hands-free voice mode (turn-based conversation, opt-in via Settings → Preferences) +- [x] TTS playback of responses (configurable voice, rate, pitch) + +### Mobile +- [x] Hamburger sidebar (slide-in overlay) +- [x] Bottom navigation bar (5-tab iOS-style) +- [x] Files slide-over (right panel as slide-over) +- [x] 44px minimum touch targets +- [x] Container queries on composer +- [x] Android Chrome compatibility fixes +- [x] PWA installation (manifest + icons + Android support) + +### Internationalization +- [x] 9 locales — English, Japanese, Russian, Spanish, German, Chinese (zh + zh-Hant), Portuguese, Korean, French +- [x] Key-parity test ensures every locale has every key +- [x] Right-to-left and CJK input (IME composition fixes) + +### Gateway integration +- [x] Real-time gateway sessions in sidebar (Telegram, Discord, Slack, Weixin) via SSE + DB polling +- [x] Cross-channel handoff dock — composer-docked flyout summarizing the live external session +- [x] Transcript-summary card at 10+ rounds +- [x] Sidebar dedup keying on per-conversation identity (distinct chats from same platform stay separate) +- [x] Gateway session sync skips dup / delete options for external sessions + +### MCP integration +- [x] MCP server management UI (System Settings → MCP Servers) +- [x] Add / edit / delete MCP server entries + +### Distribution +- [x] Docker support (multi-arch amd64 + arm64, HEALTHCHECK, UID/GID auto-detect) +- [x] Two-container Docker compose (webui + agent) +- [x] GHCR auto-publish on tag push +- [x] Subpath mount support (reverse proxy at `/hermes/`) +- [x] PWA installable from any browser +- [x] Native macOS app — universal Intel + Apple Silicon, signed + notarized DMG, Sparkle 2 auto-update — see `hermes-webui/hermes-swift-mac` repo --- -## Sprint 7: Wave 2 Core -- Cron/Skill/Memory CRUD + Session Content Search (COMPLETED) +## Forward work -**Theme:** "Wave 2 Core -- Cron/Skill/Memory CRUD + Session Content Search" +### Confirmed candidates (open feature requests with sprint-candidate or active interest) -### Track A: Bug Fixes -| Item | Description | -|------|-------------| -| Activity bar sizing | Activity bar sometimes overlaps first message on short viewports | -| Model dropdown sync | Model chip in topbar sometimes shows stale model after session switch | -| Cron output truncation | Long cron output in the tasks panel overflows its container | +| Theme | Tracking | Why | +|---|---|---| +| Persistent-host stability | #1458 | Bootstrap fork pattern crashes under launchd / systemd — partial fix shipped (foreground mode); state.db FD leak and HTTP-unhealthy wedge remain | +| Free-tier OpenRouter variants visible | #1426 | `:free` tool-support filter currently hides them from the picker | +| macOS scroll override regression | #1360 | Auto-scroll sometimes overrides user scroll on the desktop app | +| GLM dual-use (main + auxiliary) | #1291 | Currently mutually exclusive; same provider can't serve both surfaces | +| Auto-assign session to filtered project | #1468 | When user is filtering by project X, new session should default to project X | +| Update banner "What's new?" link | #1512 | Surface release highlights from the update banner | +| Sunset legacy `LMSTUDIO_API_KEY` env var | #1502 | Tracking issue — alias stays for one minor cycle, then removed | +| Hermes Agent dashboard cross-link | #1459 | Detect a running Hermes Agent and surface link in nav | +| Gateway status card in Settings | #1457 | Current gateway-status dots only on profile picker | +| Insights — daily token chart + per-model breakdown | #1456 | Existing usage badge is per-message; need rollup view | +| Logs tab — view agent / errors / gateway logs | #1455 | Currently requires terminal access to log files | +| Model picker collision handling | #1425 | Same-name models from different providers aren't disambiguated in dropdown | +| "Reveal in Finder" right-click on workspace | #1424 | macOS desktop app convenience | +| Configurable session persistence timing | #1406 | Currently every checkpoint, want operator control | +| Silent credential self-heal on 401 | #1401 | Gateway auth.json drift should resolve without user re-auth | +| LLM Wiki status panel | #1257 | On / off toggle for Wiki integration | +| Lightweight in-app Canvas editing | #1255 | Text canvas for prompt drafting / shared notes | +| Provider / Model source-of-truth alignment | #1240 | Reconcile WebUI vs CLI vs Gateway provider resolution | +| Built-in SearXNG web search | #1037 | Lightweight search tool with on / off toggle | +| Subagent session relationship view | #1004 | Show subagent hierarchy in sidebar with expand / collapse | -### Track B: Features -| Feature | What | Value | -|---------|------|-------| -| Session content search | Search message text across all sessions, not just titles. GET /api/sessions/search already does title search; extend to message content with a configurable depth limit | High: the single most-requested nav feature after rename | -| Cron edit + delete | Edit an existing cron job (name, schedule, prompt, delivery) inline in the tasks panel. Delete with confirm. POST /api/crons/update and /api/crons/delete | High: closes the cron CRUD gap (create was Sprint 6) | -| Skill create + edit | A "New skill" form in the Skills panel. Name, category, SKILL.md content in a textarea editor. Save calls POST /api/skills/save (writes to ~/.hermes/skills/). Edit opens existing skill in the same editor | High: biggest remaining CLI gap after cron | +### Backlog (deferred, listed for visibility) -### Track C: Architecture -| Item | What | -|------|------| -| Phase E: app.js module split (start) | Split app.js (1332 lines) into logical modules: sessions.js, chat.js, workspace.js, panels.js, ui.js. Serve via ES module imports in index.html. This is Phase E completion. | -| Health endpoint improvement | Add active_streams, uptime_seconds to /health response (Phase G) | -| Git init | git init , first commit, push to private GitHub repo | +- **Insights / monitoring suite** — agent heartbeat + alerts (#716), quota / rate-limit display (#706), data tabs (#722), monitor dashboard concepts (#766, #721) +- **Native MCP server expose** — Hermes WebUI as an MCP server for direct agent integration (#733) +- **Provider failover status** — show active provider per model + LLM Gateway failover state (#732) +- **Teams / agents management panel** — editable names, roles, assignments (#719) +- **Web UI profile model alignment with Hermes runtime** — design parity (#749) +- **DOM windowing / message virtualization** — for sessions with hundreds of messages (#734) +- **Searchable global tool list** (#697) +- **Add agent / replace model modals** (#698) +- **Code execution inline cells** — Jupyter-style cell rendering inside chat +- **Sharing / public conversation URLs** — requires hosted backend with access control (out of scope for self-host) -### Tests -- ~20 new pytest tests (cron update/delete, skill save, session content search) -- TESTING.md: Sections 29-31 (cron edit, skill edit, session search) -- Estimated total after Sprint 7: ~126 +### Intentionally not planned +- Full SwiftUI rewrite of the frontend — the WKWebView shell already gets 95% of native benefit +- App Store distribution — sandboxing breaks the local server model +- Real-time multi-user collaboration — single-user assumption throughout +- Plugin marketplace — Hermes skills cover this surface +- Anthropic / Claude proprietary features — Projects AI memory, Claude artifacts sync (not reproducible) --- -## Wave 2: Full CRUD and Interaction Parity +## Sprint history -**Status:** In progress. Sprint 6 completed cron create and workspace management. -Remaining Wave 2 items targeted for Sprints 7-8. +Per-version detail lives in [CHANGELOG.md](./CHANGELOG.md). The table below is a high-level chronology of major sprint themes; individual PR / fix detail moved to CHANGELOG to keep this file readable. -### Sprint 2.0: Workspace Management (COMPLETE Sprint 5+6) -All workspace features delivered: add/validate/remove/rename workspaces, topbar quick-switch, -sidebar live display, new sessions inherit last workspace. See Sprint 5 completed section. - -### Sprint 2.1: Cron Job Management (Partial -- Sprint 7 for remaining) -- [x] View all jobs (Sprint 3) -- [x] Run / pause / resume (Sprint 3) -- [x] Create job from UI (Sprint 6) -- [x] Edit job -- [x] Delete job -- [x] Full cron run history - -### Sprint 2.2: Skill Management (Partial -- Sprint 7 for remaining) -- [x] List all skills with categories (Sprint 3) -- [x] View SKILL.md content (Sprint 3) -- [x] Create skill -- [x] Edit skill -- [x] Delete skill - -### Sprint 2.3: Memory Write (Sprint 7) -- [x] View notes + profile (Sprint 3) -- [x] Edit notes inline - -### Sprint 2.4: Todo Management (Wave 2) -- [x] View current todo list (sidebar Todo panel, parsed from session history) - -### Sprint 2.5: Session Content Search (Sprint 7) -- [x] Session title search (Sprint 4) -- [x] Message content search across sessions - -### Sprint 2.6: Session Rename (COMPLETE Sprint 4) -Double-click any session title in the left sidebar to edit inline. -Enter saves, Escape cancels. Topbar updates immediately. +| Range | Theme | Highlights | +|---|---|---| +| Sprints 1–6 | Foundations + workspace | server / static split, JS module split, workspace CRUD, file editor, message queue + INFLIGHT, isolated test environment | +| Sprint 7 | Wave 2 core | Cron / skill / memory CRUD, session content search, health endpoint, git init | +| Sprint 8 | Daily-driver finish line | Edit + regenerate, regenerate last response, clear conversation, Prism.js, queue + INFLIGHT polish | +| Sprints 9–10 | Codebase health + operational polish | `app.js` → 6 modules, server.py → `api/` modules, tool card UX, background task cancel, regression tests | +| Sprint 11 | Multi-provider models + streaming | Dynamic model dropdown, smooth scroll pinning, routes extracted to `api/routes.py` | +| Sprint 12 | Settings + reliability + session QoL | Settings panel, SSE auto-reconnect, pin sessions, JSON import | +| Sprint 13 | Alerts + polish | Cron alerts, background error banner, session duplicate, browser tab title | +| Sprint 14 | Visual polish + workspace ops | Mermaid, message timestamps, file rename, folder create, session tags, archive | +| Sprint 15 | Session projects + code copy | Projects / folders, code copy button, tool card expand / collapse | +| Sprint 16 | Sidebar visual polish | SVG icons, action dropdown, pin indicator, project border, safe HTML rendering | +| Sprint 17 | Workspace polish + slash commands | Breadcrumb nav, slash command autocomplete, send key setting (#26) | +| Sprint 18 | Thinking display + workspace tree | File preview auto-close, thinking / reasoning cards, expandable directory tree (#22) | +| Sprint 19 | Auth + security hardening | Password auth, login page, security headers, body limit (#23) | +| Sprint 20 | Voice input + send button | Web Speech API voice, send button polish | +| Sprint 21 | Mobile responsive + Docker | Hamburger sidebar, mobile nav, slide-over files, Docker support (#21, #7) | +| Sprint 22 | Multi-profile support | Profile picker, management panel, seamless switching, per-session tracking (#28) | +| Sprint 23 | Agentic transparency | Token / cost display, subagent cards, skill picker in cron, profile-local storage | +| Sprint 24 | Web polish | rAF streaming, git detection, collapsible date groups, context ring (#80, #81, #82, #83) | +| Sprint 25 | macOS desktop application | Native Swift + WKWebView shell, universal DMG, Sparkle 2 auto-update — separate repo | +| Sprint 26 | Pluggable themes | Light / Slate / Solarized / Monokai / Nord, settings unsaved-changes guard, `/theme` | +| Sprint 27 | Theme polish | 30+ hardcoded colors → CSS variables, light theme final polish | +| Sprint 28 | Security hardening | Env race fix, random signing key, upload traversal, PBKDF2 | +| Sprints 29–32 | Model routing + custom endpoints + reasoning | Model routing by provider prefix, custom endpoint URL fix, OLED theme, top-level reasoning, message_count sync | +| Sprint 33 | Approval card + Lucide icons | Approval prompt surfaced, emoji → SVG, login CSP fix, update diagnostics | +| Sprint 34 | v0.50.0 UI overhaul | Composer-centric controls, Control Center modal, workspace state machine, collapsible date groups, rAF throttle, context ring | +| Sprints 35–37 | Onboarding + i18n + Spanish | First-run wizard, OpenRouter / Anthropic / OpenAI / Custom config, Spanish locale, Docker two-container, mobile Profiles button | +| Sprints 38–40 | Session + UI polish + Sprint 40 | Five-bug clean-up + sidebar timestamp + test port isolation | +| Sprints 41–42 | Renderer hardening + KaTeX + handoff | Context ring live usage, renderMd link / image / code stash chain, MEDIA: image rendering, gateway handoff foundation | +| Sprints 43+ | Continuous contributor sprints | Custom providers, Russian locale, IME fixes, model-switch toast, approval queue multi-slot, profile polish, font-size CSS, contributor wave | --- -## Completed Waves (Summary) +## Versioning conventions -| Wave | Theme | Key Deliverables | -|------|-------|-----------------| -| Wave 2 | Full CRUD + Interaction | Cron/skill/memory CRUD, session search, workspace management, session rename | -| Wave 3 | Power Features | Tool call cards, multi-model dropdown, resizable panels, file actions, conversation controls | -| Wave 4 | Settings + Notifications | Settings panel, cron alerts, background error banner | -| Wave 5 | Session Continuity | Session tags, archive, projects/folders | -| Wave 6 | Agentic Features | Background task cancel, voice input (Web Speech API) | -| Wave 7 | Production Hardening | Password auth, security headers, mobile responsive, Docker + GHCR CI | +- **Patch** (`v0.50.X`) — small batches, contributor PR releases, hotfixes +- **Minor** (`v0.X.0`) — sprint completion, new feature surface, architecture milestone +- **Major** (`v1.0.0`) — declared when CLI parity + Claude parity reach steady state and the feature surface stabilizes ---- - -## User Requested Features - -Community-requested enhancements tracked from GitHub issues. All shipped. - -| Feature | Issue | Shipped | Sprint | -|---------|-------|---------|--------| -| Workspace tree view | #22 | Done | Sprint 18 | -| Docker container + GHCR images | #7 | Done | Sprint 21 + v0.28.1 CI | -| Authentication | #23 | Done | Sprint 19 | -| Send key / personalization | #26 | Done | Sprint 17 | -| Multi-profile support | #28 | Done | Sprint 22 | -| Mobile responsive UI | #21 | Done | Sprint 21 | -| Profile creation in Docker | #44 | Done | v0.27 | +Per-version detail and contributor attribution live in [CHANGELOG.md](./CHANGELOG.md). diff --git a/SPRINTS.md b/SPRINTS.md index b2d1b272..db704396 100644 --- a/SPRINTS.md +++ b/SPRINTS.md @@ -1,1159 +1,147 @@ -# Hermes Web UI -- Forward Sprint Plan +# Hermes Web UI — Sprint Planning -> Current state: v0.50.245 | 3309 tests | Full daily driver — CLI parity achieved +> Forward-looking sprint plan and active queue. > -> NOTE: This file is preserved as a historical planning record. Current sprint state -> and version history live in CHANGELOG.md and ROADMAP.md. +> Current state: v0.50.281 | 3995 tests | port 8787 +> Target A (CLI parity): ✅ Complete +> Target B (Claude parity): ~95% — full subagent transparency UI and code-execution cells remain > -> Target A (CLI parity): ✅ Complete — all core tools, workspace, cron, skills, -> memory, sessions, profiles, model routing, streaming, voice, mobile. -> -> Target B (Claude parity): ~90% — thinking display, math rendering (KaTeX), -> tool cards, workspace preview, onboarding, settings panel all done. -> Remaining: full subagent transparency UI, file diff viewer. -> -> Last meaningful update: v0.50.245 (April 30, 2026). See CHANGELOG.md for full history. +> Per-version detail: [CHANGELOG.md](./CHANGELOG.md) +> Sprint history (chronology): [ROADMAP.md](./ROADMAP.md) --- -## Where we are now (v0.50.245 — updated April 2026) +## How sprints work here -> The sections below describe the original sprint plans (Sprints 11–17) for historical reference. -> See ROADMAP.md for the full sprint history table (v0.36 → v0.50.245) and CHANGELOG.md for per-version release notes. +A sprint is a thematic batch — usually 3–8 PRs landed together as a release. Each sprint has: -**CLI parity: ✅ Complete** as of the v0.50.x line. Core agent loop, all tools visible, workspace file ops with tree view and git detection, cron/skills/memory CRUD, session management, streaming with rAF throttle, cancel, multi-provider models, custom endpoint discovery, slash commands (help/clear/model/workspace/new/usage/theme/compact/queue/interrupt/steer/btw/reasoning), thinking/reasoning display, password auth, multi-profile support with seamless switching, CLI session bridge (read and import from state.db), context auto-compaction handling, self-update checker, embedded workspace terminal, archive upload (zip/tar), workspace directory CRUD. +1. **Theme** — single-sentence framing of what changes +2. **Items** — selected work, with tracking issue / PR +3. **Out of scope** — what is explicitly deferred and why +4. **Risks** — known sharp edges +5. **Retro** — once shipped, what we learned -**Claude parity: ~95% complete.** Chat, streaming with incremental markdown (vendored streaming-markdown@0.2.15), file browser with diff/JSON/YAML/CSV/Excalidraw inline rendering, PDF/SVG/audio/video preview, session management with projects/tags, tool cards with subagent delegation, syntax highlighting, model switching with provider-aware default rehydration, Mermaid diagrams, full mobile responsive layout (container queries on composer, slide-over workspace), breadcrumb workspace nav with tree view, slash commands, thinking/reasoning display, auth with signed cookies, 8 pluggable UI themes (dark/light/system/slate/solarized/monokai/nord/Sienna/OLED), voice input (Web Speech API) and TTS playback, collapsible date groups, context ring usage indicator, token/cost display, git branch badge, Docker support with HEALTHCHECK, batch session select mode, configurable model badges, MCP server management UI, cron run-status tracking with watch mode, PWA manifest. Remaining gaps: artifacts sharing/public URLs, code execution inline cells. +External contributor PRs that don't fit a planned sprint get released individually as patch versions (`v0.50.X`). Sprints are reserved for coherent batches where the items reinforce each other. --- -## Sprint 11 -- Multi-Provider Models + Streaming Smoothness (COMPLETED) +## Active sprint candidates -**Theme:** Use any Hermes-supported model provider from the UI, and make -heavy agentic work feel fast and fluid. +These are the issues currently labeled `sprint-candidate` — the inbox the next sprint plan draws from. Each item already has a confirmed root cause or design direction. -**Why now:** Two high-impact gaps converge here. First, the model dropdown is -hardcoded to ~10 OpenRouter model strings. If Hermes is configured with direct -Anthropic, OpenAI, Google, or other API providers, the web UI can't use them. -This means users who set up Hermes with native API keys are locked out of -their own models in the browser. Second, the streaming render path rebuilds -the entire message list on every tool event, causing visible flicker during -heavy agentic work. +| # | Title | Type | Sprint fit | +|---|---|---|---| +| #1458 | Persistent-host crashes — bootstrap fork pattern, state.db FD leak, HTTP-unhealthy wedge | bug, stability | Stability sprint candidate | +| #1426 | OpenRouter free-tier `:free` variants invisible (tool-support filter) | bug + feat | Model picker sprint candidate | +| #1362 | In-app OAuth login for Codex and Claude (currently terminal-only) | feat, ux | Onboarding sprint candidate | +| #1360 | macOS desktop app — auto-scroll overrides user scroll (#677 regression) | bug, ux | Desktop app polish | +| #1291 | GLM mutually exclusive between main agent and auxiliary title generation | bug | Auxiliary-route sprint | -### Track A: Bugs -- Tool card DOM thrash: renderMessages() rebuilds all cards on each tool event. - Switch to incremental append (append new card to existing group, no full rebuild). -- Scroll position lost on re-render during streaming (messages jump). - -### Track B: Features -- **Multi-provider model support:** Query Hermes agent's configured providers - and available models at startup via a new `GET /api/models` endpoint. The - model dropdown populates dynamically from whatever providers the user has - configured (OpenRouter, direct OpenAI, direct Anthropic, Google, DeepSeek, - etc.). Group by provider. Fall back to the current hardcoded list if the - agent query fails. This ensures the web UI can use any model the CLI can. -- **Incremental tool card streaming:** Instead of renderMessages() on each - tool event, maintain a live card group element per turn and append/update - cards in place. The assistant text row below the cards also updates - incrementally (already does via assistantBody.innerHTML). -- **Smooth scroll:** Pin scroll to bottom during streaming unless user has - manually scrolled up (read-back mode). Resume pinning when user scrolls - back to bottom. - -### Track C: Architecture -- `api/routes.py`: extract the 49 if/elif route handlers from server.py's - Handler class into a dedicated routes module. server.py becomes a true - ~50-line shell: imports, Handler stub that delegates to routes, main(). - Completes the server split started in Sprint 10. - -**Tests:** ~15 new. Total: ~205. -**Hermes CLI parity impact:** High (model provider parity is a major CLI gap) -**Claude parity impact:** Low (streaming smoothness) +The active queue stays small — it's the next 1-2 sprints' worth of work. The broader backlog of feature requests lives in [ROADMAP.md → Forward Work](./ROADMAP.md#forward-work) and on the GitHub `enhancement` label. --- -## Sprint 12 -- Settings Panel + Reliability + Session QoL (COMPLETED) +## Planning principles -**Theme:** Persist your preferences, survive network blips, and organize sessions. +**Phase-0 fit assessment.** Every sprint candidate gets a marginal-benefit screen first: does this make the product noticeably better for real users, or does it add surface area that costs more to maintain than it earns? Five-question fit screen — need / shape / bloat / clutter / scope. -**Why now:** Three daily-driver friction points converge. First, default model -and workspace aren't persisted server-side -- every restart loses them. Second, -SSH tunnel hiccups during long agent runs silently kill the response with no -recovery. Third, after 50+ sessions the flat chronological list makes it hard -to keep important conversations accessible. +**Salvage over absorb.** When a contributor PR is partial or scoped wrong, prefer splicing the good parts into a maintainer-side PR with `Co-authored-by` attribution rather than asking for multiple rebase rounds. Only absorb whole when the PR is genuinely shippable as-is. -### Track A: Bugs -- Workspace validation on add doesn't check symlinks (shows as invalid when - it's actually a valid symlink to a directory). +**Independent-review gate.** Self-built PRs need either (a) Opus advisor pass on the merged stage diff, or (b) independent review from a separate reviewer. High-risk batches (large LOC, security, locks, durability) get both. -### Track B: Features -- **Settings panel:** A gear icon in the topbar opens a slide-in settings panel. - Sections: Default Model, Default Workspace. Persisted server-side in - `~/.hermes/webui-mvp/settings.json`. Server reads settings on startup and - uses them as defaults. `GET /api/settings` + `POST /api/settings` endpoints. -- **SSE auto-reconnect:** When the EventSource connection drops mid-stream - (network blip, SSH tunnel hiccup), auto-reconnect once using the same - `stream_id`. The server-side queue holds undelivered events. If reconnect - fails after 5s, show error banner. This is the #1 reliability gap for - remote VPS usage. -- **Pin sessions:** A star icon on any session in the sidebar. Pinned sessions - float to the top of the list above date groups. Persisted on the session - JSON as `pinned: true`. Toggle on click. Simple and high quality-of-life. -- **Import session from JSON:** Drag a `.json` export file into the sidebar - (or click an import button) to restore it as a new session. Mirrors the - existing JSON export. Useful for moving sessions between machines. +**Per-PR release velocity.** When a single PR fixes a real bug and has a clean review, ship it as its own patch release the same day rather than waiting for a sprint batch. Friction-free is the goal — sprint batches exist for coherence, not for arbitrary grouping. -### Track C: Architecture -- Settings schema: `settings.json` with typed fields, validated on load, with - sane defaults. Served via `GET /api/settings`, written via `POST /api/settings`. -- SSE reconnect: server keeps `STREAMS[stream_id]` alive for 60s after - client disconnect, allowing reconnect with the same stream_id. +**No feature creep mid-PR.** If a contributor proposes a scope addition during review, file it as a separate PR and link from the original. The current PR keeps its original boundaries. -**Tests:** ~15 new. Total: ~216. -**Hermes CLI parity impact:** Medium (settings persistence, reliability) -**Claude parity impact:** Medium (settings panel, pinned conversations) +**Pre-release gate (mandatory).** Every release runs: +1. `pytest tests/ -q --timeout=120` clean +2. Browser sanity check (HTTP-level API tests against a test server) +3. Opus advisor pass on the merged stage diff with a written brief +4. CHANGELOG.md + ROADMAP.md + TESTING.md version stamp +5. CI green on Python 3.11 / 3.12 / 3.13 + +Skipping any of these requires a documented "I'm doing an override" from the maintainer. --- -## Sprint 13 -- Alerts, Session QoL, Polish (COMPLETED) +## Sprint shape -**Theme:** Know what Hermes is doing, and small quality-of-life wins. +A typical sprint runs 3-7 days end to end: -**Why now:** Cron jobs run silently. Background errors surface nowhere. You have -no way to know a long-running task finished (or failed) while you were on another -tab. Meanwhile, a few small UX gaps (no session duplicate, no tab title) add up -to daily friction. +| Phase | Duration | Output | +|---|---|---| +| Triage | 0.5 day | Active queue → selected items + scope notes | +| Design / spike | 0.5–1 day | Design notes for items needing them; deferrals documented | +| Build | 2–4 days | Each item on its own branch + PR for independent review | +| Review | 0.5–1 day | Maintainer + Opus advisor passes; SHOULD-FIX absorbed in-release | +| Stage + ship | 0.5 day | Stage branch, full test suite, release PR, tag, deploy, verify live | +| Hygiene | 0.5 day | Close PRs / issues, GitHub release notes, docs sync, retro | -### Track A: Bugs -- Symlink workspace validation — confirmed already fixed (`.resolve()` follows - symlinks before `is_dir()` check). - -### Track B: Features -- **Cron completion alerts:** `GET /api/crons/recent?since=TIMESTAMP` endpoint. - UI polls every 30s (only when tab is focused). Toast notification on each - completion. Red badge count on Tasks nav tab, cleared when tab is opened. -- **Background agent error alerts:** When a streaming session errors out and - the user is on a different session, show a persistent red banner above the - message area: "Session X encountered an error." Click "View" to navigate, - "Dismiss" to clear. -- **Session duplicate:** Copy icon on each session in the sidebar (visible on - hover). Creates a new session with same workspace/model, titled "(copy)". -- **Browser tab title:** `document.title` updates to show the active session - title (e.g. "My Task — Hermes"). Resets to "Hermes" when no session active. - -**Tests:** ~10 new. Total: ~221. -**Hermes CLI parity impact:** Medium (cron visibility, error surfacing) -**Claude parity impact:** Low +Smaller sprints (1–2 PRs) compress to 1–2 days end to end. Single-PR releases skip the stage branch and ship via a release PR directly off the contributor's branch (or a maintainer-rebased copy if the fork doesn't grant write access). --- -## Sprint 14 -- Visual Polish + Workspace Ops + Session Organization (COMPLETED) +## Sprint history -**Theme:** Polish the visual experience, close workspace file gaps, and -organize sessions properly. +Per-version detail is in [CHANGELOG.md](./CHANGELOG.md). High-level theme chronology is in [ROADMAP.md → Sprint History](./ROADMAP.md#sprint-history). A few notable sprints worth highlighting: -### Track B: Features -- **Mermaid diagram rendering:** Code blocks tagged `mermaid` render as - diagrams inline. Mermaid.js loaded lazily from CDN. Dark theme. Falls - back to code block on parse error. -- **Message timestamps:** Subtle HH:MM time next to each role label. Full - date/time on hover. User messages tagged with `_ts` on send. -- **Date grouping fix:** Session list uses `created_at` for groups instead - of `updated_at`. Prevents sessions jumping between groups on auto-title. -- **File rename:** Double-click any filename in the workspace panel to - rename inline (same pattern as session rename). `POST /api/file/rename`. -- **Folder create:** Folder icon button in workspace panel header. - `POST /api/file/create-dir`. Prompt for folder name. -- **Session tags:** Add `#tag` to session titles. Tags extracted and shown - as colored chips in the sidebar. Click a tag to filter the session list. -- **Session archive:** Archive button on each session (box icon). Archived - sessions hidden from sidebar by default. "Show N archived" toggle at top - of list. `POST /api/session/archive` endpoint. - -**Tests:** ~12 new. Total: ~233. -**Hermes CLI parity impact:** Medium (file rename, folder create) -**Claude parity impact:** Medium (Mermaid, tags, archive) +- **Sprint 19** — auth + security hardening. First sprint that made the app safe to leave running beyond localhost. +- **Sprint 21** — mobile responsive + Docker. Two-container compose enabled the first wave of self-host deployments. +- **Sprint 22** — multi-profile support. Major CLI-parity unlock; profile switching is now seamless without server restart. +- **Sprint 25** — macOS desktop application. Native Swift + WKWebView shell, universal Intel + Apple Silicon DMG, Sparkle 2 auto-update. Lives in the separate `hermes-webui/hermes-swift-mac` repo. +- **Sprint 26** — pluggable themes. CSS-variable-driven 8-theme system that lets community contributors add themes as pure CSS. +- **Sprint 34** — v0.50.0 UI overhaul. Composer-centric controls, Control Center modal, workspace state machine, rAF streaming throttle. --- -## Sprint 15 -- Session Projects + Code Copy + Tool Card Toggle (COMPLETED) +## Out of scope (across all sprints) -**Theme:** Organize work the way you think, not just chronologically. -Plus two quick UX wins for code and agentic workflows. +These are intentionally not on the roadmap. Listing them here to save planning cycles. -**Why now:** After 100+ sessions the sidebar is a flat chronological list. -Finding sessions from 2 weeks ago, or keeping work separated by project, -requires the search box. Session projects are the single biggest remaining -organizational gap vs. Claude's project folders. - -### Track A: Bugs -- None. - -### Track B: Features -- **Session projects:** Named groups for organizing sessions. A project - filter bar (subtle chips) sits between the search input and the session - list. Each project has a name and color. Click a chip to filter sessions - to that project; "All" shows everything. Create projects inline (+ - button), rename (double-click chip), delete (right-click). Assign - sessions via folder icon button (hover-reveal) with a dropdown picker. - Projects stored in `projects.json`. Session model gains `project_id` - field (null = unassigned). Fully backward-compatible with existing - sessions. Endpoints: `GET /api/projects`, `POST /api/projects/create`, - `POST /api/projects/rename`, `POST /api/projects/delete`, - `POST /api/session/move`. -- **Code block copy button:** Every code block gets a "Copy" button. - Positioned in the language header bar (or top-right corner for plain - code blocks). Click copies code to clipboard, shows "Copied!" for 1.5s. -- **Tool card expand/collapse:** When a message has 2+ tool cards, an - "Expand all / Collapse all" toggle appears above the card group. - Scoped per message group, not global. - -### Track C: Architecture -- `projects.json` flat file storage for project list (same pattern as - `workspaces.json` and `settings.json`). -- `project_id` field on Session model with backward-compatible null default. -- `_index.json` includes `project_id` for fast client-side filtering. - -**Tests:** 13 new. Total: ~237. -**Hermes CLI parity impact:** Low (CLI has no session organization) -**Claude parity impact:** Very High (projects are a core Claude concept) - -### Candidates for later sprints -- Artifacts + code execution (HTML/SVG preview, inline Python execution) -- Voice input via Whisper -- Subagent delegation cards (enhanced tool card rendering) +- **Multi-user collaboration** — single-user assumption throughout the codebase. Refactoring would be a from-scratch architecture change. +- **Sharing / public conversation URLs** — requires hosted backend with access control + CDN. Out of scope for self-hosted. +- **Plugin marketplace** — Hermes skills already cover this surface. +- **Anthropic / Claude proprietary features** — Projects AI memory, Claude artifacts sync. Not reproducible. +- **Linux / Windows native app wrappers** — macOS done; demand on other platforms not yet established. Web UI works in any browser. +- **App Store distribution** — sandboxing breaks the local-server model. +- **Auto-update mechanism for the Python webapp** — Sparkle 2 covers the Mac app; the webapp updates via `git pull` + restart, which is the same as every other Python service. --- -## Sprint 16 -- Session Sidebar Visual Polish (COMPLETED) +## Templates -**Theme:** Make the session list feel high-quality and delightful. +When opening a new sprint plan, copy this structure: -**Why now:** The session sidebar had two visible UX bugs: titles truncated -unnecessarily because action icons reserved space even when hidden, and -the project folder icon felt "sticky" and awkward. Emoji icons rendered -inconsistently across platforms. These were the most common visual complaints. +```markdown +# Sprint NN — -### Track A: Bugs (from BUGS.md) -- **Session title truncation.** Action icons (pin, move, archive, dup, trash) - were always in the DOM with `flex-shrink:0`, reserving ~30px even when - invisible. Fix: wrapped all actions in a `.session-actions` overlay - container with `position:absolute`. Titles now use full available width. - Actions appear on hover with a gradient fade from the right edge. -- **Folder button feels sticky.** Replaced `.has-project` persistent blue - button with a colored left border matching the project color. The folder - button now only appears in the hover overlay like all other actions. +**Version target:** vX.Y.Z +**Theme:** +**Date started:** YYYY-MM-DD +**Status:** PLANNED | IN PROGRESS | COMPLETED — vX.Y.Z -### Track B: Features -- **SVG action icons.** Replaced old symbol and emoji HTML entities - with monochrome SVG line icons that inherit `currentColor`. Consistent - rendering across macOS, Linux, and Windows. Icons: pin (star), folder, - archive (box), duplicate (overlapping squares), trash (bin with lines). -- **Pin indicator.** Small gold filled-star icon rendered inline before the - title only when the session is actually pinned. Unpinned sessions get - full title width with zero space reservation. -- **Project border indicator.** Sessions assigned to a project show a - colored left border matching the project color, replacing the old - always-visible blue folder button. -- **Hover overlay polish.** Actions container uses a gradient background - that fades from transparent to the sidebar color, creating a smooth - emergence effect. Overlay hides automatically during inline rename. +## Items +| # | Issue | Title | Complexity | Files | PR | +|---|-------|-------|------------|-------|-----| -### Deferred to Sprint 17 -- Slash commands (basic set with `commands.js` module) -- Thinking/reasoning display for extended-thinking models -- Slash command autocomplete popup +## Rationale +Why these items, why now. -**Tests:** 74 new (test_sprint16.py: safe HTML rendering, XSS security, sidebar polish). Total: 289. -**Hermes CLI parity impact:** Low -**Claude parity impact:** Medium (sidebar polish matches Claude's quality bar) +## Build approach +Per-item branch + PR; or single combined branch if items are tightly coupled. ---- +## Out of scope +What did NOT make this sprint and why. -## Sprint 17 -- Workspace Polish + Slash Commands + Settings (COMPLETED) +## Known risks +Sharp edges to watch during review. -**Theme:** Workspace polish, slash commands, and composer settings. +## PR Status +| Issue | PR | Status | +|-------|-----|--------| -**Why now:** Three things converge: @nothingmn filed Issue #22 requesting a -tree/accordion workspace view (breadcrumb navigation is the foundation for -that), slash commands were deferred from Sprint 16, and Issue #26 (send key -personalization) fits naturally since we are already touching the keydown -handler for slash command autocomplete. - -### Track A: Workspace Breadcrumb Navigation -- **Breadcrumb path bar.** When users click into subdirectories, a breadcrumb - bar appears showing the path (e.g. `~ / src / components`) with clickable - segments to navigate back. Hidden at root level for a clean UI. -- **Up button.** Arrow-up button in the panel header navigates to the parent - directory. Hidden when already at workspace root. -- **Current directory tracking.** `S.currentDir` state property tracks the - active directory. File operations (rename, delete, new file, new folder) - stay in the current directory instead of jumping back to root. -- **New file/folder in subdirectories.** Creating files or folders now respects - the current directory, creating them in the viewed subdirectory. - -### Track B: Slash Commands Foundation -- **commands.js module.** New 7th JS module with command registry, parser, - autocomplete dropdown, and built-in command handlers. -- **Built-in commands:** `/help` (list commands), `/clear` (clear conversation), - `/model ` (switch model with fuzzy match), `/workspace ` (switch - workspace), `/new` (start new session). -- **Autocomplete dropdown.** Typing `/` in the composer shows a filtered - dropdown. Arrow keys navigate, Tab/Enter select, Escape closes. Positioned - above the composer using the workspace dropdown CSS pattern. -- **Transparent pass-through.** Unrecognized `/` commands pass through to the - agent normally (not intercepted). - -### Track C: Send Key Setting (Issue #26) -- **`send_key` setting.** New setting in Settings panel: "Enter" (default) or - "Ctrl+Enter". Persisted to `settings.json`. Loaded on boot. -- **Keydown handler rewrite.** Combined handler for autocomplete navigation - and send key preference. When `ctrl+enter` is selected, plain Enter inserts - a newline and Ctrl/Cmd+Enter sends. - -### Deferred to Sprint 18 -- Thinking/reasoning display for extended-thinking models -- Voice input via Whisper -- Workspace tree/accordion view (full implementation of Issue #22) - -**Tests:** 6 new (test_sprint17.py). Total: 318. -**Hermes CLI parity impact:** Low (slash commands add convenience) -**Claude parity impact:** Medium (workspace nav, slash commands match Claude UX) - ---- - -## Sprint 18 -- Thinking Display + Workspace Tree + Preview Fix (COMPLETED) - -**Theme:** Show the model's reasoning, improve workspace navigation, fix UX bug. - -**Why now:** Thinking/reasoning display was deferred twice (Sprint 16 → 17 → 18). -Workspace tree view was the #1 community request (Issue #22). File preview -staying open on directory navigation was a daily-driver annoyance. - -### Track A: Bugs -- **File preview auto-close.** When viewing a file in the right panel and - navigating directories (breadcrumbs, up button, folder clicks), the preview - stayed visible with stale content. Fix: extracted `clearPreview()` as a named - function in boot.js and call it from `loadDir()` in workspace.js. - -### Track B: Features -- **Thinking/reasoning display.** Assistant messages with structured content - arrays containing `type:'thinking'` or `type:'reasoning'` blocks now render - as collapsible gold-themed cards above the response text. Collapsed by - default, click header to expand. Works with Claude extended thinking and - o3 reasoning tokens when preserved in the message array. -- **Workspace tree view (Issue #22).** Directories expand/collapse in-place - with toggle arrows. Single-click toggles, double-click navigates (breadcrumb - view). Subdirectory contents fetched lazily and cached in `S._dirCache`. - Nesting depth shown via indentation. Empty directories show "(empty)". - -**Tests:** 0 new (pure CSS/DOM changes). Total: 318. -**Hermes CLI parity impact:** Low -**Claude parity impact:** High (reasoning display matches Claude's UI) - ---- - -## Sprint 19 -- Auth + Security Hardening (COMPLETED) - -**Theme:** Make this safe to leave running beyond localhost. - -**Why now:** Issue #23 requested authentication. Auth is the last production -hardening feature before the app is safe to expose to a network. - -### Track A: Bugs -- **No request size limit.** POST bodies were unbounded (DoS risk). Added 20MB - cap in `read_body()`. - -### Track B: Features -- **Password authentication (Issue #23).** Off by default — zero friction for - localhost. Enable via `HERMES_WEBUI_PASSWORD` env var or Settings panel. - Password-only (no username — single-user app). Signed HMAC HTTP-only cookie - with 24h TTL. Minimal dark-themed login page at `/login`. API calls without - auth return 401; page loads redirect to `/login`. Settings panel gains - "Access Password" field and "Sign Out" button. -- **Security headers.** All responses now include `X-Content-Type-Options: nosniff`, - `X-Frame-Options: DENY`, `Referrer-Policy: same-origin`. - -### Track C: Architecture -- New `api/auth.py` module: password hashing (SHA-256 + STATE_DIR salt), signed - session cookies, auth middleware, public path allowlist. -- Auth check in `server.py` do_GET/do_POST before routing. -- `password_hash` added to `_SETTINGS_DEFAULTS` in config.py. -- `_set_password` special field in save_settings for secure password updates. - -**Tests:** 10 new. Total: 328. -**Hermes CLI parity impact:** Low (CLI has no auth concerns) -**Claude parity impact:** High (Claude is authenticated) - ---- - -## Sprint 20 -- Voice Input + Send Button Polish (COMPLETED) - -**Theme:** Input refinements — voice and visual polish. - -**Why now:** Voice input was the next feature on the roadmap. The send button -UX was a low-effort high-impact polish opportunity that pairs naturally. - -### Track A: Bugs -- **Send button always visible.** The old pill-shaped "Send" button was always - visible even with an empty textarea, wasting space. Now hidden by default, - appears only when there is content to send. - -### Track B: Features -- **Voice input (Web Speech API).** Microphone button in composer. Tap to - record, tap again to stop. Live interim transcription in textarea. Auto-stops - after ~2s of silence. Appends to existing text. Hidden when browser doesn't - support Web Speech API. No API keys, no server changes. -- **Send button polish.** Icon-only 34px circle with upward arrow SVG. Pop-in - spring animation on appear. Scale hover/active for tactile feedback. Hidden - while agent is responding. - -### Track C: Architecture -- Voice input IIFE in `boot.js` with SpeechRecognition lifecycle. -- `updateSendBtn()` in `ui.js` hooked into setBusy, renderTray, autoResize. - -**Tests:** 52 new (voice) + 33 new (send button). Total: 415. -**Hermes CLI parity impact:** Medium (voice not in CLI, but adds capability) -**Claude parity impact:** High (Claude has native voice mode) - ---- - -## Sprint 21 -- Mobile Responsive + Docker (COMPLETED) - -**Theme:** Mobile experience + containerized deployment. - -**Why now:** Issue #21 (mobile) was the most-requested UX gap. Issue #7 (Docker) -enables deployment beyond localhost. Both were achievable without new dependencies. - -### Track A: Bugs (from review) -- **CSS cascade broke mobile slide-in.** `position:relative` after the media query - overrode `position:fixed`. Wrapped in `@media(min-width:641px)`. -- **mobileSwitchPanel() always reopened sidebar.** Chat tab now closes it. -- **Dockerfile missing pip install.** Container failed on startup. -- **No .dockerignore.** `.git`, `tests/`, `.env*` leaked into images. -- **docker-compose tilde expansion.** `~` doesn't expand in Compose defaults. - -### Track B: Features -- **Hamburger sidebar.** Slide-in overlay on mobile, tap outside to close. -- **Bottom navigation bar.** 5-tab iOS-style bar replaces sidebar tabs. -- **Files slide-over.** Right panel opens as slide-over from right edge. -- **Touch targets.** Minimum 44px on all interactive elements. -- **Docker support.** Dockerfile, docker-compose.yml, .dockerignore. - -### Track C: Architecture -- Mobile nav functions in `boot.js`. Session click auto-closes sidebar. -- 69 new CSS lines scoped to `@media(max-width:640px)`. -- Desktop layout untouched — all mobile elements `display:none` by default. - -**Tests:** 0 new (CSS/DOM changes). Total: 415. -**Hermes CLI parity impact:** Low -**Claude parity impact:** High (Claude has mobile layout) - ---- - -## Sprint 22 -- Multi-Profile Support (COMPLETED, Issue #28) - -**Theme:** Switch between Hermes agent profiles seamlessly from the web UI. - -**Why now:** Issue #28 requested full profile management in the UI. The CLI has -had comprehensive profile support since v0.6.0 — isolated instances with their -own config, skills, memory, cron, and API keys. The web UI was locked to a -single default profile, blocking multi-persona workflows. - -### Track A: Bugs -- **Hardcoded `~/.hermes` paths.** Memory read/write in routes.py and model - discovery in config.py used hardcoded paths instead of the active profile's - directory. Fixed to resolve through `get_active_hermes_home()`. -- **Module-level cached paths.** hermes-agent's `skills_tool.py` and `cron/jobs.py` - snapshot `HERMES_HOME` at import time. Profile switch now monkey-patches these - cached variables (`SKILLS_DIR`, `CRON_DIR`, `JOBS_FILE`, `OUTPUT_DIR`). - -### Track B: Features -- **Profile picker (topbar).** Purple-accented chip with SVG user icon in the - topbar. Click opens a dropdown listing all profiles with gateway status dots, - model info, and skill count. Click to switch; "Manage profiles" link opens - the management panel. -- **Profiles sidebar panel.** New nav tab with full management UI. Cards show - each profile with model, provider, skill count, API key status, and gateway - badge. "Use" button to switch, delete button for non-default profiles. -- **Profile creation.** "+ New profile" form with name validation (lowercase - alphanumeric + hyphens), optional "clone config from active" checkbox. Wraps - `hermes_cli.profiles.create_profile()`. -- **Profile deletion.** Confirm dialog, auto-switches to default if deleting - the active profile. Blocked while agent is running. -- **Seamless switching.** No server restart required. Profile switch updates - `HERMES_HOME` env var, patches module-level caches, reloads `.env` API keys, - reloads `config.yaml`, and refreshes the model dropdown, skills, memory, and - cron panels. -- **Per-session profile tracking.** New `profile` field on Session records which - profile was active when the session was created. Backward-compatible (defaults - to `null` for old sessions). - -### Track C: Architecture -- New `api/profiles.py` module (~200 lines): profile state management wrapping - `hermes_cli.profiles`. Thread-safe with `_profile_lock`. Lazy imports to - avoid circular dependencies. -- `api/config.py`: Replaced module-level `cfg` dict with reloadable - `get_config()`/`reload_config()`. Dynamic `_get_config_path()` resolves - through active profile. -- `api/streaming.py`: `HERMES_HOME` added to env save/restore block around - agent runs (alongside `TERMINAL_CWD`, `HERMES_EXEC_ASK`). -- Profile switch blocked while any agent stream is active (process-global - `HERMES_HOME` cannot be changed mid-run). -- Zero modifications to hermes-agent code required. - -**Tests:** 0 new (profile management requires hermes-agent integration). Total: 415. -**Hermes CLI parity impact:** Very High (profile support is a major CLI feature) -**Claude parity impact:** Low (Claude has no profile concept) - ---- - -## Sprint 23 -- Agentic Transparency + Context Visibility (COMPLETED) - -**Theme:** Surface what the agent is doing and how much context it's using. - -**Why now:** Users had no visibility into tool call arguments, session token -usage, or context window fill. Sprint 22 left five coherence bugs in the -profile/workspace/model flow that also needed closing before the UI felt -reliable. - -### Track A: Bugs -- **Model picker ignores profile on switch.** `populateModelDropdown()` skipped - the profile's default model if `localStorage` had a saved preference. Fixed: - `switchToProfile()` now clears `hermes-webui-model` from localStorage and - applies the profile's default model from the switch response. -- **Workspace list is a global file.** `workspaces.json` was process-global. - Fixed: workspace storage is now profile-local at `{profile_home}/webui_state/`. - Default profile uses global STATE_DIR for backward compatibility. -- **`DEFAULT_WORKSPACE` is a startup singleton.** Frozen at boot. Fixed: - `get_last_workspace()` and `_profile_default_workspace()` now resolve - dynamically through the active profile's config. -- **Session list shows all profiles.** Fixed: `renderSessionListFromCache()` - filters to `S.activeProfile` by default, with "Show N from other profiles" - toggle (modeled on the archived toggle). -- **`switchToProfile()` doesn't refresh workspace list or sessions.** Fixed: - now calls `loadWorkspaceList()`, `renderSessionList()`, resets profile filter. - -### Track B: Features -- **Profile-local workspace storage.** Each named profile stores its own - `workspaces.json` and `last_workspace.txt` under `{profile_home}/webui_state/`. - Falls back to global STATE_DIR for the default profile (preserves test - isolation and backward compat). -- **Profile switch returns defaults.** `POST /api/profile/switch` response now - includes `default_model` and `default_workspace` so the frontend can apply - both in one round-trip. -- **Session profile filter.** Session sidebar filters to active profile by - default. "Show N from other profiles" toggle reveals sessions from all - profiles. Resets on profile switch. - -### Track C: Architecture -- `api/workspace.py`: Rewritten with `_profile_state_dir()`, `_workspaces_file()`, - `_last_workspace_file()`, `_profile_default_workspace()`. All lazy imports to - avoid circular deps. -- `api/profiles.py`: `switch_profile()` returns `default_model` and - `default_workspace` from the new profile's config.yaml. -- `static/panels.js`: `switchToProfile()` clears localStorage model key, - refreshes workspace list and session list, resets profile filter. -- `static/sessions.js`: `_showAllProfiles` state variable, profile filter in - `renderSessionListFromCache()`, toggle UI. - -**Tests:** 8 new (test_sprint23.py). Total: 423. -**Hermes CLI parity impact:** High (coherent profile behavior) -**Claude parity impact:** Low - ---- - -## Sprint 24 -- Web Polish + Bug Fix Pass (PLANNED) - -**Theme:** Stabilize, harden, and close the last meaningful web UI gaps before -shifting focus to distribution. Goal is a release that's genuinely ready for -wider user adoption -- no rough edges, no obvious missing pieces. - -**Why now:** Sprint 23 completed the core agentic transparency features. The -remaining web roadmap items are diminishing-returns polish. Rather than -grinding through marginal features, this sprint cleans up what's there, fixes -bugs users will actually hit, and closes a few real gaps before recommending -the app to others. - -### Track A: Bug Fixes -- **Cron edit form has no skill picker.** Sprint 23 added skill picker to the - create form but not the edit form. cronEditSave() doesn't include skills in - the update body, so existing skills survive an edit but can't be changed. - Fix: add the same skill picker UI to the inline edit form and include - `skills` in the update POST body. -- **S.lastUsage dead code.** messages.js sets `S.lastUsage` from `d.usage` at - done-time, but nothing reads it. The usage badge reads cumulative session - totals from `S.session.input_tokens` instead. Either wire `S.lastUsage` into - a per-turn display or remove the dead assignment. -- **_cronSkillsCache never invalidated.** Skills picker shows stale data if - skills are added/removed mid-session. Add a cache-bust when the skills panel - is opened or a skill is saved/deleted. -- **Tool args not shown on session reload.** Tool call cards in history show - name and result snippet but not the args (args only exist in the live SSE - event). Sprint 23 added args to the session JSON -- verify they're actually - rendering in the settled history cards. - -### Track B: Features -- **Cron edit: skill picker parity.** As above -- make create and edit forms - identical in capability. -- **Per-turn cost display.** The current usage badge shows cumulative session - totals attached to the last message, which is misleading. Either: (a) show - per-turn cost from `S.lastUsage` immediately after each response instead of - cumulative, or (b) show cumulative in the session topbar/header instead of - attached to a message bubble. Pick the cleaner UX. -- **Virtual scroll for long session/skill lists.** When session count or skill - count gets large (100+), the sidebar becomes sluggish. Add a simple virtual - scroll or windowed render -- only render visible items + a buffer above/below. - CSS `contain: strict` + IntersectionObserver approach, no library needed. - -### Track C: Code Quality -- Audit and remove any remaining dead code introduced by Sprint 23 (e.g. `S.lastUsage` assignment in messages.js that nothing reads). -- Verify tool call args render correctly in settled history cards on session reload. -- Update test count in all docs to match actual pytest output after sprint merges. - -**Estimated tests:** ~10 new. Target total: ~435. -**Hermes CLI parity impact:** Low -**Claude parity impact:** Low -**User-facing value:** Medium -- removes rough edges that would bother new users - ---- - -## Sprint 25 -- macOS Desktop Application (PLANNED) - -**Theme:** Native Mac desktop app. Single download, runs entirely offline, -feels like a real application -- not a browser tab. - -**Why this matters:** The web UI requires an SSH tunnel or a server setup to -use. A .app bundle that a user can double-click and immediately have a working -Hermes interface is genuinely differentiating. No other open-source Hermes -interface ships as a native Mac app. This is the highest-leverage remaining -investment for user adoption. - -**Approach: Swift + WKWebView (not Electron)** - -The right architecture is a thin native Swift shell (~300-500 lines) that: -1. Bundles the existing Python server and all api/ modules inside the .app -2. Spawns the server as a subprocess on a random local port at launch -3. Opens a WKWebView window pointed at that localhost port -4. Handles Mac app lifecycle natively (dock icon, cmd+Q, window management, - app menu, about box) -5. Bridges a small set of native Mac capabilities that WKWebView can't do - -**Why not Electron:** WKWebView is Safari's engine -- dramatically lighter than -Chromium. No 200MB node_modules. No separate update daemon. The .app is ~30MB -including the Python runtime, vs 150MB+ for Electron. - -**Why not full native Swift UI:** Would require rewriting the entire frontend -from scratch. The web UI is already fast, dark-themed, and feature-complete. -The thin shell approach gets 95% of the benefit at 5% of the cost. - -### Track A: Swift App Shell - -**Files to create:** -``` -desktop/ - HermesApp.swift -- @main entry point, NSApp delegate - AppDelegate.swift -- lifecycle: start server on launch, stop on quit - WindowController.swift -- NSWindow + WKWebView setup, cmd shortcuts - ServerManager.swift -- spawn/monitor Python subprocess, pick free port - MenuBuilder.swift -- native app menu (File, Edit, View, Window, Help) - Info.plist -- bundle ID, display name, version, icon - Assets.xcassets/ -- app icon (1024x1024 + all required sizes) - HermesApp.xcodeproj/ -- Xcode project file +## Retro (post-ship) +What worked, what we'd do differently. ``` -**ServerManager.swift responsibilities:** -- Find Python: check bundled runtime first, fall back to system python3 -- Pick a free port (bind to :0, read assigned port, close, use it) -- Spawn: `python3 server.py --port {port}` as a child Process -- Monitor: if server crashes, show an error sheet and offer restart -- Shutdown: SIGTERM on app quit, wait up to 3s, then SIGKILL - -**WKWebView configuration:** -- `allowsBackForwardNavigationGestures = false` (it's a single-page app) -- `WKUserContentController` for JS bridge (native notifications, file picker) -- Wait for server health check before loading (poll /health, show loading - spinner in the native window while waiting, typically <1s) -- `userAgent` override so the server can detect desktop app context - -**Native menu items (beyond defaults):** -- File > New Session (Cmd+N) -- calls JS `newSession()` -- File > New Window (Cmd+Shift+N) -- opens second window with its own WKWebView -- View > Toggle Sidebar (Cmd+Shift+S) -- Window > Zoom, Minimize (standard) -- Help > About Hermes, Check for Updates (links to GitHub releases page) - -### Track B: Python Bundling - -Two options, in order of preference: - -**Option A: Require system Python (simpler, recommended for v1)** -- Check for `python3` at known paths: `/usr/bin/python3`, homebrew paths, - pyenv paths -- If not found: show a one-time setup sheet with instructions -- Pros: tiny download (~5MB for the Swift app + web assets), no bundling complexity -- Cons: user needs Python installed (most developers do; target audience does too) - -**Option B: Bundle python-standalone (self-contained, larger)** -- Use `python-build-standalone` (from Astral/uv project): pre-built Python - 3.11 binaries, ~30MB compressed, no Xcode toolchain needed to build -- Extract to `~/Library/Application Support/Hermes/python/` on first launch -- Install `requirements.txt` via bundled pip into a local venv -- Pros: zero dependencies, works on a clean Mac -- Cons: first launch takes ~10-20s for extraction + pip install; ~30MB download - -**Recommendation:** Ship v1 with Option A. Add Option B as an optional -"standalone" download for non-developers. - -### Track C: Distribution - -**GitHub Releases (primary):** -- Build with `xcodebuild -scheme HermesApp -configuration Release -archivePath` -- `xcodebuild -exportArchive` to produce a .app bundle -- `hdiutil create` to produce a .dmg with drag-to-Applications installer UI -- Upload .dmg as a GitHub Release asset via `gh release create` -- CI: add `.github/workflows/mac-release.yml` -- trigger on `vX.Y.Z-mac` tag - -**Code signing:** -- Without an Apple Developer account: distribute as unsigned, users must - right-click > Open on first launch (standard for open-source Mac apps) -- With a free Apple Developer account: ad-hoc signing removes the Gatekeeper - warning without paying $99/year (no notarization, but much better UX) -- With paid account ($99/year): full notarization, no warnings, direct download - -**Recommended for v1:** ad-hoc signing (free, good enough for early adopters). -Document the right-click > Open workaround in the README for unsigned builds. - -**Universal binary (Intel + Apple Silicon):** -```bash -xcodebuild archive -scheme HermesApp -destination "generic/platform=macOS" -``` -Both architectures in one .app. No separate downloads needed. - -### Track D: Native Integrations (v1 scope) - -**System notifications for cron completion:** -- The web UI polls `/api/cron/alerts` and shows in-page banners -- The Mac app can additionally post `UNUserNotificationCenter` notifications -- JS bridge: `window.webkit.messageHandlers.notify.postMessage({title, body})` -- Swift handler: posts a native notification with the cron job name and output - summary -- appears in Notification Center, works even when app is in background - -**File picker for workspace add:** -- Currently: user types a path string into the workspace add form -- Mac app: intercept workspace-add form submission, open `NSOpenPanel` instead, - return the selected path to the JS via `evaluateJavaScript` -- Much better UX -- standard Mac folder picker, no typing paths - -**Dock badge for pending approvals:** -- When an agent approval is waiting, set `NSApp.dockTile.badgeLabel = "1"` -- Clear badge when approval is resolved -- JS bridge fires when approval card appears/disappears - -**Menu bar mode (optional, v2):** -- A small status bar item (beaker icon in menu bar) that opens a compact popover -- Popover shows current session status, last message, quick-compose field -- Useful for running Hermes in the background without a full window - -### Track E: Testing - -Since the Swift app is thin glue, most testing remains in the existing pytest -suite (server still runs identically). New Swift-specific tests: -- `ServerManagerTests.swift`: verify port picking, process spawn, health wait -- UI tests via `XCUITest`: launch app, wait for WKWebView to load, verify - title bar shows "Hermes", verify /health responds -- Smoke test in CI: `xcodebuild test -scheme HermesApp` - -### Implementation Order - -1. `ServerManager.swift` + basic `AppDelegate` -- get Python server spawning - and health-check working from Swift -2. `WindowController.swift` -- WKWebView loading, loading spinner while - server starts -3. App icon + Info.plist -- make it look like a real app -4. `MenuBuilder.swift` -- native menus + keyboard shortcuts -5. JS bridge for notifications -- most impactful native integration -6. DMG build script + GitHub Actions CI -7. (Optional) File picker bridge, dock badge - -### What to NOT do in v1 - -- Windows or Linux wrapper (different toolchain; do Mac first, assess demand) -- Full Swift/SwiftUI rewrite of the frontend (months of work, wrong tradeoff) -- App Store submission (sandboxing breaks local server; not worth the effort) -- Auto-update mechanism (GitHub releases + manual download is fine for v1) -- Menu bar mode (cool but not v1 scope) - -### Files to create in the repo - -``` -desktop/mac/ - HermesApp/ - HermesApp.swift - AppDelegate.swift - WindowController.swift - ServerManager.swift - MenuBuilder.swift - Assets.xcassets/ - Info.plist - HermesApp.xcodeproj/ - README.md -- build instructions, requirements, signing notes -.github/workflows/ - mac-release.yml -- build + sign + upload DMG on tag push -``` - -The server code (`server.py`, `api/`, `static/`, `requirements.txt`) is -referenced from the repo root -- no duplication. The .app bundle copies them -at build time. - -**Estimated effort:** 2-3x a typical web sprint (new language, new toolchain, -bundling complexity). Realistic for a focused weekend or a dedicated agent run -with clear instructions. - -**Hermes CLI parity impact:** N/A (different distribution channel) -**Claude parity impact:** Medium (Claude.app is a native Mac app) -**User-facing value:** Very high -- lowers barrier to entry dramatically, -genuinely differentiating for an open-source project - ---- - -## Feature Parity Summary - -### Hermes CLI Parity (as of Sprint 19) - -| CLI Feature | Status | -|-------------|--------| -| Chat / agent loop | Done (v0.3) | -| Streaming responses | Done (v0.5) | -| Tool call visibility | Done (v0.11) | -| File ops (read/write/search/patch) | Done (v0.6) | -| Terminal commands | Done via workspace | -| Cron job management | Done (v0.9) | -| Skills management | Done (v0.9) | -| Memory read/write | Done (v0.9) | -| Session history | Done (v0.3) | -| Workspace switching | Done (v0.7) | -| Model selection | Done (v0.3) | -| Multi-provider model support | Done (Sprint 11) | -| Settings persistence | Done (Sprint 12) | -| Cron completion alerts | Done (Sprint 13) | -| Slash commands | Done (Sprint 17) | -| Thinking/reasoning display | Done (Sprint 18) | -| Auth / login | Done (Sprint 19) | -| Voice input | Done (Sprint 20) | -| Multi-profile support | Done (Sprint 22) | -| Subagent visibility | Deferred | -| Code execution (Jupyter) | Deferred | -| Toolset control | Deferred | -| Virtual scroll (perf) | Deferred | - -### Claude Parity (as of Sprint 19) - -| Claude Feature | Status | -|----------------|--------| -| Dark theme, 3-panel layout | Done (v0.1) | -| Streaming chat | Done (v0.5) | -| Model switching | Done (v0.3) | -| File attachments | Done (v0.6) | -| Syntax highlighting | Done (v0.10) | -| Tool use visibility | Done (v0.11) | -| Edit/regenerate messages | Done (v0.10) | -| Session management | Done (v0.6) | -| Mermaid diagrams | Done (Sprint 14) | -| Projects / folders | Done (Sprint 15) | -| Pinned/starred sessions | Done (Sprint 12) | -| Notifications | Done (Sprint 13) | -| Settings panel | Done (Sprint 12) | -| Reasoning display | Done (Sprint 18) | -| Auth / login | Done (Sprint 19) | -| Mobile layout (basic) | Done (v0.16.1) | -| Workspace tree view | Done (Sprint 18) | -| Slash commands | Done (Sprint 17) | -| Voice input | Done (Sprint 20) | -| TTS playback | Deferred | -| Artifacts (HTML/SVG preview) | Deferred | -| Code execution inline | Deferred | -| Mobile-optimized layout | Done (Sprint 21) | -| Sharing / public URLs | Not planned (requires server infra) | -| Claude-specific features | Not replicable (Projects AI, artifacts sync) | - -### What is intentionally not planned - -- **Sharing / public conversation URLs:** Requires a hosted backend with access - control and CDN. Out of scope for a personal VPS deployment. -- **Claude-specific model features:** Claude-native Projects memory, extended - artifacts sync, Anthropic's proprietary reasoning UI. These are Anthropic - infrastructure, not reproducible. -- **Real-time collaboration:** Multiple users in the same session simultaneously. - Single-user assumption throughout. -- **Plugin marketplace:** Hermes skills cover this use case already. - ---- - -## Sprint 26 -- Pluggable UI Themes (COMPLETED) - -**Theme:** Let users choose how the app looks -- light, dark, and custom color -schemes. One-click switching, persistent preference, zero flicker on load. - -**Difficulty: Low-Medium.** The existing CSS is already 100% CSS-variable-driven -off a single `:root` block. Every color, background, and accent in the entire UI -is already a variable. Adding themes is mostly a matter of defining alternative -`:root` overrides and wiring a picker -- not a rewrite. The main engineering -work is flicker prevention on load and the settings UI. - -**Estimated effort:** 1 sprint, ~2 days of implementation. 8-12 new tests. - ---- - -### Why now - -The UI ships only one dark theme. Contributors have asked for light mode. Power -users want to match their terminal colorscheme. This is low-risk, high-value -polish that makes the app feel more finished and more personal. It's also a -good precedent-setter: once the theme system exists, community members can -contribute new themes as a pure CSS addition with no Python changes needed. - ---- - -### Design decisions - -**Themes are CSS-variable overrides, not separate stylesheets.** Each theme is -a named `:root[data-theme="name"]` block. The base stylesheet stays untouched. -Switching themes sets `document.documentElement.dataset.theme = name` in JS. -No FOUC (flash of unstyled content), no stylesheet swap latency. - -**Theme preference persists server-side in `settings.json`.** Same mechanism -as `send_key` and `show_token_usage`. The server includes `theme` in the -`GET /api/settings` response. Boot.js reads it and applies before first paint. - -**Flicker prevention.** A tiny inline ` -``` - -This runs synchronously before the stylesheet parses. Zero flicker. - -**3. Theme loading in `static/boot.js`** - -In the existing `api('/api/settings')` call, read and apply the theme: - -```js -const s = await api('/api/settings'); -window._sendKey = s.send_key || 'enter'; -window._showTokenUsage = !!s.show_token_usage; -window._showCliSessions = !!s.show_cli_sessions; -// Theme: apply server preference, update localStorage for flicker prevention -const theme = s.theme || 'dark'; -document.documentElement.dataset.theme = theme; -localStorage.setItem('hermes-theme', theme); -``` - -**4. Theme setting in `api/config.py`** - -```python -_SETTINGS_DEFAULTS = { - ... - 'theme': 'dark', # active UI theme name - ... -} -_SETTINGS_ALLOWED_KEYS = set(_SETTINGS_DEFAULTS.keys()) - {'password_hash'} -``` - -No enum constraint on `theme` -- allows user-defined theme names to work -without server changes. - ---- - -### Track B: Theme picker UI - -**Settings panel addition (`static/index.html` + `static/panels.js`)** - -A ` - - - - - - - -``` - -In `loadSettingsPanel()`: -```js -const themeSel = $('settingsTheme'); -if(themeSel) themeSel.value = settings.theme || 'dark'; -``` - -In `saveSettings()`: -```js -body.theme = $('settingsTheme').value; -``` - -**Live preview on select change (no save required):** -```js -$('settingsTheme').addEventListener('change', e => { - document.documentElement.dataset.theme = e.target.value; - localStorage.setItem('hermes-theme', e.target.value); -}); -``` - -This gives instant visual feedback as the user clicks through options. -The full settings save then persists it server-side. - -**`/theme` slash command (`static/commands.js`)** - -```js -async function cmdTheme(arg) { - const themes = ['dark','light','solarized','monokai','nord']; - if(!arg || !themes.includes(arg)) { - showToast('Usage: /theme dark|light|solarized|monokai|nord'); - return; - } - document.documentElement.dataset.theme = arg; - localStorage.setItem('hermes-theme', arg); - try { await api('/api/settings', {method:'POST', body: JSON.stringify({theme: arg})}); } catch(e) {} - showToast('Theme: ' + arg); -} -``` - ---- - -### Track C: Tests - -New test cases in `tests/test_sprint26.py`: - -1. `GET /api/settings` returns `theme: 'dark'` by default -2. `POST /api/settings` with `{theme: 'light'}` persists and round-trips -3. `POST /api/settings` with `{theme: 'nord'}` accepts any string (no enum gate) -4. Theme value survives server restart (reads from `settings.json`) -5. `/theme` command fires without error for each named theme -6. `loadSettingsPanel()` populates the select with the current theme value -7. Settings save includes theme in the POST body -8. `data-theme` attribute is set on `` before first paint (inline script) - -**Estimated new tests:** 8. Target total after sprint: ~443. - ---- - -### What's out of scope - -- **Custom color editors** (hex pickers for each variable): saves that for v2. - The five shipped themes cover the main use cases. A custom theme can always - be added by dropping a CSS block with no code changes. -- **Per-session themes**: single global preference is the right call for v1. -- **System `prefers-color-scheme` sync**: nice-to-have, low priority. The - flicker-prevention script could be extended to read the media query if no - explicit preference is set. -- **Prism.js theme switching**: the code-block syntax highlighting comes from - a CDN stylesheet. Swapping it requires a `` swap and SRI re-check. - Defer to a future sprint; the default Prism Tomorrow theme works on all - current dark themes and is acceptable on light. - ---- - -**Estimated tests:** 8 new. Target total: ~443. -**Hermes CLI parity impact:** None -**Claude parity impact:** Medium (Claude.ai has light/dark/system sync) -**User-facing value:** High -- first thing many users ask for - ---- - -*Last updated: April 12, 2026* -*Current version: v0.49.1 | 700 tests* -*Next sprint: Sprint 24 (Web Polish + Bug Fix Pass)* -*Horizon sprint: Sprint 25 (macOS Desktop Application)* -*Docs sweep policy: update markdown proactively during PR reviews and after significant releases* +The maintainer's planning notes for each sprint live in the workspace repo (private), not in this file. This file is the public-facing planning shape. diff --git a/TESTING.md b/TESTING.md index 1e9fb5df..532502fa 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1836,7 +1836,7 @@ Bridged CLI sessions: --- *Last updated: v0.50.281, May 03, 2026* -*Total automated tests collected: 3990* +*Total automated tests collected: 3995* *Regression gate: tests/test_regressions.py* *Run: pytest tests/ -v --timeout=60* *Source: /*