Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
88f2eaf
Polish workspace panel behavior and app dialogs
aronprins Apr 11, 2026
0a6e4b1
Replace remaining emoji UI glyphs with Lucide icons
aronprins Apr 11, 2026
5b5d1f5
Redesign composer footer around model and context controls
aronprins Apr 10, 2026
bbd1bde
Remove obsolete activity bar
aronprins Apr 11, 2026
0933b89
Move workspace and model switching into composer footer
aronprins Apr 10, 2026
d291cb1
Move profile switching into composer footer
aronprins Apr 10, 2026
9e0ace5
Refactor Hermes control center UI
aronprins Apr 11, 2026
39c2003
Redesign control center settings modal layout
aronprins Apr 11, 2026
e891eb8
Put session item actions in a dropdown
aronprins Apr 11, 2026
2fb7bd4
Use Hermes mark in sidebar control button
aronprins Apr 11, 2026
aa4a7a3
Reset control center section on close
aronprins Apr 11, 2026
b2c5213
Drop session-item left border indicator
aronprins Apr 11, 2026
f6fc9c9
Increase session search input vertical padding
aronprins Apr 11, 2026
6ff9601
Normalise odd pixel values across UI
aronprins Apr 11, 2026
99a5a36
Add missing #btnMobileFiles button and .mobile-files-btn CSS (for mob…
aronprins Apr 11, 2026
bfaf441
Improve composer footer mobile responsiveness and UX
aronprins Apr 12, 2026
dbd7c28
Fix duplicate files button and broken workspace close on mobile
aronprins Apr 12, 2026
26f34a2
Fix model chip icon vertical alignment in composer footer
aronprins Apr 12, 2026
76dd808
Fix workspace toggle button hidden on desktop by conflicting CSS class
aronprins Apr 12, 2026
6736fd0
Fix session actions dots button inaccessible on mobile sidebar
aronprins Apr 12, 2026
3d51858
Fix composer footer manage links not opening sidebar panel
aronprins Apr 12, 2026
0056654
Widen icon-only composer chips breakpoint from 400px to 768px
aronprins Apr 12, 2026
ef015db
Fix composer-left vertical scrollbar by setting overflow-y:hidden
aronprins Apr 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@

The Hermes Web UI is a lightweight web application that gives you a browser-based
interface to the Hermes agent that is functionally equivalent to the CLI. It is modeled on
the Claude-style interface: a three-panel layout with a sidebar for session management,
a central chat area, and a right panel for workspace file browsing.
the Claude-style interface: a sidebar for session management, a central chat area,
and a demand-driven right panel used for workspace browsing and preview surfaces.
The right panel is closed by default on desktop and opens only when it is actively
being used for browsing or previewing content.

The design philosophy is deliberately minimal. There is no build step, no bundler, no
frontend framework. The Python server is split into a routing shell (server.py) and
business logic modules (api/). The frontend is seven vanilla JS modules loaded from static/.
This makes the code easy to modify from a terminal or by an agent.

Hermes-level chrome is intentionally consolidated: the sidebar has no dedicated brand header.
Instead, the footer exposes a single "Hermes WebUI" launch button that opens one tabbed
control-center modal for global preferences, conversation import/export, and clear-conversation
actions. The topbar remains focused on conversation context and the workspace/files toggle.

---

