> ## Documentation Index
> Fetch the complete documentation index at: https://e2b.manicule.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For every page in one file, fetch https://e2b.manicule.dev/llms-full.txt (large).
> To search and read these docs as tools, connect the MCP server at https://e2b.manicule.dev/api/mcp.
> Every agent surface: https://e2b.manicule.dev/.well-known/llms-manifest.json

# Claude Code (/docs/agents/claude-code)

<!-- agent-signals: reading_time_min: 7 · est_tokens: 3339 · updated: 2026-07-30 -->
Related: [Amp](/docs/agents/amp.md), [Claude Managed Agents](/docs/agents/claude-managed-agents.md), [Codex](/docs/agents/codex.md), [Crabbox with E2B](/docs/agents/crabbox.md), [Devin](/docs/agents/devin.md), [Devin Outposts](/docs/agents/devin-outposts.md)

> Run Claude Code in a secure E2B sandbox with full filesystem, terminal, and git access.

[Claude Code](https://docs.anthropic.com/en/docs/claude-code) is Anthropic's agentic coding tool. E2B provides a pre-built `claude` template with Claude Code already installed.

## CLI

Create a sandbox with the [E2B CLI](/docs/cli).

```bash
e2b sbx create claude
```

Once inside the sandbox, start Claude Code.

```bash
claude
```

## Run headless

Use `-p` for non-interactive mode and `--dangerously-skip-permissions` to auto-approve all tool calls. The sandbox isolates the agent from your host machine, but sandboxes can reach the open internet by default — restrict outbound traffic with [network rules](/docs/network/internet-access) if the agent processes untrusted input or handles secrets.

<Note>Auto-approving tool calls is contained by the sandbox: the agent cannot touch your host machine, local files, or credentials. It can still make outbound network requests — internet access is enabled by default. To limit where an auto-approved agent can connect, configure [outbound network rules](/docs/network/internet-access) (`allowInternetAccess`, plus allow/deny lists by CIDR or hostname). Hostname rules apply to HTTP(S) traffic only; use CIDR rules for other protocols.</Note>

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
})

const result = await sandbox.commands.run(
  `claude --dangerously-skip-permissions -p "Create a hello world HTTP server in Go"`
)

console.log(result.stdout)
await sandbox.kill()
```

```python title="Python"
import os
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
})

result = sandbox.commands.run(
    'claude --dangerously-skip-permissions -p "Create a hello world HTTP server in Go"',
)

print(result.stdout)
sandbox.kill()
```
</CodeGroup>

### Example: work on a cloned repository

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
  timeoutMs: 600_000,
})

await sandbox.git.clone('https://github.com/your-org/your-repo.git', {
  path: '/home/user/repo',
  username: 'x-access-token',
  password: process.env.GITHUB_TOKEN,
  depth: 1,
})

const result = await sandbox.commands.run(
  `cd /home/user/repo && claude --dangerously-skip-permissions -p "Add error handling to all API endpoints"`,
  { onStdout: (data) => process.stdout.write(data) }
)

const diff = await sandbox.commands.run('cd /home/user/repo && git diff')
console.log(diff.stdout)

await sandbox.kill()
```

```python title="Python"
import os
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
}, timeout=600)

sandbox.git.clone("https://github.com/your-org/your-repo.git",
    path="/home/user/repo",
    username="x-access-token",
    password=os.environ["GITHUB_TOKEN"],
    depth=1,
)

result = sandbox.commands.run(
    'cd /home/user/repo && claude --dangerously-skip-permissions -p "Add error handling to all API endpoints"',
    on_stdout=lambda data: print(data, end=""),
)

diff = sandbox.commands.run("cd /home/user/repo && git diff")
print(diff.stdout)

sandbox.kill()
```
</CodeGroup>

## Structured output

Use `--output-format json` to get machine-readable responses — useful for building pipelines or extracting specific results.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
})

