# Codex

> Cordium documentation. Canonical page: <https://octelium.com/docs/cordium/latest/examples/ai/codex>.

This example drives [OpenAI Codex](https://developers.openai.com/codex) from your own program via the Cordium SDKs to implement features in a TypeScript web application. For each task, the program starts an ephemeral *Workspace* from a pre-built *Template* in which the repository is already cloned and its dependencies are already installed, runs `codex exec` inside it, runs the test suite, collects the resulting diff and Codex's summary, and deletes the *Workspace*. This orchestration pattern is the building block of internal coding-agent platforms, evaluation harnesses and "best-of-N" setups (read a parallel version [here](https://octelium.com/docs/cordium/latest/examples/ai/parallel-agents.md)).

As in all the AI examples, the OpenAI API key never enters the *Workspace*. Codex is configured with a custom model provider that points to an Octelium `LLM` *Service*, which injects the key on a per-request basis (read more [here](https://octelium.com/docs/cordium/latest/examples/ai/secretless-llm.md)).

## The Octelium Service

A *Cluster* administrator stores the OpenAI API key as an Octelium *Secret* and exposes the OpenAI API as an `LLM` *Service*:

```bash
octeliumctl create secret openai-api-key
```

```yaml
kind: Service
metadata:
  name: openai
spec:
  mode: LLM
  config:
    upstream:
      url: https://api.openai.com
    llm:
      protocol: OPENAI
      auth:
        bearer:
          fromSecret: openai-api-key
```

The *Users* who run the program must be allowed to access the `openai` *Service* by a *Policy*.

## The Template

The `codex` *Template* of the `storefront` *Space* clones the repository with a read-only token, installs Codex, configures its model provider and installs the npm dependencies. Since these are `ON_CREATE` tasks, they run once in the *Template*'s pre-build and every *Workspace* starts with everything ready:

```yaml
spec:
  image:
    registry:
      url: node:24-bookworm
  repository:
    url: https://github.com/acme-corp/storefront
    cloneOptions:
      branch: main
    authentication:
      http:
        username: x-access-token
        password:
          fromSecret: github-read-token.storefront.cordium
  runtime:
    envVars:
      # A placeholder. Octelium injects the real API key and never forwards this one.
      - key: OPENAI_API_KEY
        value: injected-by-octelium
      - key: CI
        value: "true"
    tasks:
      - name: install-codex
        type: ON_CREATE
        runAsRoot: true
        onFailure: ON_FAILURE_ABORT
        run: npm install -g @openai/codex
      - name: configure-codex
        type: ON_CREATE
        workingDir: /workspace
        onFailure: ON_FAILURE_ABORT
        run: |
          mkdir -p "$HOME/.codex"
          cat > "$HOME/.codex/config.toml" <<'EOF'
          model_provider = "octelium"

          [model_providers.octelium]
          name = "OpenAI via Octelium"
          base_url = "http://openai/v1"
          env_key = "OPENAI_API_KEY"
          wire_api = "responses"
          EOF
      - name: install-dependencies
        type: ON_CREATE
        workingDir: /workspace/repo
        onFailure: ON_FAILURE_ABORT
        run: npm ci
  limit:
    cpu:
      millicores: 4000
    memory:
      megabytes: 8192
    storage:
      megabytes: 20000
```

Create and pre-build the *Template*:

```bash
cordium create secret github-read-token.storefront.cordium --from-env GITHUB_READ_TOKEN
cordium create template codex.storefront.cordium --file codex.yaml
cordium build codex.storefront.cordium
```

> **Note:**
>
> The read-only token is used by the *Workspace*'s git credential helper, which means that it is readable inside the *Workspace*. Use a fine-grained token restricted to the **Contents: read** permission of the repository. To keep even that token out of the *Workspace*, clone the repository through an Octelium `HTTP` *Service* in a `POST_START` task instead, as shown in the [Claude Code](https://octelium.com/docs/cordium/latest/examples/ai/claude-code.md) example.

## The Orchestrator

The following Python program uses the Cordium SDK to run one Codex task and return its result. It runs with your own identity, or with a `WORKLOAD` *User*'s identity in automation (read more about authenticating the SDKs [here](https://octelium.com/docs/cordium/latest/use/api.md)):

```python
import sys
from dataclasses import dataclass

from cordium import Cordium, shell_quote


@dataclass
class Result:
    workspace: str
    codex_exit_code: int
    tests_passed: bool
    summary: str
    diff: str


def run_task(client: Cordium, task: str) -> Result:
    workspace = client.workspaces.run(
        template="codex.storefront.cordium",
        ephemeral=True,
        display_name=f"Codex: {task[:40]}",
        timeout=600,
    )
    try:
        codex = workspace.exec(
            "codex exec --sandbox danger-full-access "
            f"--output-last-message /tmp/summary.md {shell_quote(task)} < /dev/null",
            cwd="/workspace/repo",
            timeout=3600,
        )
        tests = workspace.exec("npm test", cwd="/workspace/repo", timeout=1200)
        diff = workspace.exec("git add -A && git diff --cached", cwd="/workspace/repo", check=True)
        summary = workspace.files.read_text("/tmp/summary.md") if codex.exit_code == 0 else ""
        return Result(workspace.name, codex.exit_code, tests.exit_code == 0, summary, diff.stdout)
    finally:
        workspace.delete()


if __name__ == "__main__":
    with Cordium() as client:
        result = run_task(client, sys.argv[1])
    print(result.summary)
    print(f"Tests passed: {result.tests_passed}")
    with open("codex.patch", "w") as f:
        f.write(result.diff)
```

```bash
export OCTELIUM_DOMAIN=<DOMAIN>
python run_codex.py "Add a 'Sort by price' option to the product list page, with unit tests"
git apply codex.patch
```

Here are a few notes about this program:

- `workspaces.run()` creates and starts the *Workspace*, and waits until it is `RUNNING`. Since the *Template* is pre-built, this typically takes a few seconds.
- `codex exec` runs non-interactively, streams its progress to stderr and writes its final message to `/tmp/summary.md`. `--sandbox danger-full-access` disables Codex's own sandbox, which is meant for developer machines; the *Workspace* is the sandbox here. Its standard input is redirected from `/dev/null` since `exec` sessions do not signal the end of the standard input.
- `exec` returns the exit code instead of raising, unless `check=True` is passed. Every `exec` session counts as activity, so the *Workspace* is not stopped by the inactivity timeout while Codex is working.
- The *Workspace* is always deleted, even if any step fails. To debug a failed run, skip the deletion and open a terminal in it from the web portal.

The equivalent flow is also available via the CLI, for example from a shell script:

```bash
cordium create ws --template codex.storefront.cordium --ephemeral --start
cordium exec --no-stdin -w /workspace/repo <WORKSPACE> -- \
  sh -c 'codex exec --sandbox danger-full-access "Add a Sort by price option" < /dev/null'
cordium exec --no-stdin -w /workspace/repo <WORKSPACE> -- sh -c 'git add -A && git diff --cached' > codex.patch
cordium delete ws <WORKSPACE>
```