## 2. File Inventory
Expand Down Expand Up @@ -51,7 +58,7 @@ This makes the code easy to modify from a terminal or by an agent.
style.css All CSS incl. mobile responsive (~670 lines)
ui.js DOM helpers, renderMd, tool cards, model dropdown, file tree (~977 lines)
workspace.js File preview, file ops, loadDir, clearPreview (~185 lines)
sessions.js Session CRUD, list rendering, search, SVG icons, overlay actions (~533 lines)
sessions.js Session CRUD, list rendering, search, SVG icons, dropdown actions (~533 lines)
messages.js send(), SSE event handlers, approval, transcript (~297 lines)
panels.js Cron, skills, memory, workspace, profiles, todo, settings (~974 lines)
commands.js Slash command registry, parser, autocomplete dropdown (~156 lines)
Expand Down Expand Up @@ -351,7 +358,7 @@ highlighting) and Mermaid.js (diagrams) from CDN, both loaded async/deferred wit
Six JS modules loaded in order at end of <body>:
1. ui.js (~846 lines) DOM helpers, renderMd, tool card rendering, global state
2. workspace.js (~169 lines) File tree, preview, file operations
3. sessions.js (~532 lines) Session CRUD, list rendering, search, SVG icons, overlay actions, project picker
3. sessions.js (~532 lines) Session CRUD, list rendering, search, SVG icons, dropdown actions, project picker
4. messages.js (~293 lines) send(), SSE event handlers, approval, transcript
5. panels.js (~771 lines) Cron, skills, memory, workspace, todo, switchPanel
6. boot.js (~175 lines) Event wiring + boot IIFE
Expand All @@ -362,10 +369,19 @@ inherit `currentColor` for consistent theming.

Three-panel layout (in static/index.html):

<aside class="sidebar"> Left panel: session list, nav tabs, model selector
<aside class="sidebar"> Left panel: session list, nav tabs, sidebar-footer Hermes WebUI trigger
<main class="main"> Center: topbar, messages area, approval card, composer
<aside class="rightpanel"> Right panel: workspace file tree and file preview

Composer footer layout (current):

left cluster attach button, mic button, per-conversation model selector
right cluster compact circular context-usage badge, send button

The model selector is still the authoritative control for new-session creation
and session updates; it was moved out of the sidebar so model choice feels scoped
to the active conversation rather than a global app setting.

### 5.2 Global State

const S = {
Expand Down Expand Up @@ -410,11 +426,19 @@ Approval:
stopApprovalPolling clearInterval

UI helpers:
setStatus(t) Updates #statusText in composer footer
setStatus(t) Fallback helper: shows a toast for non-chat status/error messages
setComposerStatus(t) Updates the inline composer status label for turn-scoped states
setBusy(v) Sets S.busy, disables/enables Send button, clears status on false
showToast(msg, ms) Bottom-center fade toast (default 2800ms)
showConfirmDialog(o) Shared in-app confirmation modal, resolves true/false
showPromptDialog(o) Shared in-app input modal, resolves string/null
autoResize() Auto-resize #msg textarea up to 200px

Dialog policy:
Native browser confirm()/prompt() are not used in the Web UI.
Destructive actions use showConfirmDialog(...), then a toast on success.
Lightweight naming flows (new file/folder/project) use showPromptDialog(...).

Files:
loadDir(path) GET /api/list, rebuild #fileTree
openFile(path) GET /api/file, show in #previewArea
Expand Down Expand Up @@ -467,7 +491,7 @@ Known gaps:
- Nested lists: single regex pass, multi-level indentation not handled
- Mixed bold+link in same line: may produce garbled output

### 5.5 Model Chip Label (Fixed in Sprint 1)
### 5.5 Model Label Resolution (Fixed in Sprint 1, reused by composer selector)

B3 was resolved in Sprint 1. Current code uses a MODEL_LABELS dict:

Expand All @@ -478,10 +502,10 @@ B3 was resolved in Sprint 1. Current code uses a MODEL_LABELS dict:
'anthropic/claude-haiku-3-5': 'Haiku 3.5', 'google/gemini-2.5-pro': 'Gemini 2.5 Pro',
'deepseek/deepseek-chat-v3-0324': 'DeepSeek V3', 'meta-llama/llama-4-scout': 'Llama 4 Scout',
};
$('modelChip').textContent = MODEL_LABELS[m] || (m.split('/').pop() || 'Unknown');
getModelLabel(m) => MODEL_LABELS[m] || (m.split('/').pop() || 'Unknown');

Fallback: any unlisted model shows its short ID (after the last /) rather than a wrong label.
To add a new model: add an entry to MODEL_LABELS and add an <option> to the <select>.
To add a new model: add an entry to MODEL_LABELS and add an <option> to the composer footer <select>.

### 5.6 Session Delete Rules (from skill)