const result = await sandbox.commands.run(
  `claude --dangerously-skip-permissions --output-format json -p "Review this codebase and list all security issues as JSON"`
)

const response = JSON.parse(result.stdout)
console.log(response)

await sandbox.kill()
```

```python title="Python"
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
})

result = sandbox.commands.run(
    'claude --dangerously-skip-permissions --output-format json -p "Review this codebase and list all security issues as JSON"',
)

response = json.loads(result.stdout)
print(response)

sandbox.kill()
```
</CodeGroup>

## Streaming output

Use `--output-format stream-json` to get a real-time JSONL event stream — including tool calls, token usage, and result metadata.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
})

const result = await sandbox.commands.run(
  `cd /home/user/repo && claude --dangerously-skip-permissions --output-format stream-json -p "Find and fix all TODO comments"`,
  {
    onStdout: (data) => {
      for (const line of data.split('\n').filter(Boolean)) {
        const event = JSON.parse(line)
        if (event.type === 'assistant') {
          console.log(`[assistant] tokens: ${event.message.usage?.output_tokens}`)
        } else if (event.type === 'result') {
          console.log(`[done] ${event.subtype} in ${event.duration_ms}ms`)
        }
      }
    },
  }
)

await sandbox.kill()
```

```python title="Python"
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
})

def handle_event(data):
    for line in data.strip().split("\n"):
        if line:
            event = json.loads(line)
            if event["type"] == "assistant":
                usage = event.get("message", {}).get("usage", {})
                print(f"[assistant] tokens: {usage.get('output_tokens')}")
            elif event["type"] == "result":
                print(f"[done] {event['subtype']} in {event['duration_ms']}ms")

result = sandbox.commands.run(
    'cd /home/user/repo && claude --dangerously-skip-permissions --output-format stream-json -p "Find and fix all TODO comments"',
    on_stdout=handle_event,
)

sandbox.kill()
```
</CodeGroup>

## Resume a session

Claude Code persists conversations that can be resumed with follow-up tasks using `--resume`.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
  timeoutMs: 600_000,
})

// Start a new session
const initial = await sandbox.commands.run(
  `cd /home/user/repo && claude --dangerously-skip-permissions --output-format json -p "Analyze the codebase and create a refactoring plan"`
)

// Extract session ID from the JSON response
const response = JSON.parse(initial.stdout)
const sessionId = response.session_id

// Continue with a follow-up task
const followUp = await sandbox.commands.run(
  `cd /home/user/repo && claude --dangerously-skip-permissions --resume ${sessionId} -p "Now implement step 1 of the plan"`,
  { onStdout: (data) => process.stdout.write(data) }
)

const diff = await sandbox.commands.run('cd /home/user/repo && git diff')
console.log(diff.stdout)

await sandbox.kill()
```

```python title="Python"
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
}, timeout=600)

# Start a new session
initial = sandbox.commands.run(
    'cd /home/user/repo && claude --dangerously-skip-permissions --output-format json -p "Analyze the codebase and create a refactoring plan"',
)

# Extract session ID from the JSON response
response = json.loads(initial.stdout)
session_id = response["session_id"]

# Continue with a follow-up task
follow_up = sandbox.commands.run(
    f'cd /home/user/repo && claude --dangerously-skip-permissions --resume {session_id} -p "Now implement step 1 of the plan"',
    on_stdout=lambda data: print(data, end=""),
)

diff = sandbox.commands.run("cd /home/user/repo && git diff")
print(diff.stdout)

sandbox.kill()
```
</CodeGroup>

## Custom system prompt

Write a `CLAUDE.md` file into the sandbox for project context or use `--system-prompt` to provide task-specific instructions.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
})

// Write project context
await sandbox.files.write('/home/user/repo/CLAUDE.md', `
You are working on a Go microservice.
Always use structured logging with slog.
Follow the project's error handling conventions in pkg/errors.
`)

const result = await sandbox.commands.run(
  `cd /home/user/repo && claude --dangerously-skip-permissions -p "Add a /healthz endpoint"`
)

console.log(result.stdout)
await sandbox.kill()
```

