> ## 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.

# Configuration reference

> Every setting in o4's configuration files.

This page lists every key you can set in o4's configuration files: `config.toml` (policy and behavior), `settings.json` (preferences) and `display.json` (display options `/config` saves). For where the files live, which one wins, and how `/config` edits them, see [Configuration files](/configuration/overview).

All keys are optional. Anything you leave out uses the default shown.

## config.toml

`config.toml` can live in four places. From lowest to highest precedence:

1. `~/.o4/config.toml`, your user file.
2. `.o4/config.toml` in the project.
3. `.o4/config.local.toml` in the project.
4. `~/.o4/managed/config.toml`, the managed file for policy an organization sets.

Project files are read only in a [trusted workspace](/safety/workspace-trust). A key set in a higher file wins, except where a section below says its values are combined.

Most sections can go in any of the four files. These can't:

| Section | Files that may set it |
| - | - |
| `[daemon]`, `[codemode]` | User and managed. o4 ignores them in project files, with a warning in the log. |
| `[resume]` | User only. |
| `[watch]` | Project `.o4/config.toml` only. |

o4 ignores keys it doesn't know. If a file isn't valid TOML, or a known key has the wrong type, o4 stops at startup with an error that names the file.

### Top-level keys

<ParamField path="model" type="string">
  The default model, as a model reference such as `anthropic:claude-opus-5`. `model` in `settings.json` takes priority when both are set, and `-m` overrides both. See [Choosing a model](/models/overview).
</ParamField>

