by dzhng
Run Claude Agent (Claude Code) in a sandbox, control it via websocket
# Add to your Claude Code skills
git clone https://github.com/dzhng/claude-agent-serverA WebSocket server that wraps the Claude Agent SDK, allowing real-time bidirectional communication with Claude through WebSockets. Deploy it as an E2B sandbox and connect via the TypeScript client library.
Typical Workflow:
bun run build:e2b@dzhng/claude-agent in your project and connect to your E2B sandboxpackages/server/bun run start:server and bun run test:local to test your changes before rebuildingCreate a .env file in the root directory:
cp .env.example .env
Add your API keys:
ANTHROPIC_API_KEY=sk-ant-your-api-key-here
E2B_API_KEY=e2b_your-api-key-here
Install dependencies:
bun install
Build and deploy the server as an E2B template:
bun run build:e2b
This creates a sandbox template named on E2B. The build process:
claude-agent-serverThe build may take a few minutes. Once complete, your template is ready to use.
Install the client library in your project:
npm install @dzhng/claude-agent
# or
bun add @dzhng/claude-agent
Connect to your E2B sandbox:
import { ClaudeAgentClient } from '@dzhng/claude-agent'
const client = new ClaudeAgentClient({
e2bApiKey: process.env.E2B_API_KEY,
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
template: 'claude-agent-server', // Your E2B template name
debug: true,
})
// Start the client (creates E2B sandbox and connects)
await client.start()
// Listen for messages from Claude
client.onMessage(message => {
if (message.type === 'sdk_message') {
console.log('Claude:', message.data)
}
})
// Send a message to Claude
client.send({
type: 'user_message',
data: {
type: 'user',
session_id: 'my-session',
message: {
role: 'user',
content: 'Hello, Claude!',
},
},
})
// Clean up when done
await client.stop()
That's it! The client library handles:
If you want to customize the server behavior:
The server code is in packages/server/:
index.ts - Main server and WebSocket handlingmessage-handler.ts - Message processing logic