Overview
Code Workspaces provide interactive Docker containers with in-browser terminals powered by xterm.js, WebSocket, and ttyd. They enable live coding sessions where you can execute commands, run code, and interact with the agent in real-time. Key features:- Ephemeral environments — Each workspace is an isolated Docker container
- Browser-based terminal — Full terminal emulation with xterm.js
- WebSocket connection — Real-time bidirectional communication
- Container lifecycle management — Automatic recovery and cleanup
- Session authentication — Secure access via JWT session tokens
Architecture
The system consists of several components working together:Data Flow
Container Creation
- Chat agent calls
start_codingtool createCodeWorkspaceContainer()inlib/tools/docker.jscreates a Docker container:- Image:
claude-code-workspace - Entrypoint:
ttyd bash - Port: 7681 (WebSocket)
- Container name:
code-workspace-{id}
- Image:
- Container registered in database with user ownership
- Browser redirected to
/code/{id}
Terminal Connection
- Browser loads
/code/{id}page TerminalViewcomponent (xterm.js) initializes- Opens WebSocket to
/api/code/ws/{id} ws-proxy.jshandles connection:- Authenticates session
- Verifies workspace ownership
- Proxies to container WebSocket
- Bidirectional WebSocket proxying begins
- User can type commands, agent can send output
Container Recovery
ensureCodeWorkspaceContainer(id) in lib/code/actions.js handles container state recovery:
- Inspects container via Docker Engine API (Unix socket)
- Determines state: running, stopped, exited, paused, dead, missing
- Takes action:
- Running → Return success
- Stopped/Exited/Paused → Restart container
- Dead/Missing → Recreate container
- Returns status:
'running','started','created','no_container','error'
WebSocket Authentication
Middleware can’t intercept WebSocket upgrades, sows-proxy.js authenticates directly:
Authentication Flow
- Reads
authjs.session-tokencookie from HTTP upgrade request headers - Decodes JWT using
next-auth/jwtdecode()withAUTH_SECRET - Validates session and extracts user ID
- Looks up workspace in database
- Verifies workspace belongs to authenticated user
- Rejects with:
- 401 if no valid token
- 403 if workspace not found or doesn’t belong to user
- Proxies WebSocket bidirectionally to
ws://{containerName}:7681/ws
Security Considerations
- Session tokens are httpOnly cookies (not accessible to JavaScript)
- Each workspace has a unique ID (UUID)
- Ownership verified on every connection
- WebSocket upgrade is atomic — no race conditions
Server Actions
All workspace operations userequireAuth() with ownership checks:
Available Actions
Action Details
getCodeWorkspaces()
getCodeWorkspaces()
Purpose: Fetch all workspaces owned by the current userReturns: Array of workspace objects
createCodeWorkspace(name)
createCodeWorkspace(name)
Purpose: Create a new code workspace and Docker containerParameters:
name(string) — Workspace display name
renameCodeWorkspace(id, name)
renameCodeWorkspace(id, name)
Purpose: Rename an existing workspaceParameters:
id(string) — Workspace UUIDname(string) — New name
starCodeWorkspace(id, starred)
starCodeWorkspace(id, starred)
Purpose: Toggle workspace starred statusParameters:
id(string) — Workspace UUIDstarred(boolean) — Star or unstar
deleteCodeWorkspace(id)
deleteCodeWorkspace(id)
Purpose: Delete workspace and its Docker containerParameters:
id(string) — Workspace UUID
- Removes database record
- Stops and removes Docker container
- Deletes all container data
ensureCodeWorkspaceContainer(id)
ensureCodeWorkspaceContainer(id)
Purpose: Ensure container is running, restart or recreate if neededParameters:
id(string) — Workspace UUID
Container Lifecycle
Creation
States
| State | Description | Action |
|---|---|---|
| running | Container is active | None — return success |
| stopped | Container stopped gracefully | Restart container |
| exited | Container exited (error or complete) | Restart container |
| paused | Container paused | Unpause and restart |
| dead | Container is dead (cannot be restarted) | Recreate container |
| missing | Container doesn’t exist | Recreate container |
Recovery
When a user navigates to/code/{id}, the page calls ensureCodeWorkspaceContainer(id) to guarantee the container is running:
Cleanup
Containers are cleaned up when:- User deletes the workspace (immediate)
- Container crashes and is recreated
- Docker daemon restarts (containers are not set to auto-restart)
Use Cases
Interactive Development
Scenario: User wants to develop a feature with agent assistance- User: “Start a coding workspace for the new API endpoint”
- Agent calls
start_codingtool - Workspace created with full development environment
- Agent can run commands, edit files, test code
- User can type commands in the terminal
- Changes saved to container filesystem
Debugging Sessions
Scenario: User needs help debugging a failing test- User shares error message with agent
- Agent creates workspace and reproduces the error
- Agent runs debugger, inspects variables
- Agent identifies root cause
- Agent proposes fix and tests it in the workspace
- User reviews and approves
Learning and Tutorials
Scenario: User wants to learn a new framework- User: “Teach me React hooks with live examples”
- Agent creates workspace with React environment
- Agent writes example code and runs it
- User modifies examples in the terminal
- Agent explains behavior and suggests improvements
- User experiments with variations
Technical Details
Docker Image
Theclaude-code-workspace image includes:
- Node.js runtime
- Common development tools (git, curl, vim)
- ttyd (terminal WebSocket server)
- Bash shell
ttyd Server
ttyd is a simple command-line tool that shares a terminal over WebSocket:- Listens on port 7681
- Exposes WebSocket at
/ws - Streams bash terminal I/O
xterm.js Integration
The browser terminal uses xterm.js:WebSocket Proxy
ws-proxy.js is a Next.js API route with WebSocket upgrade:
Troubleshooting
WebSocket Connection Failed
Symptoms: Terminal shows “Connecting…” indefinitely Causes:- Container not running
- Session expired
- Network connectivity issues
Container Not Starting
Symptoms:ensureCodeWorkspaceContainer returns 'error'
Causes:
- Docker daemon not running
- Image not pulled
- Resource constraints
Terminal Freezes
Symptoms: Terminal stops responding to input Causes:- Container process crashed
- WebSocket connection dropped
- Browser tab backgrounded (throttled)
- Refresh the page
- Check container logs
- Recreate the workspace
Best Practices
Name Workspaces Clearly
Use descriptive names like “API Debugging” or “React Tutorial” to easily identify workspaces.
Clean Up Unused Workspaces
Delete workspaces when done to free up Docker resources. Each container consumes memory and disk space.
Star Important Workspaces
Star workspaces you want to keep long-term. Unstarred workspaces can be bulk-deleted.
Commit Changes to Git
Code in workspaces is ephemeral. Commit changes to Git or copy files out before deleting.
Limitations
- No persistence — Container filesystem is ephemeral. Use Git or volume mounts for persistence.
- No multi-user — One workspace per user session. Can’t share terminals between users.
- No clipboard integration — Copy/paste requires browser permissions and manual selection.
- No file upload — Use
curlorgit cloneto get files into the container. - Resource limits — Containers share host resources. Too many workspaces can exhaust memory.
Related Features
- Web Interface — Start coding workspaces from chat
- Docker Agent — Agent jobs can reference workspace code
- Skills — Skills can use code workspaces for testing