Command Center is a personal learning lab + mini “command center” dashboard built directly on the official Anthropic Claude Agent SDK. Not a wrapper. The SDK is the engine.
It pairs a small Express server with a vanilla-JS browser UI to expose the SDK’s agent loop in the most visible, hackable way possible. Multi-agent sidebar, per-agent system prompts + tools + models, session persistence, folder selection, @file autocomplete. Built in ~15 minutes on 2026-04-23 while evaluating whether the SDK could replace a months-old OpenClaw-based project (Clawless). Verdict: different problem, different tool — SDK is Claude-only, OpenClaw is multi-provider. Command Center is the Claude-native side of that comparison, and a sandbox for exploring what the SDK makes easy.
ANTHROPIC_API_KEY needed.ANTHROPIC_API_KEY and a per-provider auth model (see Clawless, which does this properly).ANTHROPIC_API_KEY in the shell, the SDK picks it up automatically.Browser (vanilla JS) → Express server (port 3333) → Claude Agent SDK → Claude Code CLI
│ │ │ │
│ /api/* routes query({...}) OAuth session
│ │ │
│ in-memory state Max plan subscription
│ (sessions, cwd, overrides)
One process, one port. No electron, no IPC bridge, no separate renderer build. tsx runs TypeScript directly. Static files serve from /public.
State model:
sessionByAgent: Map<agentId, sessionId> — SDK session IDs per agent (resume: threads conversations)modelOverride: Map<agentId, string> — per-agent model override vs agents.ts defaultcurrentCwd: string — working directory passed to every query() call| Route | Method | Purpose |
|---|---|---|
/api/agents |
GET | List agents with model + defaultModel |
/api/models |
GET | Available models (Opus/Sonnet/Haiku) |
/api/model/:agentId |
POST | Override model for an agent (empty body = reset to default) |
/api/cwd |
GET/POST | Read/set working directory |
/api/browse?path= |
GET | List subdirectories (folder picker) |
/api/files?q= |
GET | List files in cwd (@file autocomplete) |
/api/chat |
POST | {agentId, message} → {reply, toolUses, model, apiKeySource, cwd} |
/api/reset/:agentId |
POST | Clear an agent’s session |
Mirrors the Clawless v5 process. Every medium-or-larger task runs through all six roles in sequence. No task is complete until every role signs off.
Architect → Developer → Reviewer → QA → Performance Analyst → Security Analyst
| Role | Fires | Job |
|---|---|---|
| Architect | Before any code | Approves design, flags architectural risks, Go/No-Go |
| Developer | After Architect Go | Implements exactly the approved design |
| Reviewer | After build passes | Audits code correctness from actual source files |
| QA | After Reviewer sign-off | Writes + runs Playwright tests for everything delivered |
| Performance Analyst | After QA sign-off | Profiles hot paths, bundle size, latency, dead code |
| Security Analyst | After Performance sign-off | Threat model; surface risks to the user explicitly |
{error: string} with appropriate statusquery() options are complete (allowedTools, systemPrompt, cwd, resume, model) and type-safe/tests)Smoke · Agent chat · Session persistence · Model switching · Folder scoping · @file autocomplete · Error states
Every user-visible feature gets at least one Playwright test.
/api/cwd, /api/browse, /api/files — resolved paths must stay under the user’s controlWhen wrapping a session, spawn Performance Analyst and Security Analyst as background agents (run_in_background: true). Their reports land in docs/audits/ (public) for reference, and in .notes/handoff.md (private) for next-session triage.
npm (not bun). Small project, no build pipeline, no reason to diverge.tsx for TypeScript directly. No compile step.allowedTools, systemPrompt, model, cwd. Pass resume when continuing a conversation.session_id off the first system.init message in the SDK message stream.tool_use blocks to the UI for visible trace — the “thinking” should be legible.Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>.gh pr create, merge it (typically --squash or --merge), then delete the local + remote branch. Don’t stop at “pushed to a feature branch” and wait for follow-up; the user does not consider that “done.”After any major change, update before the session ends:
.notes/handoff.md (private, gitignored) — current state, what changed this session, what’s nextbacklog.md — move completed items to Done, add new items discovered during workarchitecture.md — new design decisions, updated file mapdocs/case-studies/ (public, when useful) — case studies for patterns discovered, iteration loops, decisions worth documenting.notes/drafts/ (private, gitignored, when useful) — LinkedIn / blog drafts per session. Style: measured optimism, personal reflection, ends with a question.The .notes/ directory is gitignored. Anything in there stays on your disk
and never lands on the public GitHub repo — use it for session handoffs,
draft posts, and internal thinking. Everything else (docs/, backlog.md,
architecture.md, CLAUDE.md, README.md, source, tests, screenshots) is public.
After any change to src/server.ts or src/agents.ts, restart automatically:
lsof -ti:3333 | xargs kill -9 2>/dev/null
cd "~/Desktop/claude-agent-lab" && npm run serve &
Frontend changes (public/*.html|css|js) need only a browser reload — no server restart.
Tell the user: “Restarted the server — reload the browser to pick up changes.”
cd "~/Desktop/claude-agent-lab"
npm install # if node_modules missing
npm run serve # starts Express on :3333
open http://localhost:3333/
Prereqs:
claude CLI installed and logged in (Max plan OAuth)ANTHROPIC_API_KEY NOT set in shell (unset lets OAuth take over)claude-agent-lab/
├── src/
│ ├── agents.ts # Agent definitions (systemPrompt, tools, model)
│ ├── server.ts # Express + SDK glue (~180 LOC)
│ └── hello.ts # First smoke test — URL-summarizer agent
├── public/
│ ├── index.html # Dashboard markup
│ ├── style.css # Dark command-center theme
│ └── app.js # Frontend logic (vanilla JS)
├── tests/ # Playwright tests (added in C06)
├── docs/
│ ├── case-studies/ # Patterns, iterations, decisions
│ └── drafts/ # LinkedIn drafts per session
├── CLAUDE.md # This file
├── architecture.md # Technical architecture
├── backlog.md # Sequential backlog (C##)
├── .notes/ # Private, gitignored — handoff + drafts
│ ├── handoff.md # Session-to-session continuity (private)
│ └── drafts/ # LinkedIn / blog drafts (private)
├── package.json
├── tsconfig.json
└── .gitignore
| File | Purpose |
|---|---|
CLAUDE.md |
This file — project rules and quick reference |
backlog.md |
Feature backlog prioritized by importance (C##) |
architecture.md |
Technical architecture and design decisions |
.notes/handoff.md |
Session handoff notes for continuity (private, gitignored) |
npm (not bun — small project, no build pipeline).Co-Authored-By footer.agents, hooks, resume, cwd, model, etc.src/, public/, tests/, scripts/F1–F7: scaffold, multi-agent sidebar, per-agent prompts/tools/sessions, folder picker, @file autocomplete, model selector, auth+model footer.
| # | Feature | Notes |
|—|—|—|
| C01 | Sub-agent delegation | Main routes via SDK agents: option; 🤝 chips |
| C02 | Token-by-token streaming | NDJSON; includePartialMessages: true |
| C03 | Task queue + Haiku auto-routing | Three-column board, classifier in server.ts |
| C06 | Playwright smoke + engine | Two projects in playwright.config.ts |
| C08 | Markdown rendering | marked + DOMPurify + highlight.js via jsDelivr |
| C09 | Persistent memory (SQLite) | better-sqlite3 at data/lab.db; injected as <persistent-memory> |
| C10 | Slash commands + autocomplete popover | /help, /clear, /agents, /model, /think, /plan, /export |
| C11 | Plan mode | Per-agent permissionMode: 'plan' toggle |
| C12 | (file checkpointing — flag pulled in audit; UI deferred) | See backlog C12-follow-up |
| C13 | WhisprDesk voice | Mic + SSE listener + speak button; WAV conversion in browser; ⌥V shortcut |
| C14 | Settings modal | SQLite-backed; secrets masked; env-var fallback |
| C15 | Custom agents (CRUD) | + New agent; SQLite-backed; built-ins read-only |
| A1 | Cost & token tracking | OAuth-aware (no $ for Max plan); per-message + session totals |
| A2 | Session history + restore | Conversations persist; click any past session to resume |
| A3 | Conversation export | /export md and /export json slash commands |
npm run serve on 127.0.0.1:3333 (LAN-isolated)~/Desktop/Command Center.command — auto-finds the project via candidate list (works whether it’s at ~/Desktop/claude-agent-lab or ~/Documents/projects/claude-agent-lab etc.)main.claude/skills/*/SKILL.md in cwdmaxTurns safety rail.notes/handoff.md — the most recent session-end notes (private, gitignored)backlog.md — full sequential backlog with change log at the bottomarchitecture.md — module-by-module file map + design decisionsgit log --oneline | head -20 — last ~20 commits for the recent shape of changesYou are part of a multi-agent team. Other agents may be running in separate terminals and can send you messages at any time via ClaudeLink.
read_inbox firstread_inboxsend before continuing your own workread_inbox to check for new messagesget_agents to list all connected agentspost_bulletin to post a status updateget_bulletin to read the bulletin board