```python title="Python"
import os
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
})

# Write project context
sandbox.files.write("/home/user/repo/CLAUDE.md", """
You are working on a Go microservice.
Always use structured logging with slog.
Follow the project's error handling conventions in pkg/errors.
""")

result = sandbox.commands.run(
    'cd /home/user/repo && claude --dangerously-skip-permissions -p "Add a /healthz endpoint"',
)

print(result.stdout)
sandbox.kill()
```
</CodeGroup>

## Connect MCP tools

Claude Code has built-in support for [MCP](https://modelcontextprotocol.io/). E2B provides an [MCP gateway](/docs/mcp) that gives Claude access to 200+ tools from the [Docker MCP Catalog](https://hub.docker.com/mcp).

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('claude', {
  envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
  mcp: {
    browserbase: {
      apiKey: process.env.BROWSERBASE_API_KEY,
      projectId: process.env.BROWSERBASE_PROJECT_ID,
    },
  },
})

const mcpUrl = sandbox.getMcpUrl()
const mcpToken = await sandbox.getMcpToken()

await sandbox.commands.run(
  `claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`
)

const result = await sandbox.commands.run(
  `claude --dangerously-skip-permissions -p "Use browserbase to research E2B and summarize your findings"`,
  { onStdout: console.log }
)

await sandbox.kill()
```

```python title="Python"
import os
from e2b import Sandbox

sandbox = Sandbox.create("claude", envs={
    "ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"],
}, mcp={
    "browserbase": {
        "apiKey": os.environ["BROWSERBASE_API_KEY"],
        "projectId": os.environ["BROWSERBASE_PROJECT_ID"],
    },
})

mcp_url = sandbox.get_mcp_url()
mcp_token = sandbox.get_mcp_token()

sandbox.commands.run(
    f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
)

result = sandbox.commands.run(
    'claude --dangerously-skip-permissions -p "Use browserbase to research E2B and summarize your findings"',
    on_stdout=lambda data: print(data, end=""),
)

sandbox.kill()
```
</CodeGroup>

## Build a custom template

If you need to customize the environment (e.g. pre-install dependencies, add config files), build your own template on top of the pre-built `claude` template.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
// template.ts
import { Template } from 'e2b'

export const template = Template()
  .fromTemplate('claude')
```

```python title="Python"
# template.py
from e2b import Template

template = (
    Template()
    .from_template("claude")
)
```
</CodeGroup>

<CodeGroup>
```typescript title="JavaScript & TypeScript"
// build.ts
import { Template, defaultBuildLogger } from 'e2b'
import { template as claudeCodeTemplate } from './template'

await Template.build(claudeCodeTemplate, 'my-claude', {
  cpuCount: 2,
  memoryMB: 2048,
  onBuildLogs: defaultBuildLogger(),
})
```

```python title="Python"
# build.py
from e2b import Template, default_build_logger
from template import template as claude_code_template

Template.build(claude_code_template, "my-claude",
    cpu_count=2,
    memory_mb=2048,
    on_build_logs=default_build_logger(),
)
```
</CodeGroup>

Run the build script to create the template.

<CodeGroup>
```bash title="JavaScript & TypeScript"
npx tsx build.ts
```

```bash title="Python"
python build.py
```
</CodeGroup>

## Related guides

<CardGroup cols="3">
<Card title="MCP tools" icon="plug" href="/docs/mcp">Connect Claude Code to 200+ MCP tools</Card>

<Card title="Sandbox persistence" icon="clock" href="/docs/sandbox/persistence">Auto-pause, resume, and manage sandbox lifecycle</Card>

<Card title="Git integration" icon="code-branch" href="/docs/sandbox/git-integration">Clone repos, manage branches, and push changes</Card>
</CardGroup>
