Skip to content

Latest commit

 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Control Center

A local web dashboard for all your Claude Code sessions — live and historical. See every session's status at a glance, drill into transcripts, tasks, and token stats, mirror a live tmux pane in the browser, send prompts, answer permission dialogs, and interrupt turns — all from one page. Zero npm dependencies (Node stdlib backend + vanilla-JS frontend), no build step.

Security model

  • Binds 127.0.0.1 only; requests with a non-localhost Host header get 403.
  • A random per-launch token is required on every /api/* call (X-CCC-Token header, or ?token= for the EventSource URL). It is printed once at startup and never persisted.
  • This server can type into your terminals (tmux send-keys) — treat the URL+token like a credential. Keys are restricted to a fixed whitelist (Enter, Escape, arrows, Tab, BSpace, C-c, 1–9, y, n); prompts go through the tmux paste-buffer; only panes mapped to live Claude processes (or panes the server launched) are addressable.
  • Strictly read-only on ~/.claude — never writes, never deletes stale pid files. From ~/.claude.json it reads only the .projects key names (the file holds secrets; nothing else is exposed).
  • The server invokes tmux/osascript via execFile with argv arrays — no shell, ever. The bin/ccc launcher is a shell script but builds no command strings: quoted argv only, no eval.
  • Static serving is a fixed 3-file whitelist (/, /app.js, /style.css); request input is never joined into a filesystem path.
  • No dollar/cost figures anywhere in the API or UI (token counts only).

Requirements

  • macOS (notifications use the built-in osascript)
  • Node >= 18
  • tmux (>= 3.2 for direct-exec launches; 3.6b verified)
  • the claude CLI on your PATH

Install

git clone git@github.com:jskysim/claude-control-center.git
cd claude-control-center

No npm install needed — there are zero dependencies.

Run it

./bin/ccc          # or: node server.js

Open the printed http://127.0.0.1:7777/?token=... URL. Set CCC_PORT to change the port. Optionally symlink the launcher onto your PATH:

ln -s "$PWD/bin/ccc" ~/bin/ccc

The ccc claude workflow

cd into a project and run:

ccc claude            # instead of plain `claude`
ccc claude --resume   # any claude args pass through verbatim

This wraps claude in a ccc-<dir>-<rand> tmux session so the dashboard can control it (send prompts, answer dialogs, interrupt). Plain (non-tmux) terminal sessions still appear in the dashboard but are view-only — the prompt bar shows a relaunch hint. Any claude already running inside tmux is auto-adopted; ccc claude is convenience, not a requirement.

tmux tips

  • Detach with Ctrl-b d — the session keeps running and stays controllable.
  • tmux ls lists sessions; tmux attach -t ccc-... re-attaches (the dashboard's Info tab has a copy button for the exact command).
  • Killing the pane/window ends the Claude session.

API overview

All routes require the token. :id is a session id.

Method Path Purpose
GET /api/ping liveness check
GET /api/sessions all sessions, sorted busy → ready → idle → done
GET /api/sessions/:id full record for one session
GET /api/sessions/:id/transcript?tailKb=64 seed transcript entries (rest via SSE)
GET /api/sessions/:id/tasks task list
GET /api/stats activeSessions / sessionsToday / messagesToday / tokensTodayByModel
GET /api/projects known project cwds (for the New Session picker)
GET /api/events?token=... SSE stream
POST /api/sessions/new {cwd, prompt?} → launch claude in a new ccc-* tmux session
POST /api/watch {sessionId|null} → select which pane the server mirrors
POST /api/sessions/:id/prompt {prompt} → paste+Enter; resumes done sessions into tmux
POST /api/sessions/:id/keys {key} → whitelisted key (dialogs, Esc, arrows)
POST /api/sessions/:id/kill kill the session's tmux pane (404 if not tmux-backed)

SSE event names: sessions (full snapshot), transcript (appended entries), pane (rendered screen of the watched session), notify (in-page mirror of macOS notifications), plus comment heartbeats every 25s.

Manual verification

Headless E2E covers binding/auth, the read-only and exec-discipline audits, adoption, prompt/keys/kill delivery, pane mirroring, notification debounce, and SSE — but a few checks need a human at a browser/terminal:

  1. Select a tmux session → the Live tab mirrors keystrokes you type in the real terminal within ~1s.
  2. Send a prompt from the GUI → it appears in the real terminal and Claude runs; the Transcript tab streams the durable turn.
  3. Trigger a permission dialog → answer it with the [1] quick-key button → Claude proceeds.
  4. [Esc] mid-turn interrupts; busy→ready fires exactly one macOS banner.
  5. Prompt a done session → a new ccc-* session appears in tmux ls and is attachable; the response streams in.
  6. Multiline prompt into the real claude TUI pastes without premature submit (bracketed paste).
  7. New Session modal → a new JSONL appears under the right ~/.claude/projects/... directory.

About

Local web dashboard for Claude Code sessions — live status, transcripts, prompts, and tmux control from the browser

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages