A web-based UI for running Claude Code as a persistent headless server. Submit prompts, manage projects, stream real-time output, and interact with Claude's tools — all from your browser.
Claude Code's CLI is powerful but tied to a single terminal session. Claude Code Server turns it into a multi-project, multi-job web service with:
- A persistent web UI you can access from any browser
- Multiple concurrent Claude sessions running in parallel
- Real-time streaming of Claude's reasoning, tool calls, and results
- Interactive approval system for human-in-the-loop workflows
- Session persistence — resume conversations even after server restarts
- An embedded terminal, file browser, git panel, and more
git clone https://github.com/your-org/claude-code-server.git
cd claude-code-server
./setup.shThe setup script will:
- Check that Node.js 18+ is installed
- Prompt for your Anthropic API key (optionally saves to
.env) - Install all dependencies
- Start the development server
Then open http://localhost:5173 in your browser.
# Install dependencies
cd server && npm install && cd ..
cd client && npm install && cd ..
npm install
# Set your API key
export ANTHROPIC_API_KEY=sk-ant-...
# Start development mode (HMR)
npm run dev
# Server: http://localhost:3001
# Client: http://localhost:5173 <-- open thisNeed a custom API endpoint? Set
ANTHROPIC_BASE_URLto your proxy or gateway URL.
./setup.sh --prod # Build client + start PM2 daemon
# or
./setup.sh --prod --fg # Build client + run in foreground (no PM2)Production serves everything from a single port (http://localhost:3001).
See docs/setup.md for detailed installation and configuration options. See docs/deployment.md for production deployment, PM2, reverse proxy, and Docker.
| Feature | Description |
|---|---|
| Project Workspaces | Each project gets its own working directory. Claude reads, writes, and executes code scoped to that project. |
| Job Submission | Send prompts with optional image attachments. Claude executes with full tool access (Bash, Read, Write, Edit, Grep, Glob, WebSearch, etc.). |
| Real-time Streaming | WebSocket-powered live output — watch Claude think, call tools, and produce results as they happen. |
| Persistent Sessions | Jobs can run as long-lived sessions. Resume conversations, send follow-ups, or fork from any point in the chat history. |
| Interactive Approvals | When Claude asks a question or proposes a plan, you review and respond directly in the UI. |
| Panel | Description |
|---|---|
| Chat View | Rich chat interface with per-tool rendering, syntax-highlighted diffs, thinking blocks, and subagent nesting. |
| Terminal | Embedded xterm.js terminal connected to your project directory via WebSocket PTY. |
| File Browser | Browse project files with fuzzy search across names and content. |
| Git Panel | View diffs, stage/unstage files, commit, push, and pull — with "touched by this job" indicators. |
| Memories | View and edit Claude's memory files (CLAUDE.md hierarchy) directly. |
| Cron Tasks | See all scheduled tasks Claude has created (durable and session-scoped). |
| Feature | Description |
|---|---|
| Session Mode | Keep a Claude session alive indefinitely for ongoing work. Toggle between one-shot jobs and persistent sessions. |
| Fork & Edit | Branch conversations from any assistant turn, or edit and resend any of your messages. |
| Extended Thinking | Configure Claude's thinking budget and effort level (low/medium/high) per job. |
| Image Attachments | Drag-and-drop, paste, or browse to attach images to your prompts. |
| Import Local Sessions | Discover and import past Claude Code CLI sessions from ~/.claude/projects/. |
| Command Palette | Cmd+K to fuzzy-search across all jobs by name, prompt, or chat content. |
| Slash Commands | Type / for Claude Code commands (/compact, /model, /memory, etc.) or @ for file path autocomplete. |
| Project Archiving | Archive projects and jobs to keep your workspace tidy. |
See docs/usage.md for a detailed walkthrough of every feature.
The current implementation uses three different concepts that are easy to mix up:
status= runtime state:queued/running/idle/completed/failed/archivedmode= retention policy for the next turn:joborsessionsessionId= whether Claude SDK gave us a resumable session handle
Current behavior:
- A normal
jobentersidleafter a successful turn, starts a 5 minute grace timer, then auto-completes. - A
sessionentersidleafter a successful turn and stays there until the user closes it. Pin as Sessionon an already-idlejob is a true in-place conversion: it clears the grace timer and keeps the live channel open.Resume as Sessionon acompletedorfailedjob withsessionIdnow re-attaches the resumable SDK session immediately, so the job becomes a liveidlesession again.- A finished job without
sessionIdcan still accept a follow-up, but that follow-up starts a fresh Claude run on the same job record instead of resuming prior conversation context.
Why some completed/failed jobs cannot be resumed as a live session:
- The job failed before the SDK emitted its initial
session_id - The job was imported or created from legacy data without a stored
sessionId - The process/session was lost before a resumable session was captured
UI rules:
Pin as Sessionis only for a liveidleone-shot job.Resume as Sessionis only for a finished job with a resumablesessionId.- Finished jobs without
sessionIdshow a warning that follow-up input will start a new run without prior conversation context. idle/Session Activeis only shown after the server has re-established a real live channel.
Browser (React + TypeScript)
┌─────────────┬───────────────┬──────────────────────────┐
│ Sidebar │ Job List │ Job Detail / Terminal │
│ (Projects) │ │ Files / Git / Memories │
└─────────────┴───────┬───────┴──────────────────────────┘
│ REST API + WebSocket
┌─────────────────────┼─────────────────────────────────────┐
│ Express Server │ │
│ ┌──────────┐ ┌────┴─────┐ ┌──────────────────────┐ │
│ │ REST API │ │ WS Broker│ │ Claude Agent SDK │ │
│ │ Projects │ │ (logs, │ │ @anthropic-ai/ │ │
│ │ Jobs │ │ approvals│ │ claude-agent-sdk │ │
│ │ Files │ │ import) │ │ │ │
│ │ Git │ │ │ │ Tools: Bash, Read, │ │
│ │ Memories │ │ Terminal │ │ Write, Edit, Grep, │ │
│ └──────────┘ │ (PTY) │ │ Glob, WebSearch, ... │ │
│ └─────────┘ └───────────┬────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ projects/<name>/ │ │
│ │ (working dirs) │ │
│ └─────────────────────┘ │
└───────────────────────────────────────────────────────────┘
Tech Stack:
- Server: Node.js, Express, WebSocket (
ws),node-pty,@anthropic-ai/claude-agent-sdk - Client: React 18, TypeScript, Vite, xterm.js, Lucide icons
- Process Manager: PM2 (production)
- State: JSON file persistence (
projects/.state.json)
| Environment Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
(required) | Your Anthropic API key |
ANTHROPIC_BASE_URL |
https://api.anthropic.com |
Custom API endpoint (proxy, gateway) |
PORT |
3001 |
Server port |
PROJECTS_ROOT |
./projects |
Root directory for project workspaces |
All variables can be set in a .env file in the project root.
| Document | Description |
|---|---|
| docs/setup.md | Detailed installation, prerequisites, configuration |
| docs/usage.md | Feature walkthrough with screenshots and examples |
| docs/deployment.md | Production deployment, PM2, reverse proxy, Docker |
| docs/api.md | REST API and WebSocket reference for developers |
claude-code-server/
├── setup.sh # One-click install & launch
├── ecosystem.config.cjs # PM2 production config
├── package.json # Root scripts (dev, start, stop)
├── .env # API key (create this)
├── projects/ # Runtime data
│ ├── .state.json # Persisted state (projects + jobs)
│ └── <ProjectName>/ # Per-project working directories
├── server/
│ └── src/
│ ├── index.ts # Express server, WebSocket, job runner
│ ├── types.ts # Shared TypeScript types
│ └── claude-importer.ts # Local session discovery & import
└── client/
└── src/
├── App.tsx # Root layout, panels, command palette
├── components/ # UI components
├── hooks/ # State management, API client, autocomplete
├── styles/global.css # All styles (dark theme)
└── types/index.ts # Client-side type definitions
| Command | Description |
|---|---|
npm run dev |
Start dev server with HMR (client: 5173, server: 3001) |
npm start |
Build client + start production via PM2 |
npm stop |
Stop PM2 daemon |
npm restart |
Rebuild client + restart PM2 |
npm run logs |
View PM2 live logs |
npm run status |
Check PM2 process status |
npm run build:client |
Build client only (outputs to client/dist/) |
MIT
