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

# CodeMode (experimental)

> Let the model write JavaScript programs that call o4's tools.

CodeMode gives the model an `exec` tool that runs a JavaScript program. Inside the program, o4's other tools are functions, so the model can make many tool calls in one step: read ten files, filter the results, and return only what matters. This saves turns and keeps large intermediate results out of the conversation.

CodeMode is experimental and off by default.

<Warning>
  Every tool call a program makes goes through the same checks as a direct call from the model: your [approval mode](/safety/permissions), permission rules, hooks and the [sandbox](/safety/sandbox) all still apply. The program itself has no file, network or shell access; it can only act through o4's tools.
</Warning>

## Turn it on

Add this to `~/.o4/config.toml`, or to `~/.o4/managed/config.toml`:

```toml theme={null}
[codemode]
enabled = true
```

o4 reads this when it starts, so restart o4 afterwards. A key in the managed file wins over the same key in your own file. o4 ignores a `[codemode]` section in a project's `.o4/config.toml` or `.o4/config.local.toml`, even in a trusted workspace, so a repository can't turn it on for you. It logs a `codemode_project_config_ignored` warning when it does.

When it's on, the main agent gets `exec` in interactive sessions and in print mode (`o4 -p`). Subagents and campaign workers don't get it. o4 also only offers `exec` with these providers:

| Provider | API |
| - | - |
| `anthropic`, `claude-code`, `kimi-coding` | Anthropic Messages |
| `openai`, `openai-codex`, `meta` | OpenAI Responses |
| `zai`, `zai-coding-plan` | OpenAI Chat Completions |
| `google` | Google Generative AI |
| `deepseek`, `xai`, `ollama` | Their native APIs |

With any other provider, including Amazon Bedrock and [OpenAI-compatible endpoints](/models/openai-compatible), the model doesn't get `exec`, and o4 logs `codemode_provider_unsupported` to `~/.o4/o4.log`.

## What a program looks like

The model writes the program; you don't need to. A program runs as an async JavaScript module, so it can use `await`:

```js theme={null}
const [files, todos] = await Promise.all([
  tools.glob({ pattern: "**/*.rs" }),
  tools.grep({ pattern: "TODO", path: ".", glob: "**/*.rs" }),
]);
text({ files: files.text.split("\n").length, todos: todos.text.split("\n").length });
```

Each tool call returns an object with `ok`, the tool's `text` output, `details`, and an `error` when `ok` is `false`.

A program can use:

| Name | What it does |
| - | - |
| `tools.<name>(input)` | Call an o4 tool, such as `tools.read` or `tools.grep`. MCP tools use their full name, such as `tools.mcp__github__create_issue`, with any character that isn't valid in a JavaScript name, such as `-`, replaced by `_`. `ALL_TOOLS` lists each tool's name and description. |
| `text()`, `image()`, `audio()`, `generatedImage()` | Send output back to the model. |
| `notify()` | Send output to the model right away while the program keeps running. |
| `store(key, value)`, `load(key)` | Save a plain JSON value and read it back. Values last between programs only when `cells = true`; otherwise each program starts empty. |
| `setTimeout()`, `clearTimeout()` | Timers. |
| `exit()` | End the program successfully. |
| `yield_control()` | Hand the output so far to the model and keep running in the background. Needs `background = true`. |

There's no `console`, `import`, `eval`, `Date`, `setInterval`, file system or network access in a program.

These tools can't be called from a program, only directly by the model: `enter_plan_mode`, `exit_plan_mode`, `enter_worktree`, `exit_worktree`, `ask_user_question`, `undo` and `checkpoint_restore`. A program can't call `exec` or `wait` either.

Every other tool in the session is callable from a program. The `[codemode]` key `direct_only_tools` is meant to keep more tools out, but it has no effect in 0.2.74: o4 drops the list while loading the config. To keep a tool away from programs, block it with a `deny` [permission rule](/safety/permissions), which applies inside programs too. In the interactive UI you can also leave it out of the session with `disabled_tools` in the project's [`[scout]` section](/reference/configuration#scout).

## Approvals

The `exec` call itself doesn't ask for approval, because turning CodeMode on is your approval to run programs. Each tool call inside a program asks just as it would if the model called the tool directly. If you deny a call, that call's result comes back with `ok: false` and an error, and the program can carry on or stop. The program's time limit keeps running while o4 waits for your answer.

In print mode nobody can answer, so a call that would ask is refused and the program gets an error. In [plan mode](/guides/plan-mode), a program can only call the tools plan mode allows.

## Options

| Setting | What it does |
| - | - |
| `cells = true` | Keep state between `exec` calls in a session: values saved with `store()` and properties a program sets on `globalThis`. Top-level `const`, `let` and `function` declarations don't carry over. All programs share one cell. A timeout, cancel, memory overrun or engine crash resets it, and so do `/clear` and switching models. `max_cells` and `max_cell_heap_bytes` limit cells. |
| `background = true` | Let a program keep running after it hands control back, and add a `wait` tool the model uses to collect the result. A program hands control back when it calls `yield_control()` or after 10 seconds, which the model can change per program. `max_background_executions` (default `2`) limits how many run at once. |
| `grammar = true` | For the `openai`, `openai-codex` and `meta` providers, send programs as plain text instead of inside JSON. |

The other keys set limits: program size, run time, memory, and the number, concurrency and size of tool calls. A program runs for up to 30 seconds by default. `wall_time_ms` can raise that to 120 seconds, but o4 also stops a program 2 seconds before its 120-second tool timeout, so the real maximum is 118 seconds. Each limit has a built-in ceiling, and a value of `0` or above the ceiling is replaced with the default. See the [configuration reference](/reference/configuration#codemode) for every key, default and maximum. Two keys have no effect in 0.2.74: `direct_only_tools` (see above) and `max_return_bytes`, which o4 checks but never applies.
