Codex
Run OpenAI Codex in a secure E2B sandbox with full filesystem, terminal, and git access.
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.
e2b sbx create codexOnce inside the sandbox, start Codex.
codexRun 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. Pass --skip-git-repo-check to bypass git directory ownership checks inside the sandbox. Pass CODEX_API_KEY as an environment variable.
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 (allowInternetAccess, plus allow/deny lists by CIDR or hostname). Hostname rules apply to HTTP(S) traffic only; use CIDR rules for other protocols.
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()Example: work on a cloned repository
Use -C to set Codex’s working directory to a cloned repo.
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()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.
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()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.
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()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.
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()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.
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()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.
// template.ts
import { Template } from 'e2b'
export const template = Template()
.fromTemplate('codex')// 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(),
})Run the build script to create the template.
npx tsx build.ts