# Direction 4 · Dense Data UI — `assistant-log` ## The product A self-hosted, single-user log aggregator for CLI AI assistants (Claude Code, opencode, crush, pi, kimi). Server runs on a home server (`phoebe`) behind Tailscale; collectors run as systemd user units on each machine and POST normalized turns to SQLite + FTS5. Server-rendered HTML UI, no SPA. Single user. Full transcripts of every session across every tool across every machine, searchable in one place. ## Aesthetic + personality GitHub/Linear-style dense data UI for power scanning. Built on the assumption the user lives in terminals all day and wants information density, not chrome. - **Top bar**: dark (`#1c1a17`), monospace, contains breadcrumb (`assistant-log / scarlet`), an always-visible search input that responds to ⌘K, and tab nav (Recent / Projects / Stats / Health / Settings). - **Body**: warm off-white (`#fdfcf8`), Inter for prose, JetBrains Mono for all data (timestamps, paths, tokens, IDs). - **Accent**: terracotta `#c96442`, used sparingly — selected tab, primary chip, sparkline highlight, FTS hit highlight, "stale" warnings. - **Type scale**: 11–13 px body. Tight (1.4) line-height. Uppercase 10 px column headers with 0.05 em tracking and `var(--ink-3)` color. - **Rows**: 28–32 px tall (compact mode 22–24), 1 px `--rule-2` dividers, hover `#f3f0e7`. - **Tags**: small mono pills — neutral `#ebe7d8`, host-green `#d9e6dd`, accent terracotta. Per-tool a 8 px square color dot (`claude-code` terracotta, `opencode` green, `crush` purple, `pi` ochre, `kimi` blue). - **Sparklines**: 60–140 × 12–18 px inline SVG polylines, stroke 1.2, accent-colored when row is "the user's main thing". ## Layout pattern (every page) 1. Dark mono top bar (search + nav). 2. Light sub-bar with active filters as removable chips, plus a contextual stat strip on the right (e.g. turns/day sparkline + total). 3. Tight grid header row (uppercase mono labels). 4. Scrollable rows with `display: grid; grid-template-columns: …`, mono in time/path/numeric columns, sans in prose columns. 5. Optional footer strip for global state (backfill progress, last error). ## Screens 1. **Home (Recent)** — Reverse-chronological feed of sessions across all tools/hosts. Columns: when · tool tag · host tag · session question + cwd · turns · tok · turns/h sparkline. Top sub-bar carries `tool: any · host: any · since: 30d` chips and a global turns/day sparkline. 2. **Search results** — Results are a flat table of *turns* (not sessions), one match per row, with the snippet truncated and FTS hits wrapped in a terracotta ``. Filters in chips above. Save-search action lives next to the chip row. 3. **Session view** — Two-column. Left aside (240 px) is a turn list with `# · role glyph · preview · token count`, current turn highlighted with a left accent border. Right pane is the linear transcript: each turn is a row separated by 1 px rules, role label is mono uppercase color-coded (`USER` neutral, `ASSISTANT` accent, `TOOL` muted), tool calls render as monospace cards with a faint background tint. Sticky header carries `cwd · title · tool tag · host tag · model · turn count · tokens · open dot`. 4. **Project view (cwd)** — Header shows `~/code/` breadcrumb + `tt-bundle` in mono, count chips, and a sparkline of activity. Saved-search chips below. Then the same dense session table filtered to that cwd. 5. **Stats** — Top sub-bar has range pills (7d / 30d / 90d / all) and group-by pills (tool / host / project / model). Content is a grid of cards: per-tool stat strip (turns / tokens / cost / sparkline / share %), a stacked turns/day chart (60 days), a 12-week activity heatmap, and a top-cwd bar list. 6. **Ingestion health** — Status pills in sub-bar (`● 7 ok · ● 1 warn`). Table of every (host, tool, source) row with: status dot · host · tool · source path · lag · outbox depth · last-OK · events 24h. Stale rows get accent-colored lag, non-empty outboxes get accent-colored count. Footer strip: backfill progress bar + last parser error inline. 7. **Settings** — Sidebar nav (Sources / Display / Auth / Backup / Export / Tags / Saved searches). Sources page is the dense source table with status dot, tool tag, path, poll interval, event count, last-OK, edit. Display has compact tag-pair toggles (density, tool calls, accent). ## Interaction model - Always-on global search (⌘K focuses the top input from any page). - Filter chips are removable and additive; "+ add filter" opens a small popover. - All paths are clickable and open the corresponding Project view. - Each row in any list is clickable and opens its session/turn permalink. - Keyboard: `j/k` move row, `↵` open, `g h/s/p/i` jump to home / stats / projects / health. ## Mock data shape **Sample sessions** (across `claude-code`, `opencode`, `crush`, `pi`, `kimi` on `laptop` and `workpc`): | time | tool | host | cwd | first prompt | turns | tok | model | |--------|-------------|--------|----------------------------------|-----------------------------------------------------------------------------|-------|-------|------------------| | 14:22 | claude-code | laptop | ~/code/tt-bundle | lockfile design for the tt bundle — should we hash inputs or outputs? | 84 | 12.4k | claude-opus-4-7 | | 11:08 | opencode | workpc | ~/work/atelier/migrations | why does the v3 migration drop the partial index on (org, ts) | 12 | 2.1k | gpt-5-mini | | 10:52 | claude-code | workpc | ~/work/scarlet-svc | is there a way to make this retry loop tolerate 429s without a sleep | 41 | 7.7k | claude-opus-4-7 | | 09:14 | crush | laptop | ~/code/dotfiles | rewrite this zsh prompt to show ssh host only when on a remote | 6 | 0.9k | gemini-2-flash | | Yest | pi | laptop | ~/notes | help me draft a one-pager for the offsite session on incident response | 19 | 4.0k | inflection-3 | | Yest | claude-code | laptop | ~/code/tt-bundle | when do we need to re-resolve transitive deps after a lock bump | 28 | 5.3k | claude-opus-4-7 | | Yest | kimi | workpc | ~/work/atelier | translate these comments to english but keep the tone | 4 | 0.7k | kimi-k2 | **Ingestion health** — 8 collector rows (one per host × tool): | host | tool | source | lag | outbox | last ok | status | |--------|-------------|---------------------------------|-----|--------|---------|--------| | laptop | claude-code | ~/.claude/projects | 4s | 0 | now | ok | | laptop | opencode | ~/.local/share/opencode | 12s | 0 | 12s | ok | | laptop | crush | ~/.cache/crush | 28s | 0 | 28s | ok | | laptop | pi | ~/.config/pi/history | 1m | 0 | 1m | ok | | workpc | claude-code | ~/.claude/projects | 7s | 0 | now | ok | | workpc | opencode | ~/.local/share/opencode | 18s | 0 | 18s | ok | | workpc | kimi | ~/.kimi-cli/history.jsonl | 2m | 127 | 2m | warn | | workpc | crush | ~/.cache/crush | 8m | 0 | 8m | stale | **Per-tool 30-day rollups:** - claude-code — 1820 turns / 482k tok / $0 (Max sub, cost unknowable) - opencode — 211 turns / 18k tok / $4.12 - crush — 64 turns / 2k tok / $0.71 - pi — 32 turns / 7k tok / $0 - kimi — 11 turns / 1k tok / $0 ## Tech assumptions for the build - React 18.3.1 + Babel standalone for the prototype. - Inter + JetBrains Mono via Google Fonts. - All data is hard-coded mock data. No real backend. - Single HTML file with split JSX modules per screen for maintainability. ## Suggested first prompt for the new chat > Build a hi-fi clickable prototype of a personal CLI AI assistant log aggregator UI in the **Dense Data UI** style described in the attached spec. One HTML file. Real navigation between screens (top-bar tabs, row clicks, ⌘K search focus, filter chips). Cover Home / Search / Session / Project / Stats / Health / Settings. Use the mock data shape and visual system specified.