Adds a working Dark/Light toggle (next to the language switcher, same row
as EN/VI) and re-themes the whole dashboard, not just the handful of
components that already used semantic tokens.
- Tailwind darkMode:"class" + CSS-variable color tokens (client/src/index.css,
tailwind.config.js): surface.0-5, border/border-light, accent/accent-hover,
fg.primary/secondary/muted, status.success/danger/warning. One class flip
on <html> re-themes everything — no per-element dark: variant pairs.
- useTheme() hook: localStorage-persisted, defaults to dark, no
prefers-color-scheme fallback (client/src/hooks/useTheme.ts).
- Mechanical, table-driven migration (scripts/migrate-color-tokens.mjs,
scripts/tokenize-status-colors.mjs, scripts/darken-status-colors.mjs) of
every raw neutral/gray/slate + emerald/red/amber Tailwind utility across
client/src onto the new tokens, so every badge/button/component pulls the
same shade per status/role instead of each picking its own.
- Palette values are the literal Radix Colors (radix-ui.com/colors) scale
constants — slate/blue/green/red/amber steps 1-12 — adopted after three
rounds of hand-picked values that kept overshooting (flat, then too dark,
then glaring); see docs/superpowers/specs/2026-07-31-color-redesign-
dark-light-mode-design.md for the full history and role mapping.
- PipelineMap: done/current/failed/passed-no-evidence/detected share one
visual language (border + text + translucent wash of the same status
color); `current` alone stays a solid accent fill, the one state that
gets to look bolder ("you are here").
- LaneCard: removed the stage/kind/auto-stage chips that duplicated the
Workspace lane-detail header already showing them.
Categorical/decorative hues (violet, indigo, cyan, teal, sky, rose, pink,
orange, yellow, and blue where it plays a role-coloring part e.g. message
bubbles) are deliberately out of scope — collapsing those onto shared
tokens would erase the distinction between different kinds of thing, not
a status.
Claude Code Monitor
Internal SmartGift build. Local-first dashboard for Claude Code: hooks POST every tool call to an Express + SQLite server, a React UI updates over WebSocket, and lanes track parallel agent work through a pipeline.
Internal build — all rights reserved.
What it does
- Sessions, agents, events. Everything Claude Code emits, recorded and searchable: tool calls, token usage, cost, subagent trees, transcripts.
- Lanes. One lane per working directory, surviving session restarts. A lane moves through pipeline stages and the dashboard shows where it is.
- Stage detection. The stage is inferred from the tool stream, so a session
that never calls
ccam stagestill shows progress — rendered dashed amber and never as done, because an inference is not evidence. - Run Claude from the browser. Spawn a session in a lane's directory, stream its output, send follow-ups, resume any past session.
- Analytics, alerts, Kanban and a workflow view, plus an MCP server and a CLI.
Requirements
Node >= 20 (engines in package.json). Node 24 is what the test suites
are verified on — node 25 currently breaks 6 server tests through a
better-sqlite3 ABI mismatch and 20 client tests through a global localStorage
change.
Install and run
npm run setup # root, client and vscode-extension dependencies
npm run build # builds the client into client/dist
npm start # serves the built client and the API on :4820
Open http://localhost:4820.
Development, with hot reload:
npm run dev # server on :4820, Vite client on :5173
DASHBOARD_PORT overrides the port. postinstall writes the Claude Code hook
entries that feed the dashboard.
The CLI
ccam is linked by npm run setup; otherwise call node bin/ccam.js.
ccam status # is the dashboard up
ccam start # start it in the background and wait for healthy
ccam sessions # recent sessions
ccam lanes # lanes with stage and progress
ccam stage <name> # declare the current lane's stage
ccam tail # live event feed
ccam --help lists the rest.
Lanes
A lane is a working directory the dashboard watches. Two kinds:
- adopted — a directory you already had. The dashboard only reads it; it is never reset or deleted.
- managed — a git worktree the dashboard created under
LANES_ROOT. It owns the full lifecycle and may reset or remove it, behind a three-check destroy guard and a counted preflight the caller has to echo back.
ccam lanes add --cwd /path/to/repo --title "My feature" # adopt
ccam lanes add --repo /path/to/repo --slug my-feature # managed worktree
The declared stage comes from ccam stage. The inferred stage comes from tool
events and expires after DETECTION_TTL_MS (default 5 minutes), so a lane can
move backwards between work sessions. Detection never writes the declared stage,
and an inferred node never renders as done.
docs/LANES.md has the pipeline model, the destroy guard, the
preflight contract, the Workspace page, and GET /api/lanes/:id/git.
Tests
npm run test:server # node:test
npm run test:client # Vitest
Both must be green before a commit; the pre-commit hook runs them plus Prettier.
Layout
| Path | What |
|---|---|
server/ |
Express API, SQLite schema, hook ingest, lane and worktree libraries |
client/ |
React 18 + Vite + Tailwind dashboard |
bin/ccam.js |
CLI |
mcp/ |
MCP server exposing read-only dashboard tools |
desktop/ |
Electron wrapper that embeds the server |
docs/ |
Architecture, API, lanes, database, deployment |
plugins/ |
Claude Code plugins shipped with the dashboard |
Docs
ARCHITECTURE.md— request flow, schema, WebSocket surfacedocs/LANES.md— lanes, pipelines, stage detectiondocs/API.md— REST endpoints (openapi.yamlis generated)docs/DATABASE.md— tables and migrationsINSTALL.md·DEPLOYMENT.md·DESKTOP.mdCLAUDE.md— the rules an agent working in this repo must follow