<ParamField path="auto_approve_plans" type="boolean" default="false">
  When o4 restores a plan at startup, keep it without asking **Continue** or **Abandon**. o4 restores the linked plan of a session you resume, and on a new session a plan marked `approved` or `executing`. See [Plan mode](/guides/plan-mode#plans-across-sessions). On if any config file turns it on.
</ParamField>

### permissions

Permission rules allow, ask about, or deny tool calls by pattern. Rules from every file are combined. See [Permissions](/safety/permissions#permission-rules) for the pattern syntax and precedence.

```toml theme={null}
[[permissions.rules]]
pattern = "Bash(npm test *)"
action = "allow"
```

| Key | Type | Meaning |
| - | - | - |
| `permissions.rules[].pattern` | string | A tool name, optionally with an argument pattern: `Write`, `Bash(git *)`, `Fetch(domain:docs.rs)`. |
| `permissions.rules[].action` | string | `allow`, `ask` or `deny`. |

### sandbox

Settings for the [sandbox](/safety/sandbox) around shell commands. List values are combined across files.

```toml theme={null}
[sandbox]
default_tier = "guarded"
allowedDomains = ["api.example.com"]
allowedPaths = ["~/scratch"]
escape_hatch_binaries = ["/usr/local/bin/docker"]

[sandbox.proxy]
enabled = true
```

| Key | Type | Default | Meaning |
| - | - | - | - |
| `default_tier` | string | `guarded` | Tier a session starts in: `open`, `guarded` or `airlock`. Pressing `Alt+S` saves the new tier here in the project's `.o4/config.toml`. |
| `allowedDomains` | list of strings | none | Extra hosts commands can reach in `guarded`. `example.com` also matches its subdomains, `*.example.com` matches only subdomains, and `*` matches every host. "Always allow this domain" adds entries to `~/.o4/config.toml`. |
| `allowedPaths` | list of strings | none | Extra paths commands can write in `guarded`. Absolute, `~/`, or relative to the workspace. Paths that overlap credential locations such as `~/.ssh` are dropped. |
| `escape_hatch_binaries` | list of strings | none | Absolute paths of programs that run outside the sandbox in `guarded`. |
| `proxy.enabled` | boolean | `true` | Set to `false` to turn off the egress proxy. Commands in `guarded` then get no network. |

### hooks

Hooks run a shell command or send an HTTP request at points in a session. Each `[[hooks]]` entry is one hook. Hooks from every file are combined and run in this order: `~/.o4/managed/config.toml`, `.o4/config.local.toml`, `.o4/config.toml`, `~/.o4/config.toml`, then any `hooks` block in the project's `.o4.md`. The first hook that blocks stops the rest. See [Hooks](/extend/hooks) for the events and what hooks can return.

```toml theme={null}
[[hooks]]
event = "PreToolUse"
matcher = "Bash"
command = "scripts/check-command.sh"
on_failure = "block"
```

| Key | Type | Default | Meaning |
| - | - | - | - |
| `event` | string | required | When the hook runs, such as `PreToolUse`, `PostToolUse`, `SessionStart` or `Stop`. See [Hooks](/extend/hooks#events) for all of them. |
| `matcher` | string | all tools | Tool names a tool event applies to, separated by `\|`, such as `Write\|Edit`. |
| `handler` | string | `command` | `command` runs `command` in a shell and `http` posts to `url`. `prompt` and `agent` also run a shell command, taken from the `prompt` field; neither calls a model. |
| `command` | string | none | Shell command, for `command` hooks. o4 runs it with `/bin/bash -c`. |
| `url` | string | none | For `http` hooks, the `http` or `https` URL o4 posts the event to as JSON. A `2xx` response lets the action continue, and any other status counts as a failure. Local and private network addresses are refused. |
| `prompt` | string | none | For `prompt` and `agent` hooks, the shell command to run. A `prompt` hook that contains `{{event_type}}`, `{{tool_name}}` or `{{tool_args}}` fails: the hook reads the event as JSON on standard input instead. |
| `model` | string | none | No effect. o4 accepts it, but no hook calls a model. |
| `on_failure` | string | `warn` | What happens when the hook fails or times out: `block`, `warn` or `ignore`. Other values are treated as `warn`. |
| `timeout_secs` | integer | 10 for `command` and `http`, 30 for `prompt` and `agent` | Seconds before the hook times out. |
| `env` | table | none | Extra environment variables for the hook's shell command. |
| `cwd` | string | o4's working directory | Working directory for the hook's shell command. |

### keybindings

Remaps TUI shortcuts. Each key is an action name and each value is a key: `alt-<key>`, `shift-tab`, `f1` to `f12`, or `ctrl-t`. Other `Ctrl` combinations are reserved. The new key replaces the action's default key. An unknown action or key shows a warning at startup and is skipped. When two files set the same action, the higher-precedence file wins.

```toml theme={null}
[keybindings]
cycle_approval = "f3"
cycle_sandbox_tier = "alt-y"
```

The actions are `cycle_reasoning`, `steer_current_task`, `edit_last_queued`, `resume_queue`, `cycle_approval`, `toggle_plan_mode`, `new_tab`, `close_tab`, `next_tab`, `prev_tab`, `cycle_model`, `undo_last_change`, `toggle_diff_pane`, `toggle_radar_pane`, `toggle_task_board`, `toggle_todo_list`, `open_transcript_reader`, `toggle_time_machine`, `cycle_sandbox_tier`, `repeat_with_correction`, `panic_pause`, `approve_pending` and `deny_pending`. See [Keyboard shortcuts](/reference/keyboard-shortcuts#remappable-actions) for each action's default key.

### watch

<ParamField path="watch.command" type="string">
  The check command [`o4 watch`](/guides/watch) runs after files change, for example `cargo test`. `o4 watch --command` overrides it. When unset, o4 picks a command from the project type. Read only from the project's `.o4/config.toml`, and only in a trusted workspace.
</ParamField>

### scout

`/scout` suggests which tools, MCP servers and skills a project needs, and applying its suggestions writes this section to the project's `.o4/config.toml`. See [Code intelligence](/guides/code-intelligence). You can also edit it by hand. The interactive UI applies it; print mode (`-p`) ignores it.

| Key | Type | Default | Meaning |
| - | - | - | - |
| `disabled` | boolean | `false` | Ignore the rest of this section. |
| `disabled_tools` | list of strings | none | Tools to leave out of the model's tool set, by name. Works for built-in and MCP tools. |
| `disabled_mcp_servers` | list of strings | none | MCP servers to turn off in this project. |
| `enabled_mcp_servers` | list of strings | none | MCP servers to turn on in this project. |
| `disabled_skills` | list of strings | none | Skills to leave out. |

`/scout` also writes `first_run`, `profile_hash` and `last_run` here. Nothing reads them in 0.2.74. The section is taken whole from the highest-precedence file that has one; `[scout]` tables from different files aren't combined.

### router

The model router keeps a session on one model and switches to a fallback after a provider error it can retry. `/router setup --yes` writes this section for you in `~/.o4/config.toml`, or in the project's `.o4/config.toml` with `--project`; without `--yes` it only shows what it would write. It won't write when a higher-precedence file already has a `[router]` section. `/router disable` sets `enabled = false`. On the Providers tab of `/config`, **Router setup** shows the same preview as `/router setup` without writing anything, **Router disable** (shown instead while the router is on) runs `/router disable`, and **Router status** runs `/router status`. o4 reads this section when a session starts, so changes take effect in the next session. [Model router and fallback](/models/router) explains how the router picks and switches models.

```toml theme={null}
[router]
enabled = true
candidates = ["anthropic:claude-opus-5", "openai:gpt-5.2"]
max_fallback_attempts = 2

[router.capacity.anthropic]
max_concurrent_requests = 4
```

| Key | Type | Default | Meaning |
| - | - | - | - |
| `enabled` | boolean | `false` | Turn the router on. |
| `mode` | string | `session` | Only `session` is supported. Any other value turns the router off, with a warning. |
| `candidates` | list of strings | built from your credentials | Models to route between, in order of preference. Without it, o4 builds the list from your current and default models plus the default model of each other provider you have credentials for. A built-in provider whose key is only in an environment variable, such as `ANTHROPIC_API_KEY`, counts only if it's your default provider. See [Which models the router can use](/models/router#which-models-the-router-can-use). |
| `max_fallback_attempts` | integer | `1` | How many times to fall back in one turn. Must be at least 1. |
| `context_safety_ratio` | number | `0.75` | Share of a model's context window a conversation may fill for that model to stay a candidate. Between 0 (exclusive) and 1. |
| `fallback_on` | list of strings | all four | Which errors trigger a fallback: `rate_limit`, `overloaded`, `timeout`, `server_error`. |
| `capacity.<provider>.max_concurrent_requests` | integer | none | Limit on requests in flight to one provider. Must be at least 1. |

o4 checks these values when it loads the config and writes a warning to `~/.o4/o4.log` for each problem. An out-of-range `context_safety_ratio` or `max_fallback_attempts` is replaced with the default. Unknown `fallback_on` entries are dropped, and a list with none left means all four. A `capacity` entry below 1 is dropped. Each key is taken from the highest-precedence file that sets it; `capacity` entries are combined by provider.

### daemon

Settings for the [o4 daemon](/extend/daemon). Read only from `~/.o4/config.toml` and `~/.o4/managed/config.toml`, and a key in the managed file wins; o4 ignores this section in project files. `enabled` and `idle_unload_secs` are accepted but have no effect (see [Keys that have no effect](#keys-that-have-no-effect)).

| Key | Type | Default | Meaning |
| - | - | - | - |
| `max_sessions` | integer | `64` | Sessions the daemon hosts before it refuses new ones. |
| `client_queue_max_events` | integer | `4096` | Events queued for one client connection before it's dropped. |
| `stop_grace_ms` | integer | `10000` | Milliseconds `o4 daemon stop` and `o4 daemon restart` wait after asking the daemon to exit before they force it. |
| `pressure_rss_mb` | integer | `4096` | Memory use, in MiB, above which the daemon refuses new sessions. |
| `pressure_open_files` | integer | `2048` | Open files above which the daemon refuses new sessions. |

### resume

<ParamField path="resume.cwd" type="string">
  Which directory a resumed session runs in when you resume it from a different directory: `session` (the session's own directory) or `current` (where you are now). o4 saves this when you pick one of the "Always use..." choices in the resume prompt. When unset, o4 asks. Read only from `~/.o4/config.toml`. See [Sessions](/guides/sessions#resuming-in-a-different-directory).
</ParamField>

### codemode

CodeMode is experimental and off by default. It gives the model an `exec` tool that runs JavaScript, in which o4's other tools are available as functions. Each call from inside a program goes through the same permission checks as a direct tool call. Read only from `~/.o4/config.toml` and `~/.o4/managed/config.toml`, and a key in the managed file wins; o4 ignores this section in project files, with a warning in the log. See [CodeMode](/extend/codemode) for how it works and which providers support it.

| Key | Type | Default | Meaning |
| - | - | - | - |
| `enabled` | boolean | `false` | Turn CodeMode on. |
| `direct_only_tools` | list of strings | none | Meant to list tools the model can call directly but not from a program. It has no effect in 0.2.74: o4 drops the value while loading the config. |
| `max_source_bytes` | integer | `65536` | Largest program, in bytes. At most `1048576`. |
| `wall_time_ms` | integer | `30000` | Time limit for one program, in milliseconds. At most `120000`, but o4 also stops a program 2 seconds before the 120-second tool timeout, so the real limit is 118 seconds. |
| `max_heap_bytes` | integer | `67108864` | Memory limit for a program. At most `268435456`. |
| `max_nested_calls` | integer | `64` | Tool calls one program may make. At most `256`. |
| `max_concurrency` | integer | `8` | Tool calls a program may run at the same time. At most `16`. |
| `max_nested_request_bytes` | integer | `65536` | Largest arguments for one tool call. At most `1048576`. |
| `max_aggregate_request_bytes` | integer | `1048576` | Total size of all tool-call arguments in one program. At most `8388608`. |
| `max_nested_result_bytes` | integer | `65536` | Largest result from one tool call. At most `1048576`. |
| `max_aggregate_result_bytes` | integer | `1048576` | Total size of all tool results in one program. At most `8388608`. |
| `max_return_bytes` | integer | `1048576` | No effect in 0.2.74. Programs send output with `text()` and similar functions, not a return value, and nothing reads this limit. |
| `cells` | boolean | `false` | Keep JavaScript state between programs in a session. |
| `max_cells` | integer | `8` | Cells kept at once, when `cells` is on. At most `32`. |
| `max_cell_heap_bytes` | integer | `67108864` | Memory limit for one cell. At most `268435456`. |
| `background` | boolean | `false` | Let a program keep running in the background, collected later with the `wait` tool. |
| `max_background_executions` | integer | `2` | Background programs at once, when `background` is on. At most `8`. |
| `grammar` | boolean | `false` | Offer `exec` to OpenAI Responses models as a free-form tool. |

A limit set to `0` or above its maximum is replaced with the default, with a warning in the log.

### Keys that have no effect

o4 0.2.74 accepts these `config.toml` keys without an error, but nothing uses them. Setting them changes nothing:

| Key | Notes |
| - | - |
| `allowed_tools` | A list of tool names. To control what the model may do, use [permission rules](/safety/permissions) instead. |
| `auto_compact_enabled`, `auto_compact_threshold`, `auto_compact_warning_threshold` | These work only in `settings.json`. See [Context and cost](/guides/context-and-cost). |
| `daemon.enabled` | Nothing starts the daemon automatically in 0.2.74. Start it with `o4 daemon start`. |
| `daemon.idle_unload_secs` | Not read by the daemon. |
| `codemode.direct_only_tools` | o4 drops the list while loading the config, so every tool stays callable from a program. |
| `codemode.max_return_bytes` | o4 checks the value but never applies it. |
| `hooks.model` (in a `[[hooks]]` entry) | No hook calls a model. `prompt` and `agent` hooks run their `prompt` field as a shell command. |
| `scout.first_run`, `scout.profile_hash`, `scout.last_run` | `/scout` writes them, but nothing reads them. |
| `watch.command` outside the project's `.o4/config.toml` | `o4 watch` reads `[watch]` only from the project's `.o4/config.toml`. |

## settings.json

`~/.o4/settings.json` holds your preferences. `/config` and the setup wizard write it, and you can edit it by hand. In a trusted workspace, a project's `.o4/settings.json` overrides it value by value (see [Configuration files](/configuration/overview#settings-json)); `api_keys`, `lsp_servers` and `formatters` are combined by name instead, with the project's entry winning. There is no managed `settings.json`. If a file isn't valid JSON, or a value has the wrong type (such as `"yes"` for a boolean) or an unknown choice, o4 ignores that whole file and uses the defaults. `/config` always saves to `~/.o4/settings.json`.

The last column says whether a row in `/config` changes the key.

### General

| Key | Type | Default | Meaning | In `/config` |
| - | - | - | - | - |
| `model` | string | from your credentials | Default model reference. Takes priority over `model` in `config.toml`, and `-m` overrides both. The setup wizard and the **Model** row in `/config` set it. | Yes: **Model** (Model tab) opens **Select Default Model** and saves your pick. |
| `reasoning` | string | `default` | Default reasoning level: `default`, `minimal`, `low`, `medium`, `high`, `extra-high` (or `xhigh`), `max` or `ultra`. `--reasoning` overrides it. An unknown value stops o4 from starting, with an error. See [Reasoning](/models/reasoning). | Yes: **Reasoning** (Reasoning tab) cycles through the levels the current model supports. |
| `permission_default` | string | `ask` | Permission mode new sessions start in: `ask`, `accept-edits`, `plan`, `review` or `auto` (`allow` also works). `--permission-mode` overrides it. See [Permissions](/safety/permissions#the-default-mode). | Yes: **Permission default** (General tab). |
| `memory_enabled` | boolean | `true` | Save and recall [memory](/guides/memory) between sessions. `auto_memory` is an older name for the same setting; `memory_enabled` wins when both are set. | Yes: **Auto memory** (General tab). It writes `memory_enabled` and removes `auto_memory`. |
| `suggestions_enabled` | boolean | `false` | Show suggestions at the start of a session and after each turn. | Yes: **Suggestions** (General tab). |
| `telemetry_enabled` | boolean | `true` | Send the anonymous daily usage ping and keep the local event log. See [Telemetry and privacy](/help/telemetry-and-privacy). | No. |
| `model_visible_attribution` | boolean | `false` | Tell the model which provider and model produced each earlier message. Affects only what's sent to the model. | No. |

### Providers and API keys

| Key | Type | Default | Meaning | In `/config` |
| - | - | - | - | - |
| `api_keys` | object | none | API keys by provider ID, such as `{"anthropic": "sk-ant-..."}`. Also takes `brave` and `tavily` keys for web search. These take priority over the environment variables. | Yes: **API key** (Providers tab) sets the key for the provider in the **Provider** row. An empty value removes it. |
| `default_provider` | string | none | Provider o4 prefers when it picks a default model. It doesn't change the current session's model. | Yes: **Provider** (Providers tab) cycles through the known providers. |
| `panel_rounds` | integer | `3` | Rounds a panel of two or more `^model` mentions discusses per message. `1` gives one answer per model; `0` counts as `1`. See [Panels](/guides/prompting#panels-of-two-or-more-models). | No |

Older versions stored keys in `anthropic_api_key`, `openai_api_key`, `google_api_key`, `xai_api_key`, `deepseek_api_key` and `ollama_api_key`. o4 still reads them when `api_keys` has no key for that provider, but new keys go in `api_keys`. Clearing a key with the **API key** row also removes the old field. See [Providers and API keys](/models/providers).

### Appearance

| Key | Type | Default | Meaning | In `/config` |
| - | - | - | - | - |
| `theme` | string | `auto` | Theme name. `auto` follows your terminal. Built-in names include `dark`, `light`, `dark-ansi`, `light-ansi`, `dark-daltonized` and `light-daltonized`. An unknown name falls back to `dark`. See [Themes and display](/configuration/appearance). | Yes: **Theme** (Appearance tab) moves to the next theme. |
| `nerd_fonts` | boolean | `true` | Use Nerd Font icons. Set to `false` if icons show as boxes. | Yes: **Nerd fonts** (Appearance tab). |
| `scrollbar` | boolean | `false` | Show a scrollbar when the chat is longer than the screen. | Yes: **Scrollbar** (Appearance tab). |
| `syntax_highlighting_disabled` | boolean | `false` | Turn off syntax highlighting in code blocks. | Yes: **Syntax highlight** (Appearance tab). The row shows the opposite value: `on` means this key is `false`. |
| `show_action_chips` | boolean | `true` | Show action chips below the model's replies. | Yes: **Action chips** (Appearance tab). |
| `show_file_watcher` | boolean | `true` | Watch the workspace for changes made outside o4. Takes effect after a restart. | Yes: **File watcher** (Appearance tab). |
| `reduce_motion` | boolean | `false` | Turn off animations. When it's `true`, animations stay off even if `animations` in `display.json` is `true`. | Yes: **Reduce motion** (Appearance tab). |
| `vim_mode` | boolean | `false` | Vim key bindings in the prompt. | Yes: **Vim mode** (Keys tab). |

### Notifications

| Key | Type | Default | Meaning | In `/config` |
| - | - | - | - | - |
| `notifications` | boolean or list | `true` | Terminal notifications. `true` or `false` turns all of them on or off. A list turns on only the events named: `agent-turn-complete`, `approval-requested`. `desktop_notifications` is an older name for the same key. | Yes: **Notifications** (General tab) switches between `true` and `false`, which replaces a list. |
| `notification_condition` | string | `unfocused` | When to notify: `unfocused` (only while the terminal isn't focused) or `always`. | Yes: **Notification condition** (General tab). |

### Context and background work

No `/config` row changes these keys. The setup wizard sets `auto_compact_enabled`. The three `auto_compact_*` keys apply in the interactive UI only.

| Key | Type | Default | Meaning |
| - | - | - | - |
| `auto_compact_enabled` | boolean | `true` | Compact the conversation when it gets close to the context limit. See [Context and cost](/guides/context-and-cost). |
| `auto_compact_threshold` | integer | `70` | Percentage of the context window at which o4 compacts. |
| `auto_compact_warning_threshold` | integer | `80` | Percentage of the context window at which o4 warns you. |
| `max_concurrent_agents` | integer | `10` | Sub-agents that can run at once. See [Subagents](/guides/subagents). |
| `auto_background_ms` | integer | `120000` | Milliseconds a foreground sub-agent or `bash` command runs before o4 moves it to the background. Commands that start with `sleep` time out instead. |
| `task_output_cap_bytes` | integer | `5368709120` (5 GiB) | Largest output o4 saves to disk for one background task. |
| `task_result_offload_chars` | integer | `100000` | Characters in a sub-agent's result above which o4 saves the result to a file instead of passing it to the model in full. |
| `terminal_evict_ms` | integer | `30000` | Milliseconds a finished task stays in the task list before it's removed. |

### Tools

The **LSP servers** and **Formatters** rows on the Tools tab of `/config` show these keys but can't change them; edit `settings.json` by hand. A trusted project's `.o4/settings.json` can add entries to both, and a project entry replaces a user entry with the same name.

<ParamField path="lsp_servers" type="object">
  Language servers for [code intelligence](/guides/code-intelligence), keyed by a name you choose. Each entry has `command` (required), `args` (a list) and `extensions` (a list of file extensions without the dot, such as `["rs"]`). An entry with an empty `command` or no extensions is ignored. Once the map has any entry, even an ignored one, it replaces the built-in servers (`rust-analyzer`, `typescript-language-server`, `pyright-langserver` and `gopls`). See [Language servers and formatters](/extend/lsp-and-formatters).
</ParamField>

<ParamField path="formatters" type="object">
  Formatters the model can run with its `format` tool, keyed by a name you choose. Each entry has `command` (required), `args` and `extensions`, like `lsp_servers`. o4 runs `command`, then `args`, then the file's path.
</ParamField>

```json theme={null}
{
  "lsp_servers": {
    "rust": { "command": "rust-analyzer", "extensions": ["rs"] }
  },
  "formatters": {
    "prettier": { "command": "prettier", "args": ["--write"], "extensions": ["ts", "tsx", "js"] }
  }
}
```

### Written by o4

o4 writes these keys itself. You don't need to set them.

| Key | Meaning |
| - | - |
| `last_catalog_fetch` | When the model catalog was last refreshed, as a Unix timestamp. At startup, o4 refreshes the catalog in the background when this is more than 7 days old or unset. **Refresh catalog** (Model tab in `/config`) also updates it. |
| `plugin_grants` | Permissions you granted to plugins. Only read from your own `settings.json`, never a project's. |

### settings.json keys with no effect

o4 0.2.74 reads these keys but they change nothing:

| Key | Notes |
| - | - |
| `message_style` | An older display setting. It takes `modern`, `accent`, `flat` or `bubbles`, and o4 always uses the same style. Any other value makes o4 ignore the whole file. |
| `bedrock_region` | Meant to set the AWS region for Amazon Bedrock, but o4 never passes it on. Set `AWS_REGION` instead. See [Environment variables](/reference/environment-variables#amazon-bedrock). |

## display.json

`~/.o4/display.json` holds display preferences that `/config` saves separately from `settings.json`. It exists only in your home folder; there is no project or managed `display.json`. Each time you change one of these rows, `/config` writes all four keys.

If you write the file by hand, include `show_timestamps`, `show_thinking` and `animations`. If one of them is missing, or the file isn't valid JSON, o4 ignores the whole file and uses the defaults. `screen_reader` may be left out.

| Key | Type | Default | Meaning | In `/config` |
| - | - | - | - | - |
| `show_timestamps` | boolean | `true` | Meant to show the time next to messages. o4 0.2.74 saves and loads it but never draws a timestamp, so it has no visible effect. | Yes: **Timestamps** (Appearance tab). |
| `show_thinking` | boolean | `false` | Show the model's thinking. | Yes: **Thinking display** (Reasoning tab). |
| `animations` | boolean | `true` | Animate spinners and transitions. `reduce_motion` in `settings.json` turns animations off even when this is `true`. | Yes: **Animations** (Appearance tab). |
| `screen_reader` | boolean | `false` | Screen reader output. The `--accessibility` flag turns it on for one run, but if you change any `display.json` row during that run, o4 saves this key as `true`. See [Themes and display](/configuration/appearance). | Yes: **Screen reader** (Appearance tab). |
