> ## 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

# Codex (/docs/agents/codex)

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

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

[Codex](https://github.com/openai/codex) is OpenAI's open-source coding agent. E2B provides a pre-built `codex` template with Codex already installed.

## CLI

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

```bash
e2b sbx create codex
```

Once inside the sandbox, start Codex.

```bash
codex
```

## Run headless

Use `codex exec` for non-interactive mode and `--full-auto` to auto-approve 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). Pass `--skip-git-repo-check` to bypass git directory ownership checks inside the sandbox. Pass `CODEX_API_KEY` as an environment variable.

<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('codex', {
  envs: { CODEX_API_KEY: process.env.CODEX_API_KEY },
})

const result = await sandbox.commands.run(
  `codex exec --full-auto --skip-git-repo-check "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("codex", envs={
    "CODEX_API_KEY": os.environ["CODEX_API_KEY"],
})

result = sandbox.commands.run(
    'codex exec --full-auto --skip-git-repo-check "Create a hello world HTTP server in Go"',
)

print(result.stdout)
sandbox.kill()
```
</CodeGroup>

### Example: work on a cloned repository

Use `-C` to set Codex's working directory to a cloned repo.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('codex', {
  envs: { CODEX_API_KEY: process.env.CODEX_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(
  `codex exec --full-auto --skip-git-repo-check -C /home/user/repo "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("codex", envs={
    "CODEX_API_KEY": os.environ["CODEX_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(
    'codex exec --full-auto --skip-git-repo-check -C /home/user/repo "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>

## Schema-validated output

Use `--output-schema` to constrain the agent's final response to a JSON Schema. This ensures the output conforms to a specific structure — useful for building reliable pipelines.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('codex', {
  envs: { CODEX_API_KEY: process.env.CODEX_API_KEY },
})

await sandbox.files.write('/home/user/schema.json', JSON.stringify({
  type: 'object',
  properties: {
    issues: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          file: { type: 'string' },
          line: { type: 'number' },
          severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
          description: { type: 'string' },
        },
        required: ['file', 'severity', 'description'],
      },
    },
  },
  required: ['issues'],
}))

const result = await sandbox.commands.run(
  `codex exec --full-auto --skip-git-repo-check --output-schema /home/user/schema.json -C /home/user/repo "Review this codebase for security issues"`
)

const response = JSON.parse(result.stdout)
console.log(response.issues)

await sandbox.kill()
```

```python title="Python"
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("codex", envs={
    "CODEX_API_KEY": os.environ["CODEX_API_KEY"],
})

sandbox.files.write("/home/user/schema.json", json.dumps({
    "type": "object",
    "properties": {
        "issues": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "file": {"type": "string"},
                    "line": {"type": "number"},
                    "severity": {"type": "string", "enum": ["low", "medium", "high", "critical"]},
                    "description": {"type": "string"},
                },
                "required": ["file", "severity", "description"],
            },
        },
    },
    "required": ["issues"],
}))

result = sandbox.commands.run(
    'codex exec --full-auto --skip-git-repo-check --output-schema /home/user/schema.json -C /home/user/repo "Review this codebase for security issues"',
)

response = json.loads(result.stdout)
print(response["issues"])

sandbox.kill()
```
</CodeGroup>

## Streaming events

Use `--json` to get a JSONL event stream. Each line is a JSON object representing an agent event (tool calls, file changes, messages). Progress goes to stderr; events go to stdout.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('codex', {
  envs: { CODEX_API_KEY: process.env.CODEX_API_KEY },
})

const result = await sandbox.commands.run(
  `codex exec --full-auto --skip-git-repo-check --json -C /home/user/repo "Refactor the utils module into separate files"`,
  {
    onStdout: (data) => {
      for (const line of data.split('\n').filter(Boolean)) {
        const event = JSON.parse(line)
        console.log(`[${event.type}]`, event)
      }
    },
  }
)

await sandbox.kill()
```

```python title="Python"
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("codex", envs={
    "CODEX_API_KEY": os.environ["CODEX_API_KEY"],
})

def handle_event(data):
    for line in data.strip().split("\n"):
        if line:
            event = json.loads(line)
            print(f"[{event['type']}]", event)

result = sandbox.commands.run(
    'codex exec --full-auto --skip-git-repo-check --json -C /home/user/repo "Refactor the utils module into separate files"',
    on_stdout=handle_event,
)

sandbox.kill()
```
</CodeGroup>

## Resume a session

Codex persists sessions (rollout files under `~/.codex/sessions` in the sandbox) that can be resumed with follow-up tasks using `codex exec resume`. Run the first task with `--json` and capture the `thread_id` from the `thread.started` event.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('codex', {
  envs: { CODEX_API_KEY: process.env.CODEX_API_KEY },
  timeoutMs: 600_000,
})

// Start a new session
const initial = await sandbox.commands.run(
  `codex exec --full-auto --skip-git-repo-check --json "Create plan.md with a 3-step plan for a TODO CLI app"`
)

// The first --json event is thread.started
const threadId = JSON.parse(initial.stdout.trim().split('\n')[0]).thread_id

// Continue in the same session
await sandbox.commands.run(
  `codex exec resume ${threadId} --full-auto --skip-git-repo-check "Now implement step 1 of the plan"`,
  { onStdout: (data) => process.stdout.write(data) }
)

const plan = await sandbox.commands.run('cat /home/user/plan.md')
console.log(plan.stdout)

await sandbox.kill()
```

```python title="Python"
import os
import json
from e2b import Sandbox

sandbox = Sandbox.create("codex", envs={
    "CODEX_API_KEY": os.environ["CODEX_API_KEY"],
}, timeout=600)

# Start a new session
initial = sandbox.commands.run(
    'codex exec --full-auto --skip-git-repo-check --json "Create plan.md with a 3-step plan for a TODO CLI app"',
)

# The first --json event is thread.started
thread_id = json.loads(initial.stdout.strip().splitlines()[0])["thread_id"]

# Continue in the same session
sandbox.commands.run(
    f'codex exec resume {thread_id} --full-auto --skip-git-repo-check "Now implement step 1 of the plan"',
    on_stdout=lambda data: print(data, end=""),
)

plan = sandbox.commands.run("cat /home/user/plan.md")
print(plan.stdout)

sandbox.kill()
```
</CodeGroup>

To simply continue the most recent session in the working directory, use `codex exec resume --last "follow-up task"` — no thread ID needed. When working in a cloned repo, pass `-C` before the `resume` subcommand (`codex exec -C /home/user/repo resume <thread_id> "..."`); it is not accepted after it.

## Image input

Pass screenshots or design mockups with `--image` to give Codex visual context alongside the prompt.

<CodeGroup>
```typescript title="JavaScript & TypeScript"
import fs from 'fs'
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('codex', {
  envs: { CODEX_API_KEY: process.env.CODEX_API_KEY },
  timeoutMs: 600_000,
})

// Upload a design mockup to the sandbox
await sandbox.files.write(
  '/home/user/mockup.png',
  fs.readFileSync('./mockup.png')
)

const result = await sandbox.commands.run(
  `codex exec --full-auto --skip-git-repo-check --image /home/user/mockup.png -C /home/user/repo "Implement this UI design as a React component"`,
  { onStdout: (data) => process.stdout.write(data) }
)

await sandbox.kill()
```

```python title="Python"
import os
from e2b import Sandbox

sandbox = Sandbox.create("codex", envs={
    "CODEX_API_KEY": os.environ["CODEX_API_KEY"],
}, timeout=600)

# Upload a design mockup to the sandbox
with open("./mockup.png", "rb") as f:
    sandbox.files.write("/home/user/mockup.png", f)

result = sandbox.commands.run(
    'codex exec --full-auto --skip-git-repo-check --image /home/user/mockup.png -C /home/user/repo "Implement this UI design as a React component"',
    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 `codex` template.

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

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

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

```python title="Python"
# build.py
from e2b import Template, default_build_logger
from template import template as codex_template

Template.build(codex_template, "my-codex",
    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="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>

<Card title="SSH access" icon="terminal" href="/docs/sandbox/ssh-access">Connect to the sandbox via SSH for interactive sessions</Card>
</CardGroup>
