claude-code-dashboard

agent
Security Audit
Fail
Health Warn
  • No license — Repository has no license file
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 11 GitHub stars
Code Fail
  • process.env — Environment variable access in lib/auth.js
  • os.homedir — User home directory access in lib/discovery.js
  • fs module — File system access in lib/discovery.js
  • os.homedir — User home directory access in lib/files.js
  • fs module — File system access in lib/files.js
  • network request — Outbound network request in lib/notify.js
  • fs.rmSync — Destructive file system operation in lib/ptylink.js
  • os.homedir — User home directory access in lib/ptylink.js
  • fs module — File system access in lib/ptylink.js
  • exec() — Shell command execution in lib/search.js
  • fs module — File system access in lib/search.js
  • exec() — Shell command execution in lib/sessions.js
  • process.env — Environment variable access in lib/sessions.js
  • os.homedir — User home directory access in lib/statusline.js
  • fs module — File system access in lib/statusline.js
  • fs module — File system access in lib/transcript.js
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Self-hosted control room for Claude Code and Codex — persistent sessions you can drive from your phone, Chromebook, or any browser.

README.md

Claude Dashboard

Run Claude Code (and Codex) from your phone. Or your Chromebook. Or any browser.
Your PC does the work; you just drive.

This is a self-hosted control room for AI coding agents. The session engine runs on
your Windows PC and the UI opens anywhere — start a task from your desktop, check on
it from your phone on the couch, approve a permission prompt from a coffee shop. The
agents keep running when you close the tab; reattach from any device and the terminal
replays exactly where things stand.

No cloud middleman, no per-token API bills. It drives the Claude Code and Codex CLIs
directly, on your existing subscriptions.


Why it's nice to use

  • 📱 Genuinely roamable. One PC, every screen. Sessions are owned by the server,
    not by a browser tab, so nothing dies when a device sleeps or drops off Wi-Fi.
    Reconnect and the full scrollback is there.
  • 💬 Chat view or raw console, per session. Read the conversation as clean chat
    bubbles — italics, fenced code with a copy button on every block, multi-choice
    prompts rendered as real options — or flip to the actual terminal for TUI menus.
    One tap between them.
  • 🤖 Two agents, one brain. Run Claude Code and OpenAI Codex side by side.
    With the optional claude-mem plugin they
    share a single memory store — what one learns, the other can recall.
  • 🚦 It tells you what it's doing. A phase pill — Plan, Research, Exec, Debug,
    Verify, Done, Blocked — rides above the composer and on every session card, next to
    a live context-window gauge. You can see which sessions are thinking and which are
    stuck without opening one. (Powered by the bundled status line; see below.)
  • 🔔 It taps you when it needs you. Push notifications fire when a session
    finishes or hits an approval prompt — but only while you're not looking at the
    dashboard. Tap the notification and it opens that exact session.
    Pushover if you configure it, ntfy
    otherwise.
  • 🟦 See who's waiting at a glance. A session stuck on a question glows in the
    sidebar and floats to the top; a working one waves its three dots.
  • 🎚️ Steer mid-session. Dropdowns in the composer switch a session's permission
    mode and its model live — loosen one session for a trusted task, keep another on
    a tight leash, bump one to a bigger model — without restarting anything.
  • 📎 Attach files from the PC, not just the phone. The attach button browses your
    actual machine (newest first, thumbnails on) so you can hand a session a screenshot
    that never left the desktop. Anything the browser uploads lands in Downloads with a
    clean, deduped name.
  • 🖼️ Artifacts gallery + file browser. Everything a session produced, as
    thumbnails — PDFs rendered inline, images, the lot — alongside a real directory
    tree with an editor. Upload into the folder you're browsing; download the open
    file to whatever device you're reading on.
  • 🔎 Search that behaves. Full text across every past conversation, with word
    matching that folds endings, "quoted phrases" for exact, word* for prefixes,
    and /project to scope a search to one repo.
  • 📝 Notes that stick to the work. A dated log per session card, plus a general
    notes sheet with titles — for the thread you'll pick up tomorrow.
  • ✅ One-tap commit and push, right next to Send.
  • 🖥️ PowerShell sessions too. Same persistent-terminal engine, for when you just
    need a shell on the box.
  • ♻️ Survives restarts. A watchdog auto-restarts a dead server and (optionally)
    pushes you if it can't. Sessions resume via claude --resume. Rename a session and
    the name follows the conversation even when Claude moves it to a new transcript.
  • 📊 Optional deploy/build badges. Point it at a Netlify site and any GitHub
    Actions workflows and the header carries a live dot for each, with a button that
    dispatches a fresh build. Entirely opt-in — configure nothing and the row isn't
    there.
  • 🎨 Light, dark, or follow the device. Installable PWA. Material-3 UI that
    installs to your home screen and behaves like a native app, split-view on desktop,
    pull-to-refresh on mobile.

