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

# Codex Agent

Codex is OpenAI's coding agent. On Novita Sandbox, the `codex` template gives you a ready-to-use, isolated environment where Codex can read and edit code, run commands, and complete multi-step engineering tasks autonomously — without directly modifying files on your local machine.

Typical use cases:

* **Autonomous coding tasks** — hand Codex a prompt (e.g. "add error handling to all API endpoints") and let it implement changes end to end.
* **Working on real repositories** — clone a Git repo into the sandbox and have Codex refactor, fix bugs, or add features.
* **Safe, unattended automation** — run the agent fully automatically inside an isolated sandbox, so file and command actions never affect your own environment.
* **Multi-step workflows** — start a session to plan, then resume it to carry out each step.

The `codex` template comes with Codex pre-installed, so you can spin up a sandbox and drive Codex in just a few lines. The examples below use the SDK's unified `Novita` client, create a sandbox from the `codex` template, run the `codex` CLI through `commands.run`, stream its output, then kill the sandbox.

## Quick start

<Note>
  **`codex exec "<prompt>"`:** the `exec` subcommand runs Codex non-interactively — it processes the prompt, prints the result, and exits, instead of opening an interactive session. This is what makes it scriptable inside a sandbox.
</Note>

<Note>
  **`--full-auto`:** runs Codex fully autonomously, automatically approving the file and command actions it would otherwise prompt for. Convenient in an isolated sandbox, but use it only in trusted, sandboxed environments. **`--skip-git-repo-check`** lets Codex run outside a Git repository (by default it expects to run inside one).
</Note>

```python Python icon="python" theme={"system"}
import os

from novita_sandbox import Novita


def main() -> None:
    novita = Novita(api_key=os.environ["NOVITA_API_KEY"])

    sandbox = novita.sandbox.create(
        "codex",
        timeout=3600,
        envs={"CODEX_API_KEY": os.environ["CODEX_API_KEY"]},
    )
    print("Sandbox created:", sandbox.sandbox_id)

    try:
        execution = sandbox.commands.run(
            'codex exec --full-auto --skip-git-repo-check "Hello"',
            on_stdout=lambda data: print(data, end=""),
            on_stderr=lambda data: print(data, end=""),
            timeout=0,
        )
        print(execution)
    finally:
        sandbox.kill()
        print("Sandbox killed")


if __name__ == "__main__":
    main()
```

***

## Custom Codex configuration

To make Codex use a custom LLM (custom API token, base URL, or model), write the credentials to `~/.codex/auth.json` and the provider settings to `~/.codex/config.toml` after creating the sandbox and before running `codex`.

```python Python icon="python" theme={"system"}
import os

from novita_sandbox import Novita


def main() -> None:
    novita = Novita(api_key=os.environ["NOVITA_API_KEY"])
    sandbox = novita.sandbox.create("codex", timeout=3600)
    print("Sandbox created:", sandbox.sandbox_id)

    try:
        sandbox.files.write(
            "~/.codex/auth.json",
            """{
  "OPENAI_API_KEY": "<your custom llm api token>"
}""",
        )
        sandbox.files.write(
            "~/.codex/config.toml",
            """model_provider = "custom"
model = "<your custom model>"
model_reasoning_effort = "high"
disable_response_storage = true
[model_providers]
[model_providers.custom]
name = "custom"
wire_api = "responses"
requires_openai_auth = true
base_url = "<your custom llm api url>"
""",
        )

        execution = sandbox.commands.run(
            'codex exec --full-auto --skip-git-repo-check "Hello"',
            on_stdout=lambda data: print(data, end=""),
            on_stderr=lambda data: print(data, end=""),
            timeout=0,
        )
        print(execution)
    finally:
        sandbox.kill()
        print("Sandbox killed")


if __name__ == "__main__":
    main()
```

***

## Work on a cloned repository

A common workflow is to clone a Git repository into the sandbox and let Codex work on it. Use `sandbox.git.clone` to check out the repo (with credentials for private repos), then run `codex` from inside the cloned directory.

<CodeGroup>
  ```python Python icon="python" theme={"system"}
  import os

  from novita_sandbox import Novita


  novita = Novita(api_key=os.environ["NOVITA_API_KEY"])
  sandbox = novita.sandbox.create("codex", timeout=3600)

  try:
      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 "Add error handling to all API endpoints"',
          cwd="/home/user/repo",
          on_stdout=lambda data: print(data, end=""),
          timeout=0,
      )
      print(result)
  finally:
      sandbox.kill()
  ```

  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita({ apiKey: process.env.NOVITA_API_KEY })
  const sandbox = await novita.sandbox.create('codex', { timeoutMs: 3_600_000 })

  try {
    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 "Add error handling to all API endpoints"',
      {
        cwd: '/home/user/repo',
        onStdout: (data) => process.stdout.write(data),
        timeoutMs: 0,
      }
    )
    console.log(result)
  } finally {
    await sandbox.kill()
  }
  ```
</CodeGroup>

***

## Resume a session

Codex can continue a previous session, so you can run a multi-step workflow across several invocations. Start a session with `--json` to capture the `thread_id` from the first event (`thread.started`), then pass it to `codex exec resume <thread_id>` to continue where you left off.

<CodeGroup>
  ```python Python icon="python" theme={"system"}
  import json
  import os

  from novita_sandbox import Novita


  def main() -> None:
      novita = Novita(api_key=os.environ["NOVITA_API_KEY"])

      sandbox = novita.sandbox.create(
          "codex",
          timeout=3600,
          envs={"CODEX_API_KEY": os.environ["CODEX_API_KEY"]},
      )
      print("Sandbox created:", sandbox.sandbox_id)

      try:
          # Start a new session with JSON output to capture the thread ID.
          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"',
              timeout=0,
          )
          # The first --json event is thread.started.
          thread_id = json.loads(initial.stdout.strip().splitlines()[0])["thread_id"]
          print("Thread ID:", thread_id)

          # Resume the session with a follow-up task.
          follow_up = 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=""),
              timeout=0,
          )
          print(follow_up)
      finally:
          sandbox.kill()
          print("Sandbox killed")


  if __name__ == "__main__":
      main()
  ```

  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Novita } from 'novita-sandbox'

  const novita = new Novita({ apiKey: process.env.NOVITA_API_KEY })

  const sandbox = await novita.sandbox.create('codex', {
    timeoutMs: 3_600_000,
    envs: { CODEX_API_KEY: process.env.CODEX_API_KEY },
  })
  console.log('Sandbox created:', sandbox.sandboxId)

  try {
    // Start a new session with JSON output to capture the thread ID.
    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"',
      { timeoutMs: 0 }
    )
    // The first --json event is thread.started.
    const threadId = JSON.parse(initial.stdout.trim().split('\n')[0]).thread_id
    console.log('Thread ID:', threadId)

    // Resume the session with a follow-up task.
    const followUp = 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),
        timeoutMs: 0,
      }
    )
    console.log(followUp)
  } finally {
    await sandbox.kill()
    console.log('Sandbox killed')
  }
  ```
</CodeGroup>
