Web Design Skill - Clauder Dashboard
Use this skill when designing, improving, or modifying the Clauder web management interface.
Architecture Overview
The web dashboard is a single-page application served by a Go HTTP server. All UI lives in one file:
- Template:
internal/ui/templates/dashboard.html (~2,570 lines)
- Inline
<style> block (CSS custom properties + pure CSS)
- Semantic HTML structure
- Vanilla JavaScript (no frameworks)
- Server:
internal/ui/web.go (~665 lines)
- Go
html/template rendering
- REST API endpoints
- WebSocket terminal support
- Embedded: Templates are embedded in the binary via
//go:embed templates/*
Technology Stack
| Layer |
Technology |
| HTML |
HTML5 with Go template directives ({{.RefreshInterval}}, {{.WorkDir}}) |
| CSS |
Pure CSS with CSS custom properties, Flexbox/Grid, no preprocessor |
| JavaScript |
Vanilla JS, no build step, no frameworks |
| Fonts |
Google Fonts: Inter (UI), JetBrains Mono (code/monospace) |
| Terminal |
XTerm.js v5.3.0 + fit addon + web-links addon |
| Real-time |
WebSockets (Gorilla) for terminal PTY |
| Icons |
Unicode/emoji characters (no icon library) |
Design System
Color Palette (CSS Variables)
:root {
/* Primary - Purple */
--primary: #8B5CF6;
--primary-light: #A78BFA;
--primary-dark: #7C3AED;
/* Secondary - Cyan */
--secondary: #06B6D4;
--secondary-light: #22D3EE;
/* Semantic */
--success: #10B981;
--success-light: #34D399;
--warning: #F59E0B;
--warning-light: #FBBF24;
--error: #EF4444;
/* Neutral */
--muted: #64748B;
--muted-light: #94A3B8;
--text: #F1F5F9;
--text-secondary: #CBD5E1;
/* Backgrounds - Dark theme */
--bg: #0F172A; /* Page background */
--bg-card: #1E293B; /* Card/surface background */
--bg-card-hover: #334155; /* Hover state */
/* Borders */
--border: #334155;
--border-light: #475569;
/* Glass effects */
--glass: rgba(30, 41, 59, 0.8);
--glass-border: rgba(148, 163, 184, 0.1);
/* Shadows */
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.2);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -4px rgba(0, 0, 0, 0.2);
/* Border radius */
--radius: 12px;
--radius-sm: 8px;
--radius-lg: 16px;
}
Typography
- UI text:
'Inter', -apple-system, BlinkMacSystemFont, sans-serif
- Code/IDs:
'JetBrains Mono', monospace
- Base line-height: 1.5
- Font sizes: 0.6875rem (tags) → 1.75rem (page titles)
- Font weights: 300 (light) through 700 (bold)
Spacing Conventions
- Padding: 0.25rem increments (0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 1.25, 1.5, 2rem)
- Gap: 0.375rem (tight) → 1.5rem (sections)
- Sidebar width: 280px (240px on tablet, hidden on mobile)
Component Patterns
Cards: background: var(--bg-card), border: 1px solid var(--border), border-radius: var(--radius), hover lifts with var(--shadow)
Badges: Pill shape (border-radius: 9999px), semi-transparent bg with matching text color:
- Leader/Active:
rgba(16, 185, 129, 0.15) + var(--success-light)
- Idle/Warning:
rgba(245, 158, 11, 0.15) + var(--warning-light)
- Inactive:
rgba(100, 116, 139, 0.15) + var(--muted-light)
Tags: border-radius: var(--radius-sm), background: rgba(6, 182, 212, 0.15), color: var(--secondary-light)
Buttons: Two variants:
.btn-primary: Solid var(--primary) background, white text
.btn-secondary: var(--bg-card) background, var(--border) border
Modals: Overlay with backdrop-filter: blur(4px), centered card, max-width 640px
Gradients: Logo/avatars use linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%)
Page Structure
Layout
┌─────────────────────────────────────────────┐
│ .app (display: flex) │
│ ┌──────────┐ ┌────────────────────────────┐ │
│ │ .sidebar │ │ .main │ │
│ │ (fixed │ │ (margin-left: 280px) │ │
│ │ 280px) │ │ │ │
│ │ │ │ ┌────────────────────────┐ │ │
│ │ - Logo │ │ │ .view (one visible) │ │ │
│ │ - Nav │ │ │ - Map view │ │ │
│ │ - Stats │ │ │ - Instances view │ │ │
│ │ │ │ │ - Messages view │ │ │
│ │ │ │ │ - Facts view │ │ │
│ │ │ │ └────────────────────────┘ │ │
│ └──────────┘ └────────────────────────────┘ │
└─────────────────────────────────────────────┘
Views (4 tabs)
Map View (#map-view): Hexagonal grid of instances + session panel sidebar
- Hex grid uses CSS
clip-path: polygon(...) for hexagon shape
- Session list panel (380px wide) on the right
- Diamond-shaped layout algorithm for hex arrangement
Instances View (#instances-view): Card list with search + filter (All/Active/Idle/Leader)
Messages View (#messages-view): Card list with search + filter (All/Unread/Read) + from/to dropdowns
Facts View (#facts-view): Card list with search + filter (All/Local/Global) + tag/source dropdowns
Overlays
- Detail Modal (
#modal): Shows instance/message/fact details
- Launch Modal (
#launch-modal): New session launcher with quick-launch list
- Terminal Overlay (
#terminal-overlay): Full-screen XTerm.js terminal
- Terminals Tray (
#terminals-tray): Minimized terminal pills (bottom-right)
API Endpoints
| Method |
Path |
Purpose |
| GET |
/ |
Serve dashboard HTML |
| GET |
/api/data |
JSON: instances, messages, facts, stats |
| POST |
/api/launch |
Launch Terminal.app with claude (macOS) |
| POST |
/api/facts/delete?id=N |
Soft-delete a fact |
| WS |
/api/terminal?dir=PATH |
WebSocket PTY for embedded terminal |
API Response Shape
{
"instances": [{ "id", "shortId", "directory", "shortDir", "projectName", "isLeader", "isIdle", "isActive", "needsAttention", "attentionReason", "unreadCount", "lastHeartbeat", "heartbeatAge", "recentMessages" }],
"messages": [{ "id", "fromInstance", "shortFrom", "fromDir", "shortFromDir", "toInstance", "shortTo", "toDir", "shortToDir", "content", "preview", "createdAt", "age", "isRead" }],
"facts": [{ "id", "content", "preview", "tags", "sourceDir", "shortDir", "isLocal", "createdAt" }],
"stats": { "totalInstances", "workingInstances", "totalMessages", "unreadMessages", "totalFacts", "localFacts" }
}
JavaScript Architecture
State Management
let currentView = 'map'; // Active tab
let allData = { instances: [], messages: [], facts: [], stats: {} }; // API data
let instanceFilter = 'all'; // Instance tab filter
let messageFilter = 'all'; // Message tab filter
let factFilter = 'all'; // Fact tab filter
let selectedInstanceIndex = -1; // Selected hex/session
let terminals = []; // Active terminal sessions (max 4)
let activeTerminalId = null; // Currently displayed terminal
Data Flow
fetchData() → GET /api/data → store in allData
updateStats() → update sidebar badges and stat cards
renderCurrentView() → dispatches to renderMap(), renderInstances(), renderMessages(), or renderFacts()
- Auto-refresh via
setInterval(fetchData, REFRESH_INTERVAL)
Key Functions
switchView(view) - Tab navigation
fetchData() - API fetch + render
renderMap() / renderInstances() / renderMessages() / renderFacts() - View renderers
showModal(title, content) / closeModal() - Modal management
openTerminal(dir) / closeTerminal() / minimizeTerminal() / restoreTerminal() - Terminal lifecycle
escapeHtml(text) - XSS prevention via DOM textContent
deleteFact(id, btn) - Fact deletion with optimistic UI
Keyboard Shortcuts
R - Refresh data
Escape - Close/minimize modals and terminals
1-9 - Select instance in map view
Alt+1/m - Map view
Alt+2/i - Instances view
Alt+3/e - Messages view
Alt+4/f - Facts view
Design Guidelines
When modifying the UI:
- Dark theme only - All colors use the CSS variable system, maintain contrast ratios
- No external dependencies - Keep it vanilla JS/CSS. Only allowed externals: Google Fonts, XTerm.js
- Single file - All HTML/CSS/JS stays in
dashboard.html (embedded in Go binary)
- Go template safety - Use
{{.Field}} for server data. HTML is escaped by default
- XSS prevention - Always use
escapeHtml() for user-generated content in innerHTML
- Responsive - Three breakpoints: desktop (>1024px), tablet (768-1024px), mobile (<768px)
- Animations - Subtle transitions (0.2s ease), pulse animations for attention states
- Consistent spacing - Use existing padding/gap patterns, avoid arbitrary values
- Card pattern - New content types should follow the existing card structure
- Filter pattern - New views should include search box + filter buttons + optional dropdowns
Adding New Features
Adding a new view/tab:
- Add nav item in
.sidebar > .nav with data-view="newview"
- Add
<div class="view" id="newview-view" style="display: none;"> in .main
- Add case to
renderCurrentView() switch
- Add keyboard shortcut in keydown handler
- Create
renderNewview() function following existing patterns
Adding a new API endpoint:
- Add route in
web.go Start() method
- Create handler function on
WebServer
- Update
APIResponse struct if extending /api/data
- Update JavaScript
fetchData() if data shape changes
Adding new card types:
- Follow
.fact-card / .message-card / .instance-card patterns
- Include hover state with
var(--shadow) lift
- Add click handler for modal details
- Include empty state with
.empty-state pattern
Terminal Integration
The embedded terminal uses:
- XTerm.js for rendering
- WebSocket for bidirectional PTY communication
- FitAddon for responsive sizing
- WebLinksAddon for clickable URLs
- Up to 4 concurrent terminals with minimize/restore
- Terminal theme matches the dashboard dark theme
Testing Changes
After modifying dashboard.html:
- Run
make build or go build -o clauder .
- Run
./clauder ui to start the web server
- Dashboard opens at
http://localhost:8765
- Use
--port flag for custom port, --no-browser to skip auto-open
Source: MaorBril/clauder — distributed by TomeVault.
1---2name: clauder3description: Use this skill when designing, improving, or modifying the Clauder web management interface.4---5# Web Design Skill - Clauder Dashboard67Use this skill when designing, improving, or modifying the Clauder web management interface.89## Architecture Overview1011The web dashboard is a **single-page application** served by a Go HTTP server. All UI lives in one file:1213- **Template**: `internal/ui/templates/dashboard.html` (~2,570 lines)14 - Inline `<style>` block (CSS custom properties + pure CSS)15 - Semantic HTML structure16 - Vanilla JavaScript (no frameworks)17- **Server**: `internal/ui/web.go` (~665 lines)18 - Go `html/template` rendering19 - REST API endpoints20 - WebSocket terminal support21- **Embedded**: Templates are embedded in the binary via `//go:embed templates/*`2223## Technology Stack2425| Layer | Technology |26|-------|-----------|27| HTML | HTML5 with Go template directives (`{{.RefreshInterval}}`, `{{.WorkDir}}`) |28| CSS | Pure CSS with CSS custom properties, Flexbox/Grid, no preprocessor |29| JavaScript | Vanilla JS, no build step, no frameworks |30| Fonts | Google Fonts: Inter (UI), JetBrains Mono (code/monospace) |31| Terminal | XTerm.js v5.3.0 + fit addon + web-links addon |32| Real-time | WebSockets (Gorilla) for terminal PTY |33| Icons | Unicode/emoji characters (no icon library) |3435## Design System3637### Color Palette (CSS Variables)3839```css40:root {41 /* Primary - Purple */42 --primary: #8B5CF6;43 --primary-light: #A78BFA;44 --primary-dark: #7C3AED;4546 /* Secondary - Cyan */47 --secondary: #06B6D4;48 --secondary-light: #22D3EE;4950 /* Semantic */51 --success: #10B981;52 --success-light: #34D399;53 --warning: #F59E0B;54 --warning-light: #FBBF24;55 --error: #EF4444;5657 /* Neutral */58 --muted: #64748B;59 --muted-light: #94A3B8;60 --text: #F1F5F9;61 --text-secondary: #CBD5E1;6263 /* Backgrounds - Dark theme */64 --bg: #0F172A; /* Page background */65 --bg-card: #1E293B; /* Card/surface background */66 --bg-card-hover: #334155; /* Hover state */6768 /* Borders */69 --border: #334155;70 --border-light: #475569;7172 /* Glass effects */73 --glass: rgba(30, 41, 59, 0.8);74 --glass-border: rgba(148, 163, 184, 0.1);7576 /* Shadows */77 --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -2px rgba(0, 0, 0, 0.2);78 --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -4px rgba(0, 0, 0, 0.2);7980 /* Border radius */81 --radius: 12px;82 --radius-sm: 8px;83 --radius-lg: 16px;84}85```8687### Typography8889- **UI text**: `'Inter', -apple-system, BlinkMacSystemFont, sans-serif`90- **Code/IDs**: `'JetBrains Mono', monospace`91- **Base line-height**: 1.592- **Font sizes**: 0.6875rem (tags) → 1.75rem (page titles)93- **Font weights**: 300 (light) through 700 (bold)9495### Spacing Conventions9697- Padding: 0.25rem increments (0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 1.25, 1.5, 2rem)98- Gap: 0.375rem (tight) → 1.5rem (sections)99- Sidebar width: 280px (240px on tablet, hidden on mobile)100101### Component Patterns102103**Cards**: `background: var(--bg-card)`, `border: 1px solid var(--border)`, `border-radius: var(--radius)`, hover lifts with `var(--shadow)`104105**Badges**: Pill shape (`border-radius: 9999px`), semi-transparent bg with matching text color:106- Leader/Active: `rgba(16, 185, 129, 0.15)` + `var(--success-light)`107- Idle/Warning: `rgba(245, 158, 11, 0.15)` + `var(--warning-light)`108- Inactive: `rgba(100, 116, 139, 0.15)` + `var(--muted-light)`109110**Tags**: `border-radius: var(--radius-sm)`, `background: rgba(6, 182, 212, 0.15)`, `color: var(--secondary-light)`111112**Buttons**: Two variants:113- `.btn-primary`: Solid `var(--primary)` background, white text114- `.btn-secondary`: `var(--bg-card)` background, `var(--border)` border115116**Modals**: Overlay with `backdrop-filter: blur(4px)`, centered card, max-width 640px117118**Gradients**: Logo/avatars use `linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%)`119120## Page Structure121122### Layout123```124┌─────────────────────────────────────────────┐125│ .app (display: flex) │126│ ┌──────────┐ ┌────────────────────────────┐ │127│ │ .sidebar │ │ .main │ │128│ │ (fixed │ │ (margin-left: 280px) │ │129│ │ 280px) │ │ │ │130│ │ │ │ ┌────────────────────────┐ │ │131│ │ - Logo │ │ │ .view (one visible) │ │ │132│ │ - Nav │ │ │ - Map view │ │ │133│ │ - Stats │ │ │ - Instances view │ │ │134│ │ │ │ │ - Messages view │ │ │135│ │ │ │ │ - Facts view │ │ │136│ │ │ │ └────────────────────────┘ │ │137│ └──────────┘ └────────────────────────────┘ │138└─────────────────────────────────────────────┘139```140141### Views (4 tabs)1421431. **Map View** (`#map-view`): Hexagonal grid of instances + session panel sidebar144 - Hex grid uses CSS `clip-path: polygon(...)` for hexagon shape145 - Session list panel (380px wide) on the right146 - Diamond-shaped layout algorithm for hex arrangement1471482. **Instances View** (`#instances-view`): Card list with search + filter (All/Active/Idle/Leader)1491503. **Messages View** (`#messages-view`): Card list with search + filter (All/Unread/Read) + from/to dropdowns1511524. **Facts View** (`#facts-view`): Card list with search + filter (All/Local/Global) + tag/source dropdowns153154### Overlays155156- **Detail Modal** (`#modal`): Shows instance/message/fact details157- **Launch Modal** (`#launch-modal`): New session launcher with quick-launch list158- **Terminal Overlay** (`#terminal-overlay`): Full-screen XTerm.js terminal159- **Terminals Tray** (`#terminals-tray`): Minimized terminal pills (bottom-right)160161## API Endpoints162163| Method | Path | Purpose |164|--------|------|---------|165| GET | `/` | Serve dashboard HTML |166| GET | `/api/data` | JSON: instances, messages, facts, stats |167| POST | `/api/launch` | Launch Terminal.app with claude (macOS) |168| POST | `/api/facts/delete?id=N` | Soft-delete a fact |169| WS | `/api/terminal?dir=PATH` | WebSocket PTY for embedded terminal |170171### API Response Shape172173```json174{175 "instances": [{ "id", "shortId", "directory", "shortDir", "projectName", "isLeader", "isIdle", "isActive", "needsAttention", "attentionReason", "unreadCount", "lastHeartbeat", "heartbeatAge", "recentMessages" }],176 "messages": [{ "id", "fromInstance", "shortFrom", "fromDir", "shortFromDir", "toInstance", "shortTo", "toDir", "shortToDir", "content", "preview", "createdAt", "age", "isRead" }],177 "facts": [{ "id", "content", "preview", "tags", "sourceDir", "shortDir", "isLocal", "createdAt" }],178 "stats": { "totalInstances", "workingInstances", "totalMessages", "unreadMessages", "totalFacts", "localFacts" }179}180```181182## JavaScript Architecture183184### State Management185```js186let currentView = 'map'; // Active tab187let allData = { instances: [], messages: [], facts: [], stats: {} }; // API data188let instanceFilter = 'all'; // Instance tab filter189let messageFilter = 'all'; // Message tab filter190let factFilter = 'all'; // Fact tab filter191let selectedInstanceIndex = -1; // Selected hex/session192let terminals = []; // Active terminal sessions (max 4)193let activeTerminalId = null; // Currently displayed terminal194```195196### Data Flow1971. `fetchData()` → GET `/api/data` → store in `allData`1982. `updateStats()` → update sidebar badges and stat cards1993. `renderCurrentView()` → dispatches to `renderMap()`, `renderInstances()`, `renderMessages()`, or `renderFacts()`2004. Auto-refresh via `setInterval(fetchData, REFRESH_INTERVAL)`201202### Key Functions203- `switchView(view)` - Tab navigation204- `fetchData()` - API fetch + render205- `renderMap()` / `renderInstances()` / `renderMessages()` / `renderFacts()` - View renderers206- `showModal(title, content)` / `closeModal()` - Modal management207- `openTerminal(dir)` / `closeTerminal()` / `minimizeTerminal()` / `restoreTerminal()` - Terminal lifecycle208- `escapeHtml(text)` - XSS prevention via DOM textContent209- `deleteFact(id, btn)` - Fact deletion with optimistic UI210211### Keyboard Shortcuts212- `R` - Refresh data213- `Escape` - Close/minimize modals and terminals214- `1-9` - Select instance in map view215- `Alt+1/m` - Map view216- `Alt+2/i` - Instances view217- `Alt+3/e` - Messages view218- `Alt+4/f` - Facts view219220## Design Guidelines221222When modifying the UI:2232241. **Dark theme only** - All colors use the CSS variable system, maintain contrast ratios2252. **No external dependencies** - Keep it vanilla JS/CSS. Only allowed externals: Google Fonts, XTerm.js2263. **Single file** - All HTML/CSS/JS stays in `dashboard.html` (embedded in Go binary)2274. **Go template safety** - Use `{{.Field}}` for server data. HTML is escaped by default2285. **XSS prevention** - Always use `escapeHtml()` for user-generated content in innerHTML2296. **Responsive** - Three breakpoints: desktop (>1024px), tablet (768-1024px), mobile (<768px)2307. **Animations** - Subtle transitions (0.2s ease), pulse animations for attention states2318. **Consistent spacing** - Use existing padding/gap patterns, avoid arbitrary values2329. **Card pattern** - New content types should follow the existing card structure23310. **Filter pattern** - New views should include search box + filter buttons + optional dropdowns234235## Adding New Features236237### Adding a new view/tab:2381. Add nav item in `.sidebar > .nav` with `data-view="newview"`2392. Add `<div class="view" id="newview-view" style="display: none;">` in `.main`2403. Add case to `renderCurrentView()` switch2414. Add keyboard shortcut in keydown handler2425. Create `renderNewview()` function following existing patterns243244### Adding a new API endpoint:2451. Add route in `web.go` `Start()` method2462. Create handler function on `WebServer`2473. Update `APIResponse` struct if extending `/api/data`2484. Update JavaScript `fetchData()` if data shape changes249250### Adding new card types:2511. Follow `.fact-card` / `.message-card` / `.instance-card` patterns2522. Include hover state with `var(--shadow)` lift2533. Add click handler for modal details2544. Include empty state with `.empty-state` pattern255256## Terminal Integration257258The embedded terminal uses:259- XTerm.js for rendering260- WebSocket for bidirectional PTY communication261- FitAddon for responsive sizing262- WebLinksAddon for clickable URLs263- Up to 4 concurrent terminals with minimize/restore264- Terminal theme matches the dashboard dark theme265266## Testing Changes267268After modifying `dashboard.html`:2691. Run `make build` or `go build -o clauder .`2702. Run `./clauder ui` to start the web server2713. Dashboard opens at `http://localhost:8765`2724. Use `--port` flag for custom port, `--no-browser` to skip auto-open273274---275> Source: [MaorBril/clauder](https://github.com/MaorBril/clauder) — distributed by [TomeVault](https://tomevault.io).276<!-- tomevault:4.0:skill_md:2026-06-29 -->