An open API service indexing awesome lists of open source software.

https://github.com/justinstimatze/lucida

Real-time visualization dashboard for Claude Code — passively mints Vega charts, Mermaid diagrams, 3D scenes, and animated SVGs from your conversation as you work
https://github.com/justinstimatze/lucida

anthropic claude claude-code dashboard fui llm-tools mermaid python vega visualization

Last synced: 4 days ago
JSON representation

Real-time visualization dashboard for Claude Code — passively mints Vega charts, Mermaid diagrams, 3D scenes, and animated SVGs from your conversation as you work

Awesome Lists containing this project

README

          

# lucida

[![CI](https://github.com/justinstimatze/lucida/actions/workflows/ci.yml/badge.svg)](https://github.com/justinstimatze/lucida/actions/workflows/ci.yml)

*For the monitor where you used to read code.*

Your Claude Code session, rendered live as a mission-control display. Every
decision, comparison, flow, and structure becomes a live visual cell — charts,
diagrams, 3D scenes, animated SVGs. The display builds up as you work.

It probably doesn't make you more productive. Das Blinkenlights for AI sessions.

https://github.com/user-attachments/assets/d08aa14f-2a12-4f6d-a107-d71d98529dac

---

## Themes

The dashboard ships a wardrobe of themes — switch via `?theme=` in the URL
or the `THEME` chip in the HUD.

| Theme | Feel |
| ----------- | ---------------------------------------------------------- |
| `lab` | Default dark, cyan accent |
| `mars-blue` | The Expanse, Rocinante — cobalt tactical radar, bezel gauges |
| `mars-red` | The Expanse, classic MCRN — red war-table, Donnager data stack |
| `earth` | The Expanse, UN Navy — royal-blue situations plot, institutional |
| `drift` | The Expanse, OPA/Belter — amber orbital plot, salvage eclectic |
| `vigil` | MCU/Jarvis — cold electric cyan, arc reactor gold |
| `ops` | Star Trek LCARS — full L-frame chrome |
| `circuit` | Tron Legacy — hard grid, neon data strip |
| `noir` | Blade Runner 2049 — amber holograms, blue-black |
| `terminus` | Alien/Nostromo — phosphor green, CRT vignette |
| `renegade` | Mass Effect N7 — omnitool orange, diagonal geometry |
| `mainframe` | ReBoot (1994) — Energy Sea teal |
| `conclave` | Eva/NERV — amber scan lines, monospace |
| `minimal` | Vercel/Linear — clean flat light |
| `gastown` | Steampunk brass + serif |
| `hackers` | Hackers (1995) Gibson canyon — cyan-dominant, rare magenta |
| `hailmary` | Project Hail Mary — cyan-white wireframe, monochrome |

Each theme ships per-theme entrance animations and window-edge chrome
authentic to its source material. Themes also declare a preferred layout
that activates on switch.

The four faction themes from *The Expanse* — each with its own live
tactical furniture, not just a palette swap:

![The four Expanse faction themes: mars-blue, mars-red, earth, drift](assets/expanse-themes-2x2.png)

https://github.com/user-attachments/assets/6da05581-f458-48f4-9044-4ad3795d152f

---

## mixed3d — the canyon flythrough

The `hackers` theme pairs with a `mixed3d` layout that arranges your
cells onto the faces of a city of glass towers. A swoopy camera tours
the canyon, climbing between corridors and pausing on tier-1 cells as
it passes. The visual lineage is *Hackers* (1995) — Ellingson Mineral
Company's Gibson — with a bit of *Tron Legacy* and *Ghost in the
Shell* in the mix.

https://github.com/user-attachments/assets/7faee1aa-e2e8-4f6a-b5e9-b938624c055f

Try it:

```
http://localhost:8766/?theme=hackers&layout=mixed3d
```

Cells render in three LOD tiers as the camera approaches: ambient
decorative bed (tier 2, shared per-substrate textures) → text/title
snap (tier 1 mid) → full graph render (tier 1 close). Mermaid,
animated-SVG, treemap, gauge, force-graph, timeline-ribbon, and
trajectory substrates all render in-place on tower faces. Click any
cell to park the camera in front of it; press `R` to resume the tour.

---

## Get running in 5 minutes

**Requirements:** Python 3.11+, Node.js 18+, an Anthropic API key, a
running Claude Code session.

```bash
git clone https://github.com/justinstimatze/lucida && cd lucida
uv venv && uv pip install -e .
npm install # pulls mermaid + jsdom + puppeteer (bundles its own Chromium, ~170MB)
cp .env.example .env
# fill in your ANTHROPIC_API_KEY in .env
```

Why `npm install`: lucida lints mermaid specs at mint time and
pre-renders mermaid diagrams server-side so the browser never blocks
on `mermaid.render()`. Both rely on Node deps. Puppeteer's
`postinstall` hook downloads a bundled Chromium — no system Chrome
required, and the download only happens once per machine.

Start the renderer — open this on your second monitor and leave it there:

```bash
python3 serve.py
# http://localhost:8766/
```

`serve.py` bundles the static server and the snap receiver (which
persists Mermaid SVG renders into `cells/` so heavy substrates don't
re-render every session). `python3 -m http.server 8766` works too but
skips the cache.

For the Tron/Hackers (1995) Gibson canyon look on first run, try:

```
http://localhost:8766/?theme=hackers&layout=mixed3d
```

Start watching your Claude Code session:

```bash
python watcher.py \
--transcript ~/.claude/projects/.../transcript.jsonl \
--watch 30 --write --generate
```

That's it. New cells appear as the conversation progresses.

The display starts blank — cells mint as new content appears in the
transcript. Start a conversation in Claude Code and within a few exchanges
you'll see the first cells land. You'll immediately feel cooler.

Prefer one command? `./scripts/start.sh` launches `serve.py` and `watcher.py`
side-by-side with labeled output. Edit the script to point at your own
transcript path.

---

## What it produces

Lucida reads each passage in your conversation and picks a reasonable visual
for it automatically:

- **Graphs and diagrams** — architecture, flows, entity relationships, state machines
- **Charts** — comparisons, cost breakdowns, quantitative series
- **Tables** — structured decisions, callouts, tradeoff matrices
- **Treemaps** — proportional categorical breakdowns
- **3D wireframes** — topology, spatial structure (Three.js, FUI-style)
- **Animated SVGs** — cycles, decay, state transitions
- **Sparklines** — single-variable trajectories
- **Timeline ribbons** — chronological events with horizontal flow
- **Gauges** — single scalars within a stated range (memory, latency, score)

Ambient FUI flair — transient cells, mint-time scrubbers, per-theme ambient
motion — appears automatically. No prompts required, no payload, no static
chrome. Implies "computer go beep boop."

Visuals arrive pre-themed to the active theme. No configuration needed — the
classifier chooses the substrate, the specialist generates the spec, and the
renderer paints it.

---

## Cost

About **$0.02–0.03 per cell** using Sonnet 4.6. A busy hour-long session
mints 30–80 cells — roughly $0.60–$2.00. Classifier calls are cached.

Turn off `--generate` to run the classifier only (free) and mint manually
when you want a visual.

### Where the money goes

Measured with `tools/spend_audit.py`, which reconstructs per-stage spend
from the cache counters recorded in your own `cells.json` — run it on your
data rather than trusting anyone's averages:

```bash
python tools/spend_audit.py # calibrated (a few free count_tokens calls)
python tools/spend_audit.py --no-calibrate # fully offline
```

On a long real session the classifier was ~44% of recorded spend (it runs
once per segment with an ~11.5K-token cached prefix), with the rest spread
across the specialists — none above ~11%. Within the classifier, cost
splits roughly half cached-prefix reads, half its own output tokens.

### Why the classifier stays on Sonnet

The obvious cheap move — flipping the classifier to Haiku 4.5 for the ~3x
rate cut — was tried and **rejected on quality**: on a 72-snippet
stratified replay (both models, same prompt), Haiku agreed with Sonnet on
cell_type only 36% of the time and collapsed half the sample to
low-confidence `text`, which the confidence gate then suppresses. The
saving would have arrived as a half-empty dashboard. The replay harness is
`tools/classifier_agreement_check.py` — re-run it before trying another
classifier model (every stage's model is overridable via `LUCIDA_*_MODEL`
env vars; see `.env.example`).

What *does* cut cost without touching judgment: the classifier prompt asks
for telegraphic one-sentence reasoning (output tokens are the expensive
half), and every stage sets a prompt-cache breakpoint, so keeping the
watcher polling inside the 5-minute cache TTL keeps prefix reads at ~10%
of list price.

---

## Watcher options

```bash
python watcher.py \
--transcript # Claude Code .jsonl transcript
--watch 30 # poll interval in seconds (omit for one-pass)
--write # persist to cells.json
--generate # call specialists (costs API tokens)
--session-id # tag cells with a session name
--max-cells all # default — keep every cell; pass N to cap at last N
```

**Cells accumulate by default.** `cells.json` grows with each minted cell.
Pass `--max-cells N` (or `LUCIDA_MAX_CELLS=N`) if you want a rolling cap —
e.g. `--max-cells 500` keeps only the last 500.

Multiple sessions:

```bash
# Terminal 1
python watcher.py --transcript session-a.jsonl --session-id A --watch 30 --write --generate

# Terminal 2
python watcher.py --transcript session-b.jsonl --session-id B --watch 30 --write --generate

# View both side-by-side
# http://localhost:8766/?session=A,B
```

---

## HUD + URL params

The HUD at the top of the page is a live status bar. Click it to expand.
The `SESSION` chip opens a dropdown listing every session in the corpus.

Full URL param reference:

```
?theme= theme (lab / vigil / ops / circuit / noir / terminus /
renegade / mainframe / conclave / minimal / gastown /
hackers / hailmary)
?layout= layout (pack / grid / treemap / scatter / tactical /
terminal / mixed3d)
?session= scope to one session
?session=,, N-column mission-control view
?nocache=1 bypass the persistent SVG cache (force fresh mermaid
renders this load)
?perf=1 dev: enable per-frame perf logging
?debug=1 dev: enable mixed3d debug logging
```

In `?layout=mixed3d`, dev keys: `D` toggles the debug overlay (camera path
+ tower bounds), `Q` dumps a contact sheet of all rendered tier-1 cells
into `refs/gibson/live-shots/`.

---

## Related projects

- [agentic-city](https://github.com/mrf/agentic-city) by Mark Ferree —
kindred local-only FUI dashboard for AI sessions, but framed from the
opposite angle: it renders the codebase as an isometric SimCity with
active Claude/Codex/Gemini agents flying overhead as UFOs. Where
lucida centers the *transcript content* as visual cells, agentic-city
centers the *codebase* as terrain. The companion library
[agentwatch](https://github.com/mrf/agentwatch) is a Go transcript-
watcher that normalizes Claude/Codex/Gemini session state into one
feed — worth a look if you want multi-vendor session ingest.

---

## How it works (for the curious)

The pipeline behind each cell:

1. `watcher.py` polls the transcript for new prose
2. `segmenter.py` chops it into discrete snippets
3. `classifier.py` assigns a substrate type; low-value snippets are suppressed
4. `specialists.py` produces a snippet-grounded visual spec — a forcing-step
audit checks that the specialist didn't invent data not in the source
5. Cell lands in `cells.json`; the renderer polls and paints it live
6. Every N mints, `reflect.py` synthesizes the stream into a summary cell

The `UserPromptSubmit` hook injects recent mints into your next Claude Code
prompt, so the conversation knows what just landed on the display.

To wire it up, add this to your `~/.claude/settings.json`:

```json
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/path/to/lucida/hooks/recent_mints.sh"
}
]
}
]
}
}
```

The hook is silent when nothing has minted recently — it only speaks when
there are new cells. Set `LUCIDA_MINT_WINDOW_MIN=30` (default: 60) to
tune the lookback window.

---

## Adapters

Flatten any AI session log into the format the watcher expects:

```bash
python -m adapters.cli --source claude-code --out /tmp/transcript.txt
python -m adapters.cli --source aider --out /tmp/transcript.txt
```

---

## Files

```
lucida/
├── index.html renderer
├── notebook.css all theme chrome
├── themes/ per-theme token JSON
├── serve.py static server + snap receiver
├── orchestrator.py one-shot entry point
├── watcher.py continuous listener
├── specialists.py visual spec generators
├── classifier.py substrate classifier
├── reflect.py synthesis cells
├── adapters/ transcript adapters
├── scripts/start.sh launches serve + watcher together
└── hooks/recent_mints.sh Claude Code prompt injection hook
```

Not committed: `cells.json`, `mint_log.jsonl`

---

## Development

```bash
uv venv && uv pip install -e .[dev]
pre-commit install
```

**Lint:**
```bash
uv run ruff check .
uv run ruff format .
```

**Tests:**
```bash
uv run pytest tests/
# integration tests (needs ANTHROPIC_API_KEY):
uv run pytest tests/integration/
```

CI runs lint + tests + a bandit security scan on every push.

---

## Known limitations

- **Single-user, local-host by default.** `serve.py` binds 127.0.0.1.
No auth layer — if you expose the port externally, anything that can
reach it can read your cells and mint log.
- **State files are POSIX-only.** `cells_lock` and `state_lock` use
`fcntl.flock`. Windows users will run without locking — fine for
single-process use, race-prone for parallel watchers.
- **Cells are LLM output rendered with DOMPurify sanitization.** HTML
and SVG cells are sanitized before insertion (strips ``,
event handlers, dangerous URLs). A bug in DOMPurify or a future
sanitizer-bypass would still be exposure for a session run with an
attacker-controlled transcript.
- **API cost is on the user.** Every transcript turn that lands a mint
triggers a classifier + specialist call (plus an occasional
reflection). Default models are tuned for cost, but a runaway
transcript ingestor will burn through API credit. Set
`LUCIDA_RETRIGGER_SCORE_FLOOR` higher to make the mint gate stricter.
- **Mixed3d is GPU-heavy.** ~250-500MB GPU memory at saturation
(~1500 cells in scene, 300-entry snap cache). Integrated GPUs may
drop frames; use `?layout=pack` for a pure-2D mode.
- **No Anthropic-side context window cap.** Long sessions accumulate
context in `recent_cells` for the orchestrator. We don't truncate.
A multi-day session could hit `200k context` errors.
- **Cell substrate prompts are tuned for code/dev transcripts.** Other
transcript domains (writing, research) work but may classify
differently than expected. Override via the `--type` CLI flag.