# Codex (/docs/agents/codex)

<!-- agent-signals: reading_time_min: 8 · est_tokens: 5034 · 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)

[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 [#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 [#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>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

### Example: work on a cloned repository [#example-work-on-a-cloned-repository]

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

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Schema-validated output [#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>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Streaming events [#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>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Resume a session [#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>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</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 [#image-input]

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

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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()
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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()
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Build a custom template [#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>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

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

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

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```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(),
      })
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```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(),
      )
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

Run the build script to create the template.

<CodeGroup>
  <CodeBlockTabs defaultValue="JavaScript & TypeScript" groupId="javascript-typescript+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="JavaScript & TypeScript">
        JavaScript & TypeScript
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="JavaScript & TypeScript">
      ```bash  
      npx tsx build.ts
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Python">
      ```bash  
      python build.py
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Related guides [#related-guides]

<CardGroup cols="3">
  <Card title="Sandbox persistence" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><circle cx=&#x22;12&#x22; cy=&#x22;12&#x22; r=&#x22;10&#x22; stroke=&#x22;currentColor&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M12 8V12L14 14&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/docs/sandbox/persistence">
    Auto-pause, resume, and manage sandbox lifecycle
  </Card>

  <Card title="Git integration" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M16 6.99998L19.0664 9.64296C20.3554 10.7541 21 11.3096 21 12C21 12.6903 20.3555 13.2459 19.0664 14.357L16 17&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M8 6.99998L4.93365 9.64296C3.64455 10.7541 3 11.3096 3 12C3 12.6903 3.64455 13.2459 4.93365 14.357L8 17&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/docs/sandbox/git-integration">
    Clone repos, manage branches, and push changes
  </Card>

  <Card title="SSH access" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M4.00004 17C4.00004 17 9.99999 12.5811 10 11C10 9.41884 4 5 4 5&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M12 19H20&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/docs/sandbox/ssh-access">
    Connect to the sandbox via SSH for interactive sessions
  </Card>
</CardGroup>