Expand Down Expand Up @@ -1099,7 +1123,7 @@ The model chip label bug is now fixed. The MODEL_LABELS object in syncTopbar():
'deepseek/deepseek-chat-v3-0324': 'DeepSeek V3',
'meta-llama/llama-4-scout': 'Llama 4 Scout',
};
$('modelChip').textContent = MODEL_LABELS[m] || (m.split('/').pop() || 'Unknown');
getModelLabel(m) => MODEL_LABELS[m] || (m.split('/').pop() || 'Unknown');

Fallback: splits on '/' and uses the last segment, so any unlisted model shows its
short identifier rather than a wrong hardcoded label.
Expand Down
10 changes: 5 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@
notification when the tab is in the background.
- **Thinking / reasoning block display** (PR #181, #182): Inline `<think>…</think>`
and Gemma 4 `<|channel>thought…<channel|>` tags are parsed out of assistant
messages and rendered as a collapsible 💡 "Thinking" card above the reply.
messages and rendered as a collapsible lightbulb "Thinking" card above the reply.
During streaming, the bubble shows "Thinking…" until the tag closes. Hardened
against partial-tag edge cases and empty thinking blocks.

Expand Down Expand Up @@ -665,7 +665,7 @@
command. Persists server-side across refreshes.

- **Subagent delegation cards.** `subagent_progress` events now render with
a 🔀 icon and a blue indented left border to visually distinguish child
a shuffle icon and a blue indented left border to visually distinguish child
tool activity from parent tool calls. `delegate_task` cards display as
"Delegate task" with cleaner formatting.

Expand Down Expand Up @@ -1461,9 +1461,9 @@ The sprint that closed the last gaps for heavy agentic use.
restored from session history on reload. Shows tool name, preview, args, result snippet.
- **Attachment metadata persists on reload.** File badges on user messages survive page
refresh. Server stores filenames on the user message in session JSON.
- **Todo list panel.** New checkmark tab in the sidebar. Shows current task list parsed
from the most recent todo tool result in message history. Status icons: pending (○),
in-progress (◉), completed (✓), cancelled (✗). Auto-refreshes when panel is active.
- **Todo list panel.** New task-list tab in the sidebar. Shows current task list parsed
from the most recent todo tool result in message history. Status icons use Lucide
square, loader, check, and x states. Auto-refreshes when panel is active.
- **Model preference persists.** Last-used model saved to localStorage. Restored on page
load. New sessions inherit it automatically.

Expand Down
15 changes: 9 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
| 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, overlay hover actions, pin indicator, project border, safe HTML rendering | 289 |
| 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 |
Expand Down Expand Up @@ -85,11 +85,12 @@
### Chat and Agent
- [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 in activity bar above composer
- [x] Tool progress shown inline in the conversation via live tool cards
- [x] Approval card for dangerous commands (Allow once/session/always, Deny)
- [x] Approval polling + SSE-pushed approval events
- [x] INFLIGHT guard: switch sessions mid-request without losing response
Expand All @@ -101,23 +102,25 @@
- [x] Token/cost estimate per message (Sprint 23)

### Tool Visibility
- [x] Tool progress in activity bar (moved out of composer footer)
- [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, confirm dialog)
- [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)

### Sessions
- [x] Create session (+ button or Cmd/Ctrl+K)
Expand Down Expand Up @@ -218,14 +221,14 @@
- [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 -- token count and cost in composer footer (Sprint 24, PR #83)
- [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 (activity bar Cancel button)
- [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)
Expand Down
4 changes: 2 additions & 2 deletions SPRINTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ inconsistently across platforms. These were the most common visual complaints.
button now only appears in the hover overlay like all other actions.

### Track B: Features
- **SVG action icons.** Replaced all emoji HTML entities (★, 📂, 📦, ⊕, 🗑)
- **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).
Expand Down Expand Up @@ -762,7 +762,7 @@ Both architectures in one .app. No separate downloads needed.
- JS bridge fires when approval card appears/disappears

**Menu bar mode (optional, v2):**
- A small status bar item (⚗️ icon in menu bar) that opens a compact popover
- 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

Expand Down
Loading