No build step, no framework, no database — server.js, a handful of files in lib/,
and vanilla JS in public/. It's small enough to read in an afternoon.


How it works

  • The PC is the "tmux". Each session is a persistent Windows ConPTY running
    claude.exe, codex, or PowerShell, owned by server.js — not by any browser tab.
  • Transcripts are the memory. lib/discovery.js scans Claude Code's native
    ~/.claude/projects/**/*.jsonl store (head/tail chunks only — these files get huge)
    for the history list, context gauges, model, and branch. The live PTY stream is the
    source of truth for status, spinners, and permission prompts.
  • Sessions say which transcript they're on. A /clear, a /resume, or a rewind
    moves a conversation into a different .jsonl while the process and the card stay
    put. Rather than guess from timestamps — which gets it wrong, and hands two panes
    each other's conversations — every session the dashboard launches reports its own
    id back through the status line (lib/ptylink.js). No heuristics, no duplicate
    cards.
  • The frontend is static, served two ways:
    1. Straight from the PC server (works out of the box, shared-token auth).
    2. From Netlify with Clerk sign-in, pointing back at the PC over HTTPS — the
      roaming setup: one stable URL, real login, no token-in-the-link.

⚠️ Security — read this before you expose it

This dashboard spawns real AI agents with real access to your machine — they read
and write files, run commands, and reach the network. Depending on the permission mode,
they may do so without asking. That is powerful and it is a foot-gun. Treat the URL
to this dashboard as a key to your computer.

Do:

  • Keep it on a private network. Tailscale is the intended
    setup: tailscale serve --bg 4310 gives you an HTTPS URL reachable only from your own
    devices. Do not port-forward 4310 to the open internet.
  • Set a long, random token in config.json (or use Clerk, below). If you go the
    public-tunnel route, use Clerk with ALLOWED_EMAILS and ALLOW_TOKEN_AUTH=false — an
    auth prompt is then the only thing between the internet and a shell on your PC.
  • Understand the permission modes. default asks before everything; acceptEdits
    lets file edits through but asks before shell commands; auto (the shipped default)
    is Claude Code's classifier-gated mode, which waves through what it judges safe and
    still stops for the rest; bypassPermissions asks for nothing. Pick deliberately —
    and note that each session's dropdown can change its own.

Know: an AI agent can be steered by text it reads — a poisoned README, a web page, a
dependency. With approvals off and no sandbox, an injected instruction runs immediately.
Keep approvals on for anything you don't fully trust, and don't mount sensitive network
shares you aren't actively working on.

Secrets (config.json, watchdog-config.json, public/env.js) are gitignored and
never committed. Start from the .example.json files.


Quick start (Windows PC)

npm install
copy config.example.json config.json    # then edit: set a random "token"
node server.js                           # or: .\start-dashboard.ps1

Open http://localhost:4310, paste your token once, and you're in. That's the whole
local setup — everything below is optional.

Auto-start on login:

schtasks /create /tn "Claude Dashboard" /sc onlogon /rl limited ^
  /tr "powershell -WindowStyle Hidden -File 'C:\path\to\Claude Dashboard\start-dashboard.ps1'"

Prerequisites: Node 18+, Claude Code installed and
signed in. Codex is optional — install and
sign in, and a Codex option appears in New Session automatically.


Roaming setup (optional)

