> ## Documentation Index
> Fetch the complete documentation index at: https://docs.archil.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI Codex

> Run the OpenAI Codex CLI headlessly in an Archil sandbox, with its workspace and session history on an Archil disk.

[Codex](https://github.com/openai/codex) is OpenAI's coding agent CLI. In an Archil [sandbox](/compute/sandboxes/introduction) the whole Linux VM is the sandbox, so you can turn off Codex's own sandbox and approval prompts and let it work. Its workspace and session history live on an Archil disk, so the work outlives the sandbox, and a new sandbox can resume the same session.

## Prerequisites

Export your Archil API key, a region where sandboxes are available (`aws-us-east-1`, `aws-us-west-2`, or `aws-eu-west-1`), and an [OpenAI API key](https://platform.openai.com/api-keys), then install the SDK:

```bash theme={null}
export ARCHIL_API_KEY=key-...
export ARCHIL_REGION=aws-us-east-1
export OPENAI_API_KEY=sk-...
```

<CodeGroup>
  ```bash TypeScript theme={null}
  npm init -y && npm pkg set type=module
  npm install disk tsx
  ```

  ```bash Python theme={null}
  pip install archil
  ```
</CodeGroup>

## Run Codex in a sandbox

This script creates a disk, starts a sandbox with the disk mounted at `/workspace`, installs Codex, and gives it a task with `codex exec`, which works until the task is done, prints the final answer, and exits. Then it deletes the sandbox; everything the agent made is on the disk.

<CodeGroup>
  ```typescript start.ts theme={null}
  import * as archil from "disk";

  const env = {
    CODEX_API_KEY: process.env.OPENAI_API_KEY!, // codex exec reads its key from CODEX_API_KEY
    CODEX_HOME: "/workspace/.codex", // keep sessions on the disk
  };

  const { disk } = await archil.createDisk({ name: "codex-workspace" });
  const sandbox = await archil.createSandbox({ name: "codex", mounts: [{ disk, path: "/workspace" }] });
  await sandbox.exec("npm install -g @openai/codex && mkdir -p /workspace/.codex");

  // < /dev/null: no more prompt text is coming on stdin.
  const result = await sandbox.exec(
    "codex exec --dangerously-bypass-approvals-and-sandbox " +
      '"Create a hello-world Express app with a test, and run the test. Reply in two sentences." < /dev/null',
    { cwd: "/workspace", env },
  );
  console.log(result.stdout);

  await sandbox.stop();
  await sandbox.delete();
  ```

  ```python start.py theme={null}
  import os

  import archil

  env = {
      "CODEX_API_KEY": os.environ["OPENAI_API_KEY"],  # codex exec reads its key from CODEX_API_KEY
      "CODEX_HOME": "/workspace/.codex",  # keep sessions on the disk
  }

  disk = archil.create_disk(name="codex-workspace").disk
  sandbox = archil.create_sandbox(
      name="codex", mounts=[archil.SandboxMountSpec(disk=disk, path="/workspace")]
  )
  sandbox.exec("npm install -g @openai/codex && mkdir -p /workspace/.codex")

  # < /dev/null: no more prompt text is coming on stdin.
  result = sandbox.exec(
      "codex exec --dangerously-bypass-approvals-and-sandbox "
      '"Create a hello-world Express app with a test, and run the test. Reply in two sentences." < /dev/null',
      cwd="/workspace",
      env=env,
  )
  print(result.stdout)

  sandbox.stop()
  sandbox.delete()
  ```
</CodeGroup>

Run it with `npx tsx start.ts` or `python start.py`. Codex prints its progress to standard error and only the final answer to standard output. The wording varies from run to run. One run printed:

```text theme={null}
Created an Express app that returns “Hello, world!” at `/`; start it with `npm start`.
Ran `npm test`: 1 test passed, 0 failed.
```

## Pick up where you left off

Codex's project and session history are on the disk, so any sandbox that mounts it can resume the session. This script starts a new sandbox on the same disk and runs `codex exec resume --last`, which resumes the most recent session in `/workspace`.

<CodeGroup>
  ```typescript continue.ts theme={null}
  import * as archil from "disk";

  const env = {
    CODEX_API_KEY: process.env.OPENAI_API_KEY!,
    CODEX_HOME: "/workspace/.codex",
  };

  const [disk] = await archil.listDisks({ name: "codex-workspace" });
  const sandbox = await archil.createSandbox({ name: "codex", mounts: [{ disk, path: "/workspace" }] });
  await sandbox.exec("npm install -g @openai/codex");

  const result = await sandbox.exec(
    "codex exec resume --last --dangerously-bypass-approvals-and-sandbox " +
      '"Add a /health route with a test and run all the tests. Reply in two sentences." < /dev/null',
    { cwd: "/workspace", env },
  );
  console.log(result.stdout);

  await sandbox.stop();
  await sandbox.delete();
  ```

  ```python continue.py theme={null}
  import os

  import archil

  env = {
      "CODEX_API_KEY": os.environ["OPENAI_API_KEY"],
      "CODEX_HOME": "/workspace/.codex",
  }

  [disk] = archil.list_disks(name="codex-workspace")
  sandbox = archil.create_sandbox(
      name="codex", mounts=[archil.SandboxMountSpec(disk=disk, path="/workspace")]
  )
  sandbox.exec("npm install -g @openai/codex")

  result = sandbox.exec(
      "codex exec resume --last --dangerously-bypass-approvals-and-sandbox "
      '"Add a /health route with a test and run all the tests. Reply in two sentences." < /dev/null',
      cwd="/workspace",
      env=env,
  )
  print(result.stdout)

  sandbox.stop()
  sandbox.delete()
  ```
</CodeGroup>

```text theme={null}
Added `/health`, returning HTTP 200 with `{"status":"ok"}`, and a test covering its response.
Ran `npm test`: all 2 tests passed.
```

## Going further

* **Stream output.** Pass `onOutput: ({ data }) => process.stdout.write(data)` to `exec` (in Python, `on_output=lambda out: sys.stdout.buffer.write(out.data)`) to watch the agent as it works. Add `--json` to `codex exec` to get one JSON event per line.
* **Work interactively.** Start `codex` in a pseudo-terminal with `sandbox.run` and sign in when it asks; see [Opening interactive shells](/compute/sandboxes/introduction#opening-interactive-shells).

<Accordion title="Use Vercel AI Gateway instead of an OpenAI key">
  Codex can send its requests through [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/coding-agents/openai-codex). Export `AI_GATEWAY_API_KEY` instead of `OPENAI_API_KEY`, replace the `CODEX_API_KEY` line in `env` with this one, and change `codex exec` to `codex exec -c openai_base_url=https://ai-gateway.vercel.sh/codex/v1` in both scripts. On the Developer plan, sandboxes can't reach the gateway, because it isn't on the [managed allowlist](/compute/sandboxes/firewall#developer-plan-allowlist); use your provider key instead.

  <CodeGroup>
    ```typescript TypeScript theme={null}
    CODEX_API_KEY: process.env.AI_GATEWAY_API_KEY!,
    ```

    ```python Python theme={null}
    "CODEX_API_KEY": os.environ["AI_GATEWAY_API_KEY"],
    ```
  </CodeGroup>
</Accordion>

## Clean up

Each script deletes its sandbox when it finishes, so only the disk is left. Delete it:

<CodeGroup>
  ```typescript cleanup.ts theme={null}
  import * as archil from "disk";

  const [disk] = await archil.listDisks({ name: "codex-workspace" });
  await disk.delete();
  ```

  ```python cleanup.py theme={null}
  import archil

  [disk] = archil.list_disks(name="codex-workspace")
  disk.delete()
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Claude Code" icon="terminal" href="/guides/agents/claude-code">
    Run Claude Code headlessly in a sandbox.
  </Card>

  <Card title="OpenCode" icon="terminal" href="/guides/agents/opencode">
    Run OpenCode headlessly in a sandbox.
  </Card>

  <Card title="Coding agent in a sandbox" icon="code" href="/guides/agents/coding-agent">
    Build your own coding agent with the AI SDK instead.
  </Card>

  <Card title="Persistent sandboxes" icon="box" href="/compute/sandboxes/introduction">
    Lifecycle, services, network access, and forking in detail.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.