hermes-agent/apps/dashboard
2026-05-27 21:22:14 -05:00
..
public feat: move dashboard to apps/ so we can share ws proto 2026-05-02 13:38:49 -05:00
src Merge origin/main into bb/gui 2026-05-27 21:22:14 -05:00
eslint.config.js feat: move dashboard to apps/ so we can share ws proto 2026-05-02 13:38:49 -05:00
index.html Merge remote-tracking branch 'origin/main' into bb/gui 2026-05-20 01:35:02 -04:00
package-lock.json Merge origin/main into bb/gui (2026-05-24) 2026-05-25 00:39:46 -04:00
package.json Merge origin/main into bb/gui (2026-05-24) 2026-05-25 00:39:46 -04:00
README.md Merge origin/main into bb/gui (2026-05-24) 2026-05-25 00:39:46 -04:00
tsconfig.app.json feat: move dashboard to apps/ so we can share ws proto 2026-05-02 13:38:49 -05:00
tsconfig.json feat: move dashboard to apps/ so we can share ws proto 2026-05-02 13:38:49 -05:00
tsconfig.node.json feat: move dashboard to apps/ so we can share ws proto 2026-05-02 13:38:49 -05:00
vite.config.ts feat: move dashboard to apps/ so we can share ws proto 2026-05-02 13:38:49 -05:00

Hermes Agent — Web UI

Browser-based dashboard for managing Hermes Agent configuration, API keys, and monitoring active sessions.

Stack

  • Vite + React 19 + TypeScript
  • Tailwind CSS v4 with custom dark theme
  • shadcn/ui-style components (hand-rolled, no CLI dependency)

Development

Install workspace dependencies from the repo root first:

npm install

Start the backend API server from the repo root:

hermes dashboard --tui --no-open

--tui exposes the in-browser Chat tab through /api/pty. Omit it if you only need the config/session dashboard.

In another terminal, start the Vite dev server:

cd apps/dashboard
npm run dev

The Vite dev server proxies /api, /api/pty, and /dashboard-plugins to http://127.0.0.1:9119 (the FastAPI backend). It also fetches the backend's index.html on each dev page load so the ephemeral session token stays in sync.

If the hermes entry point is not installed, use:

python -m hermes_cli.main dashboard --tui --no-open

Build

npm run build

This outputs to ../../hermes_cli/web_dist/, which the FastAPI server serves as a static SPA. The built assets are included in the Python package via pyproject.toml package-data.

Structure

src/
├── components/ui/   # Reusable UI primitives (Card, Badge, Button, Input, etc.)
├── lib/
│   ├── api.ts       # API client — typed fetch wrappers for all backend endpoints
│   └── utils.ts     # cn() helper for Tailwind class merging
├── pages/
│   ├── StatusPage   # Agent status, active/recent sessions
│   ├── ConfigPage   # Dynamic config editor (reads schema from backend)
│   └── EnvPage      # API key management with save/clear
├── App.tsx          # Main layout and navigation
├── main.tsx         # React entry point
└── index.css        # Tailwind imports and theme variables

Typography & contrast rules

Read before adding or editing UI styles. These rules keep the dashboard legible across all built-in themes and stop drift back into the patterns the design system was just refactored out of.

Text size floor

  • Minimum body size: text-xs (12px / 0.75rem). Do not use arbitrary text-[0.6rem], text-[0.65rem], text-[9px], text-[10px], or text-[11px] on copy, hints, labels, counts, or badges. Use the standard scale: text-xs, text-sm, text-base.
  • Smaller sizes are only acceptable on decorative overlays (chart stripes, empty-state icons) — never on text the user is meant to read.

Opacity floor on text

  • Never apply opacity below 0.7 to text. No opacity-30, opacity-50, opacity-60 on <span>s, <p>s, labels, etc.
  • Do not stack opacity tokens. Patterns like text-muted-foreground/60, text-midground/70, text-foreground/50 create unpredictable WCAG failures because the parent token already has alpha.
  • Use the semantic text tokens from @nous-research/ui's globals.css:
    • text-text-primary — default body text.
    • text-text-secondary — subtitles, meta, inactive nav.
    • text-text-tertiary — small chrome labels, counts, footnotes.
    • text-text-disabled — disabled states.
    • text-text-on-accent — text on filled accent surfaces.

Brand uppercase via text-display, not raw uppercase

  • The dashboard preserves the Nous brand uppercase aesthetic, but it is opt-in per element, not global.
  • Apply uppercase via the DS utility text-display on brand chrome only — page titles, nav section headings, badges, brand wordmark. DS components (Button, Badge, Tabs, Segmented, etc.) already self-apply text-display.
  • Do not introduce new uppercase (the literal Tailwind class) in hermes-agent/web/src. Prefer text-display for new brand chrome. Legacy uppercase call sites (e.g. components/ui/label.tsx, card.tsx) remain until migrated.
  • The app shell no longer forces uppercase globally, so blanket normal-case opt-outs are unnecessary. Use normal-case only where a DS component applies text-display but the label should stay sentence case — e.g. dynamic user content (model slugs, theme names) or fixed UI copy that is not brand chrome (EnvPage “not configured” toggle, sidebar “New chat”).

Fonts

Typography is opt-in per surface, not global on layout shells — the app shell and page header keep their original theme/expanded fonts; Mondwest applies only where explicitly set.

Tier Classes Use for
Brand chrome font-mondwest text-display (or themedChrome) Sidebar nav, card section headers (CardTitle), Segmented filter buttons, filter panel headings
Themed body font-mondwest normal-case (or themedBody) Card content (Card, CardDescription), session/platform rows, analytics tables — scoped to the component
Page chrome font-expanded Page header h1 (PageHeaderProvider) — sentence case, not text-display
Wordmark Typography + size/tracking only Sidebar/mobile “Hermes Agent” — mixed case, no Mondwest, no text-display
Technical font-mono-ui / font-mono / font-courier Model slugs, env keys, schedules, YAML, repo URLs
  • Do not put themedBody or themedFont on <main>, App, or other layout wrappers — it overrides component-scoped styles.
  • Card applies themedBody; CardTitle uses text-display (uppercase chrome); CardDescription uses themedBody.
  • NouiTypography defaults to font-sans unless a font prop is passed.
  • Do not use raw font-sans or font-display (theme sans variable) on new dashboard UI — prefer Mondwest tiers above where brand-appropriate.

Color tokens

  • Prefer semantic tokens (text-text-*, bg-card, border-border, text-foreground, text-destructive, text-success, text-warning) over raw layer references (text-midground, text-foreground).
  • text-muted-foreground is now wired to --color-text-secondary, so existing call sites stay correct, but new code should prefer the semantic name.
  • When you genuinely need a non-token color (icon de-emphasis on a chart, terminal foreground via inline style), keep alpha at ≥ 0.7 for any text.