Reach it from anywhere with a real login instead of a token link:

  1. Expose the PC over HTTPS. Tailscale (private, recommended):
    tailscale serve --bg 4310https://<pc>.<tailnet>.ts.net. The Netlify page is
    HTTPS, so the backend must be too (browsers refuse ws:// from an HTTPS page).
  2. Host the frontend on Netlify. Point it at your repo; set BACKEND_URL to the
    HTTPS address above and CLERK_PUBLISHABLE_KEY in Netlify's env vars. netlify.toml
    builds public/.
  3. Set up Clerk for sign-in — see the table below.

Configuration

Set as environment variables or as camelCase keys in config.json
(see config.example.json):

var config.json key notes
CLERK_SECRET_KEY clerkSecretKey enables Clerk mode; verifies JWTs (PC only — never on Netlify)
CLERK_PUBLISHABLE_KEY clerkPublishableKey must match the Netlify one
ALLOWED_EMAILS allowedEmails comma-separated allowlist — set this, or any signed-up Clerk user gets in
FRONTEND_ORIGIN frontendOrigin CORS allowlist
ALLOW_TOKEN_AUTH allowTokenAuth false locks it to Clerk only

Also in config.json: port (4310), host, token, model (opus),
permissionMode, notify (ntfy topic and/or Pushover keys), pinnedProjects,
statusBadges, fileExplorerUrl / fileExplorerPorts. The Claude/Codex binary paths
are auto-detected.


Optional extras

The status line (statusline/)

A two-line status line for Claude Code itself, vendored here because the dashboard
depends on one piece of it: reportPty tells the server which transcript a live
session is actually writing to, which is what keeps a /resume from spawning a
duplicate session card. It's also where the phase pill comes from.

statusline/README.md has the install; node scripts/statusline-sync.js keeps the
copy in ~/.claude/statusline and the one in this repo from drifting apart.

Deploy and build badges (statusBadges)

Opt-in dots in the header, sidebar and mobile session view for whatever you ship:

"statusBadges": {
  "netlify": {
    "label": "Netlify", "what": "Website deploy",
    "siteId": "<API ID from Netlify → Site configuration>",
    "url": "https://app.netlify.com/projects/yoursite/deploys"
  },
  "workflows": [
    { "target": "android", "label": "Android", "what": "Android app build",
      "repo": "you/your-repo", "workflow": "build-android.yml", "ref": "main",
      "confirm": "Trigger a new Android build on main?" }
  ]
}

Workflow badges read the latest run through your gh auth login (so private repos
work without handing the dashboard a token), and each badge's ▶ button dispatches a
new run — the workflow must declare workflow_dispatch. The Netlify "last published"
stamp additionally wants the Netlify CLI logged in; without it you get the dot and no
timestamp. Leave netlify null and workflows empty and the whole row disappears.

The watchdog (watchdog.ps1)

Restarts a dead server on a schedule. Copy watchdog-config.example.json to
watchdog-config.json to be pushed when a restart isn't sticking; sshHost puts
"how to reach the box" into that alert. With no config file it still restarts, just
silently.


Layout

  • server.js — Express + WebSocket server, auth, API, session lifecycle
  • lib/sessions.js — persistent PTY manager (scrollback replay, status scraping, permission/model control)
  • lib/discovery.js — transcript scanner (chunked, never loads whole files)
  • lib/transcript.js — incremental chat-message reader
  • lib/ptylink.js — which transcript a live session is on, reported rather than guessed
  • lib/statusline.js — phase + context fill for the chat view
  • lib/search.js — full-text search across transcripts, with /project scoping
  • lib/files.js — file browser, editor, uploads and downloads
  • lib/auth.js — Clerk JWT verification + email allowlist, with legacy token fallback
  • lib/notify.js — presence-gated push (Pushover, ntfy fallback)
  • lib/screen.js — terminal screen model behind the chat view
  • public/ — xterm.js + vanilla-JS frontend, installable PWA
  • statusline/ — the vendored Claude Code status line (see above)
  • watchdog.ps1 — restarts a dead server, alerts if it can't
  • scripts/build-static.js — copies vendor files + writes env.js (postinstall & Netlify build)

Built for personal use and shared in case it's useful. No warranty — you're running
autonomous agents on your own hardware, so read the security section and use good sense.

Reviews (0)

No results found