docs: describe this product, and only what it can do

The docs read as OpenAI's Codex CLI: a getting-started page titled for it,
`codex --enable skills` and `code sandbox macos` for commands that do not
exist, defaults given as gpt-5.1-codex-max/openai when they are
zen5-coder/hanzo, a Homebrew page describing a formula we do not publish.

Removed three tui-stream-chunking notes and the execpolicy page: they
document modules and a subcommand that live only in the vendored upstream
copy. There is no execpolicy subcommand and no .codexpolicy loader in
code-rs; the page told users to run something the binary does not have.

Rewrote tui-alternate-screen against the source. It described an
auto/always/never enum and a --no-alt-screen flag; the shipped behavior is a
tui.alternate_screen bool with Ctrl+T, which replays the transcript into
scrollback on the way out — a better answer to Zellij than the one written
down. Genuine openai-provider documentation stays.
This commit is contained in:
2026-08-07 21:51:19 -07:00
parent b3de714dec
commit 901a81abe9
27 changed files with 372 additions and 885 deletions
+3 -3
View File
@@ -140,7 +140,7 @@ session's key.
- [Configuration](docs/config.md)
- [Authentication](docs/authentication.md)
- [Sandboxing](docs/sandbox.md)
- [Themes](docs/THEME_CONFIG.md)
- [Settings overlay](docs/settings.md)
- [Hanzo docs](https://docs.hanzo.ai/docs)
## Building from source
@@ -152,8 +152,8 @@ cd dev
```
`./build-fast.sh` is the required check — it must pass cleanly, warnings
included. See [DEVELOPING.md](DEVELOPING.md) and [LLM.md](LLM.md) for the
workspace layout and the rules that apply inside it.
included. See [LLM.md](LLM.md) for the workspace layout and the rules that
apply inside it.
## Contributing
+17 -22
View File
@@ -2,14 +2,14 @@
## Non-interactive / CI mode
Run Every Code headless in pipelines. Example GitHub Action step:
Run Hanzo Dev headless in pipelines. Example GitHub Action step:
```yaml
- name: Update changelog via Code
- name: Update changelog via Dev
run: |
npm install -g @hanzo/dev
export OPENAI_API_KEY="${{ secrets.OPENAI_KEY }}"
code exec --full-auto "update CHANGELOG for next release"
export HANZO_API_KEY="${{ secrets.HANZO_API_KEY }}"
dev exec --full-auto "update CHANGELOG for next release"
```
### Resuming non-interactive sessions
@@ -19,36 +19,31 @@ You can resume a previous headless run to continue the same conversation context
Interactive TUI equivalent:
```shell
code resume # picker
code resume --last # most recent
code resume <SESSION_ID>
dev resume # picker
dev resume --last # most recent
dev resume <SESSION_ID>
```
Compatibility:
- Latest source builds include `code exec resume` (examples below).
- If `code exec --help` shows no `resume`, update to the latest release; the flag ships in v0.5.0 and newer.
```shell
# Resume the most recent recorded session and run with a new prompt
code exec "ship a release draft changelog" resume --last
dev exec "ship a release draft changelog" resume --last
# Alternatively, pass the prompt via stdin
# Note: omit the trailing '-' to avoid it being parsed as a SESSION_ID
echo "ship a release draft changelog" | code exec resume --last
echo "ship a release draft changelog" | dev exec resume --last
# Or resume a specific session by id (UUID)
code exec resume 7f9f9a2e-1b3c-4c7a-9b0e-123456789abc "continue the task"
dev exec resume 7f9f9a2e-1b3c-4c7a-9b0e-123456789abc "continue the task"
```
Notes:
- When using `--last`, Code picks the newest recorded session; if none exist, it behaves like starting fresh.
- When using `--last`, Dev picks the newest recorded session; if none exist, it behaves like starting fresh.
- Resuming appends new events to the existing session file and maintains the same conversation id.
## Tracing / verbose logging
Because Code is written in Rust, it honors the `RUST_LOG` environment variable to configure its logging behavior.
Because Dev is written in Rust, it honors the `RUST_LOG` environment variable to configure its logging behavior.
When you run the TUI with `--debug`, log messages are written to `~/.code/debug_logs/codex-tui.log`, so you can leave the following running in a separate terminal to monitor log messages as they are written:
@@ -74,16 +69,16 @@ subdirectories such as:
Tags become nested path components, so custom helpers appear alongside the
existing timestamped filenames.
Without `--debug`, Code only writes critical crash/error logs to
Without `--debug`, Dev only writes critical crash/error logs to
`~/.code/debug_logs/critical.log.*`; routine log output is suppressed.
By comparison, the non-interactive mode (`code exec`) defaults to `RUST_LOG=error`, but messages are printed inline, so there is no need to monitor a separate file.
By comparison, the non-interactive mode (`dev exec`) defaults to `RUST_LOG=error`, but messages are printed inline, so there is no need to monitor a separate file.
See the Rust documentation on [`RUST_LOG`](https://docs.rs/env_logger/latest/env_logger/#enabling-logging) for more information on the configuration options.
## Model Context Protocol (MCP)
The Code CLI can be configured to leverage MCP servers by defining an [`mcp_servers`](./config.md#mcp_servers) section in `~/.code/config.toml` (Code will also read a legacy `~/.codex/config.toml`). It is intended to mirror how tools such as Claude and Cursor define `mcpServers` in their respective JSON config files, though the Code format is slightly different since it uses TOML rather than JSON, e.g.:
Dev can be configured to leverage MCP servers by defining an [`mcp_servers`](./config.md#mcp_servers) section in `~/.code/config.toml` (Dev will also read a legacy `~/.codex/config.toml`). It is intended to mirror how tools such as Claude and Cursor define `mcpServers` in their respective JSON config files, though Dev's format is slightly different since it uses TOML rather than JSON, e.g.:
```toml
# IMPORTANT: the top-level key is `mcp_servers` rather than `mcpServers`.
@@ -93,6 +88,6 @@ args = ["-y", "mcp-server"]
env = { "API_KEY" = "value" }
```
## Using Code as an MCP Server
## Using Dev as an MCP Server
> [!TIP]
> It is somewhat experimental, but the Code CLI can also be run as an MCP _server_ via `code mcp`. If you launch it with an MCP client such as `npx @modelcontextprotocol/inspector code mcp` and send it a `tools/list` request, you will see that there is only one tool, `code`, that accepts a grab-bag of inputs, including a catch-all `config` map for anything you might want to override. Feel free to play around with it and provide feedback via GitHub issues.
> It is somewhat experimental, but Dev can also be run as an MCP _server_ via `dev mcp`. If you launch it with an MCP client such as `npx @modelcontextprotocol/inspector dev mcp` and send it a `tools/list` request, you will see that there is only one tool, `dev`, that accepts a grab-bag of inputs, including a catch-all `config` map for anything you might want to override. Feel free to play around with it and provide feedback via GitHub issues.
+9 -9
View File
@@ -1,6 +1,6 @@
# Agents & Subagents
Every Code can launch external CLI “agents” and orchestrate them in multi-agent “subagent” flows such as `/plan`, `/solve`, and `/code`.
Hanzo Dev can launch external CLI “agents” and orchestrate them in multi-agent “subagent” flows such as `/plan`, `/solve`, and `/code`.
## Agent configuration (`[[agents]]` in `config.toml`)
```toml
@@ -19,7 +19,7 @@ instructions = "Preamble added to this agent’s prompt"
Field recap: `name` (slug/alias), `command` (absolute paths ok), `args*` (RO/RW lists override base), `env`, `read_only`, `enabled`, optional `description` and `instructions`.
### Built-in defaults
If no `[[agents]]` are configured, Code advertises built-ins (gated by env `CODE_ENABLE_CLOUD_AGENT_MODEL` for cloud variants): `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `gemini-3.1-pro`, `claude-sonnet-4.6`, `gemini-3.5-flash`, `claude-haiku-4.5`, `qwen-3-coder`, `cloud-gpt-5.1-codex-max`. Built-ins strip any user `--model/-m` flags to avoid conflicts and inject their own.
If no `[[agents]]` are configured, Dev advertises built-ins (gated by env `CODE_ENABLE_CLOUD_AGENT_MODEL` for cloud variants): `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `gemini-3.1-pro`, `claude-sonnet-4.6`, `gemini-3.5-flash`, `claude-haiku-4.5`, `qwen-3-coder`, `cloud-gpt-5.1-codex-max`. Built-ins strip any user `--model/-m` flags to avoid conflicts and inject their own.
Tip: `gemini` resolves to `gemini-3.5-flash` through Antigravity CLI. Use `gemini-3.1-pro` when you want the higher-capacity Antigravity Gemini option.
@@ -29,13 +29,13 @@ Tip: `gemini` resolves to `gemini-3.5-flash` through Antigravity CLI. Use `gemin
name = "plan" # slash name (/plan, /solve, /code, or custom)
read_only = true # default plan/solve=true, code=false
agents = ["code-gpt-5.4", "claude-opus-4.8"] # falls back to enabled agents or built-ins
orchestrator_instructions = "Guidance for Code before spawning agents"
orchestrator_instructions = "Guidance for Dev before spawning agents"
agent_instructions = "Preamble added to each spawned agent"
```
- `name`: slash command created/overridden.
- `read_only`: forces spawned agents to RO when true.
- `agents`: explicit list; empty → enabled `[[agents]]`; none configured → built-in roster.
- `orchestrator_instructions`: appended to the Code-side prompt before issuing `agent.create`.
- `orchestrator_instructions`: appended to the Dev-side prompt before issuing `agent.create`.
- `agent_instructions`: appended to each spawned agent prompt.
The orchestrator fans out agents, waits for results, and merges reasoning according to your `hide_agent_reasoning` / `show_raw_agent_reasoning` settings.
@@ -52,7 +52,7 @@ The orchestrator fans out agents, waits for results, and merges reasoning accord
- `AUTO_AGENTS.md` is read alongside `AGENTS.md` for Auto Drive–specific guidance.
## AGENTS.md and project memory
- Code loads AGENTS.md files along the path (global, repo root, cwd) up to 32 KiB total; deeper files override higher-level ones.
- Dev loads AGENTS.md files along the path (global, repo root, cwd) up to 32 KiB total; deeper files override higher-level ones.
- Contents become system/developer instructions on the first turn; direct user/developer prompts still take precedence.
## Windows discovery tips
@@ -61,14 +61,14 @@ The orchestrator fans out agents, waits for results, and merges reasoning accord
- If PATH is unreliable, use absolute `command` paths in `[[agents]]`.
## Notifications and reasoning visibility
- `hide_agent_reasoning = true` removes agent reasoning streams in both the TUI and `code exec`.
- `hide_agent_reasoning = true` removes agent reasoning streams in both the TUI and `dev exec`.
- `show_raw_agent_reasoning = true` surfaces raw chains-of-thought when provided by the model.
- Notification filtering is controlled via `/notifications` or `config.toml` `notify` / `tui.notifications`.
## Headless `code exec`
- `code exec --json` streams JSONL events (agent turns included).
## Headless `dev exec`
- `dev exec --json` streams JSONL events (agent turns included).
- `--output-schema <schema.json>` enforces structured JSON output; combine with `--output-last-message` to capture only the final payload.
- `code exec` defaults to read-only; add `--full-auto` plus a writable sandbox to permit edits.
- `dev exec` defaults to read-only; add `--full-auto` plus a writable sandbox to permit edits.
## Quick examples
- Custom agent:
+52 -68
View File
@@ -1,8 +1,24 @@
# Authentication
## Usage-based billing alternative: Use an OpenAI API key
## Signing in
If you prefer to pay-as-you-go, you can still authenticate with your OpenAI API key by setting it as an environment variable:
Dev talks to the Hanzo gateway (`api.hanzo.ai/v1`) by default. Sign in once and
the machine is linked to your account:
```shell
hanzo auth login
```
That fills in `HANZO_USER_KEY`. You can also set it yourself from a key minted at
https://hanzo.ai/settings/keys. A service that runs Dev unattended sets
`HANZO_API_KEY` or `HANZO_MACHINE_TOKEN` instead.
## Using the `openai` provider
Everything below applies only when you point `model_provider` at `openai` — see
[Configuration](./config.md#model_providers).
Authenticate with an API key:
```shell
export OPENAI_API_KEY="your-api-key-here"
@@ -11,77 +27,53 @@ export OPENAI_API_KEY="your-api-key-here"
Alternatively, read from a file:
```shell
code login --with-api-key < my_key.txt
dev login --with-api-key < my_key.txt
```
The legacy `--api-key` flag now exits with an error instructing you to use `--with-api-key` so that the key never appears in shell history or process listings.
The key must, at minimum, have write access to the Responses API. The legacy
`--api-key` flag exits with an error pointing at `--with-api-key`, so the key
never appears in shell history or process listings.
This key must, at minimum, have write access to the Responses API.
To switch from an API key to a ChatGPT plan, delete `~/.code/auth.json` (and the
legacy `~/.codex/auth.json` if it exists; on Windows both live under
`C:\Users\USERNAME\`) and run `dev login` again.
## Migrating to ChatGPT login from API key
### Forcing a specific auth method
If you've used the Code CLI before with usage-based billing via an API key and want to switch to using your ChatGPT plan, follow these steps:
1. Update the CLI and ensure `code --version` is `0.5.0` or later
2. Delete `~/.code/auth.json` (and remove the legacy `~/.codex/auth.json` if it exists; on Windows these live under `C:\\Users\\USERNAME\\.code\\auth.json` and `C:\\Users\\USERNAME\\.codex\\auth.json`)
3. Run `code login` again
## Forcing a specific auth method (advanced)
You can explicitly choose which authentication Code should prefer when both are available.
- To always use your API key (even when ChatGPT auth exists), set:
When both are available, choose which one wins:
```toml
# ~/.code/config.toml (Code also reads legacy ~/.codex/config.toml)
preferred_auth_method = "apikey"
# ~/.code/config.toml (a legacy ~/.codex/config.toml is also read)
preferred_auth_method = "apikey" # or "chatgpt" (default)
```
Or override ad-hoc via CLI:
Or ad-hoc: `dev --config preferred_auth_method="apikey"`.
```bash
code --config preferred_auth_method="apikey"
```
With `"apikey"` and a key available, the login screen is skipped. With
`"chatgpt"`, ChatGPT auth wins if present and the API key is the fallback;
some account types require API-key mode regardless. `/status` in the TUI reports
which one the session is using, and the chat footer shows an “Auth: API key”
badge when a key is in play.
- To prefer ChatGPT auth (default), set:
### Project `.env` safety
```toml
# ~/.code/config.toml (Code also reads legacy ~/.codex/config.toml)
preferred_auth_method = "chatgpt"
```
Dev does not read `OPENAI_API_KEY` or `AZURE_OPENAI_API_KEY` from a project's
local `.env` — many repos keep a key there for unrelated tooling, which would
silently spend against the key instead of your plan. There is no opt-in.
Notes:
`~/.code/.env` (or `~/.codex/.env`) is loaded first and may hold a global
`OPENAI_API_KEY`, and a shell-exported one is honored.
- When `preferred_auth_method = "apikey"` and an API key is available, the login screen is skipped.
- When `preferred_auth_method = "chatgpt"` (default), Code prefers ChatGPT auth if present; if only an API key is present, it will use the API key. Certain account types may also require API-key mode.
- To check which auth method is being used during a session, use the `/status` command in the TUI.
## Connecting on a "headless" machine
## Project .env safety (OPENAI_API_KEY)
`dev login` runs a server on `localhost:1455`. In a Docker container or over
`ssh`, your local browser cannot reach it, so use one of these.
By default, Code will no longer read `OPENAI_API_KEY` or `AZURE_OPENAI_API_KEY` from a project’s local `.env` file.
### Copy credentials from a machine that has a browser
Why: many repos include an API key in `.env` for unrelated tooling, which could cause Code to silently use the API key instead of your ChatGPT plan in that folder.
What still works:
- `~/.code/.env` (or `~/.codex/.env`) is loaded first and may contain your `OPENAI_API_KEY` for global use.
- A shell-exported `OPENAI_API_KEY` is honored.
Project `.env` provider keys are always ignored — there is no opt‑in.
UI clarity:
- When Code is using an API key, the chat footer shows a bold “Auth: API key” badge so it’s obvious which mode you’re in.
## Connecting on a "Headless" Machine
Today, the login process entails running a server on `localhost:1455`. If you are on a "headless" server, such as a Docker container or are `ssh`'d into a remote machine, loading `localhost:1455` in the browser on your local machine will not automatically connect to the webserver running on the _headless_ machine, so you must use one of the following workarounds:
### Authenticate locally and copy your credentials to the "headless" machine
The easiest solution is likely to run through the `code login` process on your local machine such that `localhost:1455` _is_ accessible in your web browser. When you complete the authentication process, an `auth.json` file should be available at `$CODE_HOME/auth.json` (defaults to `~/.code/auth.json`; Code will still read `$CODEX_HOME`/`~/.codex/auth.json` if present).
Because the `auth.json` file is not tied to a specific host, once you complete the authentication flow locally, you can copy the `$CODE_HOME/auth.json` file to the headless machine and then `code` should "just work" on that machine. Note to copy a file to a Docker container, you can do:
Complete `dev login` locally, then copy the resulting `$CODE_HOME/auth.json`
(defaults to `~/.code/auth.json`) across — it is not tied to a host. Into a
container:
```shell
# substitute MY_CONTAINER with the name or id of your Docker container:
@@ -90,26 +82,18 @@ docker exec MY_CONTAINER mkdir -p "$CONTAINER_HOME/.code"
docker cp auth.json MY_CONTAINER:"$CONTAINER_HOME/.code/auth.json"
```
whereas if you are `ssh`'d into a remote machine, you likely want to use [`scp`](https://en.wikipedia.org/wiki/Secure_copy_protocol):
```shell
ssh user@remote 'mkdir -p ~/.code'
scp ~/.code/auth.json user@remote:~/.code/auth.json
```
or try this one-liner:
Or onto a remote host:
```shell
ssh user@remote 'mkdir -p ~/.code && cat > ~/.code/auth.json' < ~/.code/auth.json
```
### Connecting through VPS or remote
If you run Code on a remote machine (VPS/server) without a local browser, the login helper starts a server on `localhost:1455` on the remote host. To complete login in your local browser, forward that port to your machine before starting the login flow:
### Forward the login port
```bash
# From your local machine
ssh -L 1455:localhost:1455 <user>@<remote-host>
```
Then, in that SSH session, run `code` and select "Sign in with ChatGPT". When prompted, open the printed URL (it will be `http://localhost:1455/...`) in your local browser. The traffic will be tunneled to the remote server.
Then run `dev login` in that SSH session and open the printed
`http://localhost:1455/...` URL locally. The traffic is tunneled to the remote.
+6 -6
View File
@@ -1,10 +1,10 @@
# Auto Drive
What Auto Drive is, how to start it, and how it behaves in Every Code.
What Auto Drive is, how to start it, and how it behaves in Hanzo Dev.
## Start points
- TUI: `/auto <goal>`. If you omit the goal and there is recent history, Code proposes one for you. `/auto settings` jumps straight to the Auto Drive pane.
- CLI: `code exec --auto "<goal>"` or `code exec "/auto <goal>"`. A goal is required when launching headless.
- TUI: `/auto <goal>`. If you omit the goal and there is recent history, Dev proposes one for you. `/auto settings` jumps straight to the Auto Drive pane.
- CLI: `dev exec --auto "<goal>"` or `dev exec "/auto <goal>"`. A goal is required when launching headless.
- Precondition: Full Auto mode (danger-full-access + approval=never) must be selected in the TUI; otherwise you’ll see a warning and Auto Drive will not start.
## Goal handling
@@ -43,8 +43,8 @@ What Auto Drive is, how to start it, and how it behaves in Every Code.
## Crash diagnostics
- Set `CODEX_TUI_RECORD_SESSION=1` to persist a per-session JSONL trace of inbound TUI events, including Auto Drive coordinator decisions, countdowns, token metrics, and panic records.
- Optionally set `CODEX_TUI_SESSION_LOG_PATH=/absolute/path/session.jsonl` to choose the output file; otherwise Code writes under its normal log directory (typically `~/.code/debug_logs/`, and `code-dev` defaults to `~/.code/debug_logs/code-dev/`).
- When the TUI panics, Code now records the panic payload and captured backtrace in both the session JSONL log and the regular error log.
- Optionally set `CODEX_TUI_SESSION_LOG_PATH=/absolute/path/session.jsonl` to choose the output file; otherwise Dev writes under its normal log directory (typically `~/.code/debug_logs/`, and `code-dev` defaults to `~/.code/debug_logs/code-dev/`).
- When the TUI panics, Dev now records the panic payload and captured backtrace in both the session JSONL log and the regular error log.
## Models
- Defaults: model `gpt-5.1`, reasoning effort `high`.
@@ -71,6 +71,6 @@ What Auto Drive is, how to start it, and how it behaves in Every Code.
- All of these can be changed from `/auto settings` in the TUI or directly in `config.toml`.
## Tips
- Stay in the TUI if you want countdowns and visual status; use `code exec --auto` for CI or scripted flows.
- Stay in the TUI if you want countdowns and visual status; use `dev exec --auto` for CI or scripted flows.
- If Auto Drive stops because it couldn’t derive a goal, rerun `/auto <goal>` with a short, specific instruction.
- Turn off agents in `/auto settings` if you want a single-model run.
+90 -87
View File
@@ -2,32 +2,30 @@
<!-- markdownlint-disable MD012 MD013 MD028 MD033 -->
Every Code supports several mechanisms for setting config values:
Hanzo Dev supports several mechanisms for setting config values:
- Config-specific command-line flags, such as `--model o3` (highest precedence).
- A generic `-c`/`--config` flag that takes a `key=value` pair, such as `--config model="o3"`.
- The key can contain dots to set a value deeper than the root, e.g. `--config model_providers.openai.wire_api="chat"`.
- For consistency with `config.toml`, values are a string in TOML format rather than JSON format, so use `key='{a = 1, b = 2}'` rather than `key='{"a": 1, "b": 2}'`.
- The quotes around the value are necessary, as without them your shell would split the config argument on spaces, resulting in `code` receiving `-c key={a` with (invalid) additional arguments `=`, `1,`, `b`, `=`, `2}`.
- The quotes around the value are necessary, as without them your shell would split the config argument on spaces, resulting in `dev` receiving `-c key={a` with (invalid) additional arguments `=`, `1,`, `b`, `=`, `2}`.
- Values can contain any TOML object, such as `--config shell_environment_policy.include_only='["PATH", "HOME", "USER"]'`.
- If `value` cannot be parsed as a valid TOML value, it is treated as a string value. This means that `-c model='"o3"'` and `-c model=o3` are equivalent.
- In the first case, the value is the TOML string `"o3"`, while in the second the value is `o3`, which is not valid TOML and therefore treated as the TOML string `"o3"`.
- Because quotes are interpreted by one's shell, `-c key="true"` will be correctly interpreted in TOML as `key = true` (a boolean) and not `key = "true"` (a string). If for some reason you needed the string `"true"`, you would need to use `-c key='"true"'` (note the two sets of quotes).
- The `$CODE_HOME/config.toml` configuration file. `CODE_HOME` defaults to `~/.code`; Every Code (Code) also reads from `$CODEX_HOME`/`~/.codex` for backwards compatibility but only writes to `~/.code`. (Logs and other state use the same directory.)
- https://developers.openai.com/codex/config-reference
- The `$CODE_HOME/config.toml` configuration file. `CODE_HOME` defaults to `~/.code`; Hanzo Dev also reads from `$CODEX_HOME`/`~/.codex` for backwards compatibility but only writes to `~/.code`. (Logs and other state use the same directory.)
## model
The model that Code should use.
The model that Dev should use.
```toml
model = "o3" # overrides the default of "gpt-5.1-codex"
model = "zen5-coder" # the default on the `hanzo` provider
```
## model_providers
This option lets you override and amend the default set of model providers bundled with Code. This value is a map where the key is the value to use with `model_provider` to select the corresponding provider. Providers must expose an OpenAI-compatible HTTP API (Chat Completions or Responses); native Anthropic/Gemini APIs are not supported directly without a proxy.
This option lets you override and amend the default set of model providers bundled with Dev. This value is a map where the key is the value to use with `model_provider` to select the corresponding provider. Providers must expose an OpenAI-compatible HTTP API (Chat Completions or Responses); native Anthropic/Gemini APIs are not supported directly without a proxy.
For example, if you wanted to add a provider that uses the OpenAI 4o model via the chat completions API, then you could add the following configuration:
@@ -37,13 +35,13 @@ model = "gpt-4o"
model_provider = "openai-chat-completions"
[model_providers.openai-chat-completions]
# Name of the provider that will be displayed in the Code UI.
# Name of the provider that will be displayed in the Dev UI.
name = "OpenAI using Chat Completions"
# The path `/chat/completions` will be amended to this URL to make the POST
# request for the chat completions.
base_url = "https://api.openai.com/v1"
# If `env_key` is set, identifies an environment variable that must be set when
# using Code with this provider. The value of the environment variable must be
# using Dev with this provider. The value of the environment variable must be
# non-empty and will be used in the `Bearer TOKEN` HTTP header for the POST request.
env_key = "OPENAI_API_KEY"
# Valid values for wire_api are "chat" and "responses". Defaults to "chat" if omitted.
@@ -53,7 +51,7 @@ wire_api = "chat"
query_params = {}
```
Note this makes it possible to use the Code CLI with non-OpenAI models, so long as they use a wire API that is compatible with the OpenAI chat completions API. For example, you could define the following provider to use Code CLI with Ollama running locally:
Note this makes it possible to use Dev with non-OpenAI models, so long as they use a wire API that is compatible with the OpenAI chat completions API. For example, you could define the following provider to use Dev with Ollama running locally:
```toml
[model_providers.ollama]
@@ -88,7 +86,7 @@ requires_openai_auth = false
[OmniRoute](https://github.com/diegosouzapw/OmniRoute) exposes OpenAI-compatible
`/v1/chat/completions` and `/v1/responses` endpoints. Configure it as a custom
provider so Code sends the OmniRoute API key in a Bearer header and does not try
provider so Dev sends the OmniRoute API key in a Bearer header and does not try
to use ChatGPT authentication:
```toml
@@ -103,13 +101,13 @@ wire_api = "responses" # Use "chat" when targeting /v1/chat/completions.
requires_openai_auth = false
```
Start Code with `OMNIROUTE_API_KEY` set in the environment. The `base_url` is
the `/v1` root because Code appends `/responses` or `/chat/completions` for the
Start Dev with `OMNIROUTE_API_KEY` set in the environment. The `base_url` is
the `/v1` root because Dev appends `/responses` or `/chat/completions` for the
selected `wire_api`. With OmniRoute, `auto` (and other `auto/*` model IDs) lets
the gateway choose a connected model; replace it with a concrete model ID when
you need deterministic routing.
Code's remote model discovery is limited to its ChatGPT backend, so custom
Dev's remote model discovery is limited to its ChatGPT backend, so custom
providers such as OmniRoute do not populate the model picker from `/v1/models`.
Set `model` explicitly in `config.toml` or pass `--model` when using a custom
provider. Function tools and streamed responses use the selected OpenAI wire
@@ -146,7 +144,7 @@ query_params = { api-version = "2025-04-01-preview" }
wire_api = "responses"
```
Export your key before launching Code: `export AZURE_OPENAI_API_KEY=…`
Export your key before launching Dev: `export AZURE_OPENAI_API_KEY=…`
### Per-provider network tuning
@@ -167,19 +165,19 @@ stream_idle_timeout_ms = 300000 # 5m idle timeout
#### request_max_retries
How many times Code will retry a failed HTTP request to the model provider. Defaults to `4`.
How many times Dev will retry a failed HTTP request to the model provider. Defaults to `4`.
#### stream_max_retries
Number of times Code will attempt to reconnect when a streaming response is interrupted. Defaults to `5`.
Number of times Dev will attempt to reconnect when a streaming response is interrupted. Defaults to `5`.
#### stream_idle_timeout_ms
How long Code will wait for activity on a streaming response before treating the connection as lost. Defaults to `300_000` (5 minutes).
How long Dev will wait for activity on a streaming response before treating the connection as lost. Defaults to `300_000` (5 minutes).
## model_provider
Identifies which provider to use from the `model_providers` map. Defaults to `"openai"`. You can override the `base_url` for the built-in `openai` provider via the `OPENAI_BASE_URL` environment variable and force the wire protocol (`"responses"` or `"chat"`) with `OPENAI_WIRE_API`.
Identifies which provider to use from the `model_providers` map. Defaults to `"hanzo"`. You can override the `base_url` for the built-in `openai` provider via the `OPENAI_BASE_URL` environment variable and force the wire protocol (`"responses"` or `"chat"`) with `OPENAI_WIRE_API`.
Note that if you override `model_provider`, then you likely want to override
`model`, as well. For example, if you are running ollama with Mistral locally,
@@ -192,11 +190,11 @@ model = "mistral"
## approval_policy
Determines when the user should be prompted to approve whether Code can execute a command:
Determines when the user should be prompted to approve whether Dev can execute a command:
```toml
# Code has hardcoded logic that defines a set of "trusted" commands.
# Setting the approval_policy to `untrusted` means that Code will prompt the
# Dev has hardcoded logic that defines a set of "trusted" commands.
# Setting the approval_policy to `untrusted` means that Dev will prompt the
# user before running a command not in the "trusted" set.
#
# A configurable trusted-command list is planned; for now the built-in set is fixed.
@@ -206,7 +204,7 @@ approval_policy = "untrusted"
If you want to be notified whenever a command fails, use "on-failure":
```toml
# If the command fails when run in the sandbox, Code asks for permission to
# If the command fails when run in the sandbox, Dev asks for permission to
# retry the command outside the sandbox.
approval_policy = "on-failure"
```
@@ -221,16 +219,16 @@ approval_policy = "on-request"
Alternatively, you can have the model run until it is done, and never ask to run a command with escalated permissions:
```toml
# User is never prompted: if the command fails, Code will automatically try
# User is never prompted: if the command fails, Dev will automatically try
# something out. Note the `exec` subcommand always uses this mode.
approval_policy = "never"
```
## agents
Use `[[agents]]` blocks to register additional CLI programs that Code can launch as peers. Each block maps a short `name` (referenced elsewhere in the config) to the command to execute, optional default flags, and environment variables.
Use `[[agents]]` blocks to register additional CLI programs that Dev can launch as peers. Each block maps a short `name` (referenced elsewhere in the config) to the command to execute, optional default flags, and environment variables.
> **Note:** Built-in model slugs (for example `code-gpt-5.5`, `claude-sonnet-4.6`) automatically inject the correct `--model` or `-m` flag. To avoid conflicting arguments, Code strips any `--model`/`-m` flags you place in `args`, `args_read_only`, or `args_write` before launching the agent. If you need a new model variant, add a slug in `code-rs/core/src/agent_defaults.rs` (or set an environment variable consumed by the CLI) rather than pinning the flag here.
> **Note:** Built-in model slugs (for example `code-gpt-5.5`, `claude-sonnet-4.6`) automatically inject the correct `--model` or `-m` flag. To avoid conflicting arguments, Dev strips any `--model`/`-m` flags you place in `args`, `args_read_only`, or `args_write` before launching the agent. If you need a new model variant, add a slug in `code-rs/core/src/agent_defaults.rs` (or set an environment variable consumed by the CLI) rather than pinning the flag here.
```toml
[[agents]]
@@ -245,9 +243,9 @@ env = { GEMINI_API_KEY = "..." }
## notice
Code stores acknowledgement flags for one-time upgrade prompts inside a `[notice]`
Dev stores acknowledgement flags for one-time upgrade prompts inside a `[notice]`
table. These booleans allow you to suppress specific dialogs globally. When set
to `true`, Code will no longer prompt about that migration.
to `true`, Dev will no longer prompt about that migration.
```toml
[notice]
@@ -302,7 +300,7 @@ Users can specify config values at multiple levels. Order of precedence is as fo
1. custom command-line argument, e.g., `--model o3`
2. as part of a profile, where the `--profile` is specified via a CLI (or in the config file itself)
3. as an entry in `config.toml`, e.g., `model = "o3"`
4. the default value that comes with Code CLI (i.e., Code CLI defaults to `gpt-5.1-codex`)
4. the default value that comes with Dev (i.e., `zen5-coder` on the `hanzo` provider)
## model_reasoning_effort
@@ -337,7 +335,7 @@ Controls output length/detail on GPT‑5 family models when using the Responses
- `"medium"` (default when omitted)
- `"high"`
When set, Code includes a `text` object in the request payload with the configured verbosity, for example: `"text": { "verbosity": "low" }`.
When set, Dev includes a `text` object in the request payload with the configured verbosity, for example: `"text": { "verbosity": "low" }`.
Example:
@@ -358,7 +356,7 @@ model_supports_reasoning_summaries = true
## sandbox_mode
Code executes model-generated shell commands inside an OS-level sandbox.
Dev executes model-generated shell commands inside an OS-level sandbox.
In most cases you can pick the desired behaviour with a single option:
@@ -370,9 +368,9 @@ sandbox_mode = "read-only"
The default policy is `read-only`, which means commands can read any file on
disk, but attempts to write a file or access the network will be blocked.
A more relaxed policy is `workspace-write`. When specified, the current working directory for the Code task will be writable (as well as `$TMPDIR` on macOS). Note that the CLI defaults to using the directory where it was spawned as `cwd`, though this can be overridden using `--cwd/-C`.
A more relaxed policy is `workspace-write`. When specified, the current working directory for the Dev task will be writable (as well as `$TMPDIR` on macOS). Note that the CLI defaults to using the directory where it was spawned as `cwd`, though this can be overridden using `--cwd/-C`.
Historically, Code allowed writes inside the top‑level `.git/` folder when using `workspace-write`. That permissive behavior is the default again. If you want to protect `.git` under `workspace-write`, you can opt out via `[sandbox_workspace_write].allow_git_writes = false`.
Historically, Dev allowed writes inside the top‑level `.git/` folder when using `workspace-write`. That permissive behavior is the default again. If you want to protect `.git` under `workspace-write`, you can opt out via `[sandbox_workspace_write].allow_git_writes = false`.
```toml
# same as `--sandbox workspace-write`
@@ -380,7 +378,7 @@ sandbox_mode = "workspace-write"
# Extra settings that only apply when `sandbox = "workspace-write"`.
[sandbox_workspace_write]
# By default, the cwd for the Code session will be writable as well as $TMPDIR
# By default, the cwd for the Dev session will be writable as well as $TMPDIR
# (if set) and /tmp (if it exists). Setting the respective options to `true`
# will override those defaults.
exclude_tmpdir_env_var = false
@@ -404,30 +402,30 @@ To disable sandboxing altogether, specify `danger-full-access` like so:
sandbox_mode = "danger-full-access"
```
This is reasonable to use if Code is running in an environment that provides its own sandboxing (such as a Docker container) such that further sandboxing is unnecessary.
This is reasonable to use if Dev is running in an environment that provides its own sandboxing (such as a Docker container) such that further sandboxing is unnecessary.
Though using this option may also be necessary if you try to use Code in environments where its native sandboxing mechanisms are unsupported, such as older Linux kernels or on Windows.
Though using this option may also be necessary if you try to use Dev in environments where its native sandboxing mechanisms are unsupported, such as older Linux kernels or on Windows.
## Approval presets
Code provides three main Approval Presets:
Dev provides three main Approval Presets:
- Read Only: Code can read files and answer questions; edits, running commands, and network access require approval.
- Auto: Code can read files, make edits, and run commands in the workspace without approval; asks for approval outside the workspace or for network access.
- Read Only: Dev can read files and answer questions; edits, running commands, and network access require approval.
- Auto: Dev can read files, make edits, and run commands in the workspace without approval; asks for approval outside the workspace or for network access.
- Full Access: Full disk and network access without prompts; extremely risky.
You can further customize how Code runs at the command line using the `--ask-for-approval` and `--sandbox` options.
You can further customize how Dev runs at the command line using the `--ask-for-approval` and `--sandbox` options.
## MCP Servers
You can configure Code to use [MCP servers](https://modelcontextprotocol.io/about) to give Code access to external applications, resources, or services such as [Playwright](https://github.com/microsoft/playwright-mcp), [Figma](https://www.figma.com/blog/design-context-everywhere-you-build/), [documentation](https://context7.com/), and [more](https://github.com/mcp?utm_source=blog-source&utm_campaign=mcp-registry-server-launch-2025).
You can configure Dev to use [MCP servers](https://modelcontextprotocol.io/about) to give Dev access to external applications, resources, or services such as [Playwright](https://github.com/microsoft/playwright-mcp), [Figma](https://www.figma.com/blog/design-context-everywhere-you-build/), [documentation](https://context7.com/), and [more](https://github.com/mcp?utm_source=blog-source&utm_campaign=mcp-registry-server-launch-2025).
### Server transport configuration
Each server may set `startup_timeout_sec` to adjust how long Code waits for it to start and respond to a tools listing. The default is `10` seconds.
Similarly, `tool_timeout_sec` limits how long individual tool calls may run (default: `60` seconds), and Code will fall back to the default when this value is omitted.
Each server may set `startup_timeout_sec` to adjust how long Dev waits for it to start and respond to a tools listing. The default is `10` seconds.
Similarly, `tool_timeout_sec` limits how long individual tool calls may run (default: `60` seconds), and Dev will fall back to the default when this value is omitted.
This config option is comparable to how Claude and Cursor define `mcpServers` in their respective JSON config files, though because Code uses TOML for its config language, the format is slightly different. For example, the following config in JSON:
This config option is comparable to how Claude and Cursor define `mcpServers` in their respective JSON config files, though because Dev uses TOML for its config language, the format is slightly different. For example, the following config in JSON:
```json
{
@@ -443,7 +441,7 @@ This config option is comparable to how Claude and Cursor define `mcpServers` in
}
```
Should be represented as follows in `~/.code/config.toml` (Code will also read the legacy `~/.codex/config.toml` if it exists):
Should be represented as follows in `~/.code/config.toml` (Dev will also read the legacy `~/.codex/config.toml` if it exists):
```toml
# The top-level table name must be `mcp_servers`
@@ -479,9 +477,9 @@ tool_timeout_sec = 30
## subagents
Sub-agents are orchestrated helper workflows you can trigger with slash commands (for example `/plan`, `/solve`, `/code`). Each entry under `[[subagents.commands]]` defines the slash command name, whether spawned agents run in read-only mode, which `agents` to launch, and extra guidance for both the orchestrator (Code) and the individual agents.
Sub-agents are orchestrated helper workflows you can trigger with slash commands (for example `/plan`, `/solve`, `/code`). Each entry under `[[subagents.commands]]` defines the slash command name, whether spawned agents run in read-only mode, which `agents` to launch, and extra guidance for both the orchestrator (Dev) and the individual agents.
By default (when no `[[agents]]` are configured) Code advertises these model slugs for multi-agent runs: `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `gemini-3.1-pro`, `claude-sonnet-4.6`, `gemini-3.5-flash`, `claude-haiku-4.5`, and `qwen-3-coder`. The cloud counterpart, `cloud-gpt-5.1-codex-max`, only appears when `CODE_ENABLE_CLOUD_AGENT_MODEL=1` is set. (The Gemini built-ins are Antigravity-backed; `gemini` resolves to `gemini-3.5-flash`.) You can override the list by defining `[[agents]]` entries or by specifying `agents = [ … ]` on a given `[[subagents.commands]]` entry.
By default (when no `[[agents]]` are configured) Dev advertises these model slugs for multi-agent runs: `code-gpt-5.5`, `code-gpt-5.4`, `code-gpt-5.4-mini`, `claude-opus-4.8`, `gemini-3.1-pro`, `claude-sonnet-4.6`, `gemini-3.5-flash`, `claude-haiku-4.5`, and `qwen-3-coder`. The cloud counterpart, `cloud-gpt-5.1-codex-max`, only appears when `CODE_ENABLE_CLOUD_AGENT_MODEL=1` is set. (The Gemini built-ins are Antigravity-backed; `gemini` resolves to `gemini-3.5-flash`.) You can override the list by defining `[[agents]]` entries or by specifying `agents = [ … ]` on a given `[[subagents.commands]]` entry.
```toml
[[subagents.commands]]
@@ -492,7 +490,7 @@ orchestrator-instructions = "Coordinate a context sweep before coding. Ask each
agent-instructions = "Summarize the repository areas most relevant to the user's request. List file paths, rationale, and suggested follow-up scripts to run. Keep the reply under 2,000 tokens."
```
With the example above you can run `/context` inside the TUI to create a summary cell that the main `/code` turn can reference later. Because `context-collector` is an ordinary agent, any command-line static analysis utilities it invokes (such as your blast radius tool) should be described in the `agent-instructions` so the orchestrator launches the right workflow. You can also customise the built-in commands by providing an entry with the same `name` (`plan`, `solve`, or `code`) and pointing their `agents` list at your long-context helper.
With the example above you can run `/context` inside the TUI to create a summary cell that the main `/code` turn can reference later. Because `context-collector` is an ordinary agent, any command-line static analysis utilities it invokes (such as your blast radius tool) should be described in the `agent-instructions` so the orchestrator launches the right workflow. You can also customise the built-in commands by providing an entry with the same `name` (`plan`, `solve`, or `dev`) and pointing their `agents` list at your long-context helper.
## validation
@@ -527,7 +525,7 @@ Functional checks stay enabled by default to catch regressions in the touched
code, while stylistic linters default to off so teams can opt in when they want
formatting feedback.
With functional checks enabled, Code automatically detects the languages
With functional checks enabled, Dev automatically detects the languages
affected by a patch and schedules the appropriate tools:
- `cargo-check` for Rust workspaces (scoped to touched manifests)
@@ -540,7 +538,7 @@ affected by a patch and schedules the appropriate tools:
Each entry under `[validation.tools]` can be toggled to disable a specific tool
or to opt particular checks back in after disabling the entire group.
When enabled, Code can also run `actionlint` against modified workflows. This
When enabled, Dev can also run `actionlint` against modified workflows. This
is configured under `[github]`:
```toml
@@ -552,13 +550,13 @@ actionlint_path = "/usr/local/bin/actionlint"
## disable_response_storage
By default, Code disables server-side Responses storage so Zero Data Retention (ZDR) accounts can run without an extra config change:
By default, Dev disables server-side Responses storage so Zero Data Retention (ZDR) accounts can run without an extra config change:
```toml
disable_response_storage = true
```
Set this to `false` only if you explicitly want Code to request stored Responses for providers that support them.
Set this to `false` only if you explicitly want Dev to request stored Responses for providers that support them.
### Managing MCP servers from CLI (experimental)
@@ -566,29 +564,29 @@ You can also manage these entries from the CLI:
```shell
# Add a server (env can be repeated; `--` separates the launcher command)
code mcp add docs -- docs-server --port 4000
dev mcp add docs -- docs-server --port 4000
# List configured servers (pretty table or JSON)
code mcp list
code mcp list --json
dev mcp list
dev mcp list --json
# Show one server (table or JSON)
code mcp get docs
code mcp get docs --json
dev mcp get docs
dev mcp get docs --json
# Remove a server
code mcp remove docs
dev mcp remove docs
# Log in to a streamable HTTP server that supports oauth
code mcp login SERVER_NAME
dev mcp login SERVER_NAME
# Log out from a streamable HTTP server that supports oauth
code mcp logout SERVER_NAME
dev mcp logout SERVER_NAME
```
## shell_environment_policy
Code spawns subprocesses (e.g. when executing a `local_shell` tool-call suggested by the assistant). By default it now passes **your full environment** to those subprocesses. You can tune this behavior via the **`shell_environment_policy`** block in `config.toml`:
Dev spawns subprocesses (e.g. when executing a `local_shell` tool-call suggested by the assistant). By default it now passes **your full environment** to those subprocesses. You can tune this behavior via the **`shell_environment_policy`** block in `config.toml`:
```toml
[shell_environment_policy]
@@ -607,7 +605,7 @@ include_only = ["PATH", "HOME"]
| Field | Type | Default | Description |
| ------------------------- | -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `inherit` | string | `all` | Starting template for the environment:<br>`all` (clone full parent env), `core` (`HOME`, `PATH`, `USER`, …), or `none` (start empty). |
| `ignore_default_excludes` | boolean | `true` | When `false`, Code removes any var whose **name** contains `KEY`, `SECRET`, or `TOKEN` (case-insensitive) before other rules run; defaults to `true` so this filter is disabled by default. |
| `ignore_default_excludes` | boolean | `true` | When `false`, Dev removes any var whose **name** contains `KEY`, `SECRET`, or `TOKEN` (case-insensitive) before other rules run; defaults to `true` so this filter is disabled by default. |
| `exclude` | array<string> | `[]` | Case-insensitive glob patterns to drop after the default filter.<br>Examples: `"AWS_*"`, `"AZURE_*"`. |
| `set` | table<string,string> | `{}` | Explicit key/value overrides or additions – always win over inherited values. |
| `include_only` | array<string> | `[]` | If non-empty, a whitelist of patterns; only variables that match _one_ pattern survive the final step. (Generally used with `inherit = "all"`.) |
@@ -630,7 +628,7 @@ Currently, `CODEX_SANDBOX_NETWORK_DISABLED=1` is also added to the environment,
## otel
Code can emit [OpenTelemetry](https://opentelemetry.io/) **log events** that
Dev can emit [OpenTelemetry](https://opentelemetry.io/) **log events** that
describe each run: outbound API requests, streamed responses, user input,
tool-approval decisions, and the result of every tool invocation. Export is
**disabled by default** so local runs remain self-contained. Opt in by adding an
@@ -643,7 +641,7 @@ exporter = "none" # defaults to "none"; set to otlp-http or otlp-grpc t
log_user_prompt = false # defaults to false; redact prompt text unless explicitly enabled
```
Code tags every exported event with `service.name = $ORIGINATOR` (the same
Dev tags every exported event with `service.name = $ORIGINATOR` (the same
value sent in the `originator` header, `code_cli_rs` by default), the CLI
version, and an `env` attribute so downstream collectors can distinguish
dev/staging/prod traffic. Only telemetry produced inside the `code_otel`
@@ -656,7 +654,7 @@ Every event shares a common set of metadata fields: `event.timestamp`,
`conversation.id`, `app.version`, `auth_mode` (when available),
`user.account_id` (when available), `terminal.type`, `model`, and `slug`.
With OTEL enabled Code emits the following event types (in addition to the
With OTEL enabled Dev emits the following event types (in addition to the
metadata above):
- `codex.conversation_starts`
@@ -750,14 +748,14 @@ If the exporter is `none` nothing is written anywhere; otherwise you must run or
own collector. All exporters run on a background batch worker that is flushed on
shutdown.
If you build Code from source the OTEL crate is still behind an `otel` feature
If you build Dev from source the OTEL crate is still behind an `otel` feature
flag; the official prebuilt binaries ship with the feature enabled. When the
feature is disabled the telemetry hooks become no-ops so the CLI continues to
function without the extra dependencies.
## notify
Specify a program that will be executed to get notified about events generated by Code. Note that the program will receive the notification argument as a string of JSON, e.g.:
Specify a program that will be executed to get notified about events generated by Dev. Note that the program will receive the notification argument as a string of JSON, e.g.:
```json
{
@@ -794,9 +792,9 @@ def main() -> int:
case "agent-turn-complete":
assistant_message = notification.get("last-assistant-message")
if assistant_message:
title = f"Code: {assistant_message}"
title = f"Dev: {assistant_message}"
else:
title = "Code: Turn Complete!"
title = "Dev: Turn Complete!"
input_messages = notification.get("input_messages", [])
message = " ".join(input_messages)
title += message
@@ -812,7 +810,7 @@ def main() -> int:
"-message",
message,
"-group",
"code",
"dev",
"-ignoreDnD",
"-activate",
"com.googlecode.iterm2",
@@ -826,18 +824,18 @@ if __name__ == "__main__":
sys.exit(main())
```
To have Code use this script for notifications, you would configure it via `notify` in `~/.code/config.toml` (legacy `~/.codex/config.toml` is still read) using the appropriate path to `notify.py` on your computer:
To have Dev use this script for notifications, you would configure it via `notify` in `~/.code/config.toml` (legacy `~/.codex/config.toml` is still read) using the appropriate path to `notify.py` on your computer:
```toml
notify = ["python3", "/Users/mbolin/.code/notify.py"]
```
> [!NOTE]
> Use `notify` for automation and integrations: Code invokes your external program with a single JSON argument for each event, independent of the TUI. If you only want lightweight desktop notifications while using the TUI, prefer `tui.notifications`, which uses terminal escape codes and requires no external program. You can enable both; `tui.notifications` covers in‑TUI alerts (e.g., approval prompts), while `notify` is best for system‑level hooks or custom notifiers. Currently, `notify` emits only `agent-turn-complete`, whereas `tui.notifications` supports `agent-turn-complete` and `approval-requested` with optional filtering.
> Use `notify` for automation and integrations: Dev invokes your external program with a single JSON argument for each event, independent of the TUI. If you only want lightweight desktop notifications while using the TUI, prefer `tui.notifications`, which uses terminal escape codes and requires no external program. You can enable both; `tui.notifications` covers in‑TUI alerts (e.g., approval prompts), while `notify` is best for system‑level hooks or custom notifiers. Currently, `notify` emits only `agent-turn-complete`, whereas `tui.notifications` supports `agent-turn-complete` and `approval-requested` with optional filtering.
## history
By default, the Code CLI records messages sent to the model in `$CODE_HOME/history.jsonl` (legacy `$CODEX_HOME/history.jsonl` is also read). On UNIX, the file permissions are set to `o600`, so it should only be readable and writable by the owner.
By default, Dev records messages sent to the model in `$CODE_HOME/history.jsonl` (legacy `$CODEX_HOME/history.jsonl` is also read). On UNIX, the file permissions are set to `o600`, so it should only be readable and writable by the owner.
To disable this behavior, configure `[history]` as follows:
@@ -850,7 +848,7 @@ persistence = "none" # "save-all" is the default value
The structured environment context timeline (baseline + deltas + browser
snapshots) is gated behind the `CTX_UI` environment flag. Set `CTX_UI=1`
before launching Code to exercise the preview flow. Outside of this
before launching Dev to exercise the preview flow. Outside of this
developer flag the classic `== System Status ==` payload remains in place.
## file_opener
@@ -867,11 +865,11 @@ Note this is **not** a general editor setting (like `$EDITOR`), as it only accep
- `"cursor"`
- `"none"` to explicitly disable this feature
Currently, `"vscode"` is the default, though Code does not verify VS Code is installed. As such, `file_opener` may default to `"none"` or something else in the future.
Currently, `"vscode"` is the default, though Dev does not verify VS Code is installed. As such, `file_opener` may default to `"none"` or something else in the future.
## hide_agent_reasoning
Code intermittently emits "reasoning" events that show the model's internal "thinking" before it produces a final answer. Some users may find these events distracting, especially in CI logs or minimal terminal output.
Dev intermittently emits "reasoning" events that show the model's internal "thinking" before it produces a final answer. Some users may find these events distracting, especially in CI logs or minimal terminal output.
Setting `hide_agent_reasoning` to `true` suppresses these events in **both** the TUI as well as the headless `exec` sub-command:
@@ -898,7 +896,7 @@ show_raw_agent_reasoning = true # defaults to false
The size of the context window for the model, in tokens.
In general, Code knows the context window for the most common OpenAI models, but if you are using a new model with an old version of the Code CLI, then you can use `model_context_window` to tell Code what value to use to determine how much context is left during a conversation.
In general, Dev knows the context window for the most common OpenAI models, but if you are using a new model with an old version of Dev, then you can use `model_context_window` to tell Dev what value to use to determine how much context is left during a conversation.
## model_max_output_tokens
@@ -938,17 +936,22 @@ notifications = [ "agent-turn-complete", "approval-requested" ]
# Enable desktop notifications for approval requests only
notifications = [ "approval-requested" ]
# Draw into the terminal's alternate screen buffer. Defaults to true. Ctrl+T
# toggles it at runtime and persists the choice. See
# ./tui-alternate-screen.md for why you would turn it off.
alternate_screen = true
```
> [!NOTE]
> Code emits desktop notifications using terminal escape codes. Not all terminals support these (notably, macOS Terminal.app and VS Code's terminal do not support custom notifications. iTerm2, Ghostty and WezTerm do support these notifications).
> Dev emits desktop notifications using terminal escape codes. Not all terminals support these (notably, macOS Terminal.app and VS Code's terminal do not support custom notifications. iTerm2, Ghostty and WezTerm do support these notifications).
> [!NOTE]
> `tui.notifications` is built‑in and limited to the TUI session. For programmatic or cross‑environment notifications—or to integrate with OS‑specific notifiers—use the top-level `notify` option to run an external program that receives event JSON. The two settings are independent and can be used together.
### Auto Drive Observer
Code keeps long-running Auto Drive sessions in check with a lightweight observer thread. Configure its cadence with the top-level `auto_drive_observer_cadence` key (default `5`). After every *n* completed requests the observer reviews the coordinator/CLI transcript, emits telemetry, and—if necessary—suggests a corrected prompt or follow-up guidance. Setting the value to `0` disables the observer entirely.
Dev keeps long-running Auto Drive sessions in check with a lightweight observer thread. Configure its cadence with the top-level `auto_drive_observer_cadence` key (default `5`). After every *n* completed requests the observer reviews the coordinator/CLI transcript, emits telemetry, and—if necessary—suggests a corrected prompt or follow-up guidance. Setting the value to `0` disables the observer entirely.
```toml
# Run the observer after every third Auto Drive request
@@ -1009,9 +1012,9 @@ Hook commands run inside the same sandbox mode as the session and appear in the
When multiple `user.prompt_submit` or `stop` hooks are configured, their model-visible outputs are applied in configuration order. This keeps prompt context and stop continuation prompts deterministic for integrations that depend on lifecycle interception rather than best-effort notification.
The `stop` hook includes `stop_hook_active` in its payload. Code allows at most one stop-driven continuation per turn; if a second stop continuation is requested while one is already active, the request is ignored and a background warning is emitted.
The `stop` hook includes `stop_hook_active` in its payload. Dev allows at most one stop-driven continuation per turn; if a second stop continuation is requested while one is already active, the request is ignored and a background warning is emitted.
In the TUI, the primary surface for a blocked `user.prompt_submit` hook is the hook's own exec cell, which shows the hook exit code and stderr text. Code may also emit a background summary when it can do so without interfering with turn startup.
In the TUI, the primary surface for a blocked `user.prompt_submit` hook is the hook's own exec cell, which shows the hook exit code and stderr text. Dev may also emit a background summary when it can do so without interfering with turn startup.
Example `tool.after` payload:
@@ -1038,7 +1041,7 @@ Example `user.prompt_submit` payload:
"turn_id": "42",
"transcript_path": "/Users/me/.code/sessions/rollout-2026-05-06T12-00-00-0195f3f5-0dcb-7f5c-8dc5-7b4b24f8f0aa.jsonl",
"cwd": "/Users/me/src/my-app",
"model": "gpt-5.1-codex",
"model": "zen5-coder",
"prompt": "please finish this task"
}
```
@@ -1052,7 +1055,7 @@ Example `stop` payload:
"turn_id": "42",
"transcript_path": "/Users/me/.code/sessions/rollout-2026-05-06T12-00-00-0195f3f5-0dcb-7f5c-8dc5-7b4b24f8f0aa.jsonl",
"cwd": "/Users/me/src/my-app",
"model": "gpt-5.1-codex",
"model": "zen5-coder",
"stop_hook_active": false,
"last_assistant_message": "Implementation is complete and tests are green."
}
@@ -1073,14 +1076,14 @@ name = "unit"
run = "cargo test --lib"
```
Project commands appear in the TUI via `/cmd <name>` and run through the standard execution pipeline. During execution Code sets `CODE_PROJECT_COMMAND_NAME`, `CODE_PROJECT_COMMAND_DESCRIPTION` (when provided), and `CODE_SESSION_CWD` so scripts can tailor their behaviour.
Project commands appear in the TUI via `/cmd <name>` and run through the standard execution pipeline. During execution Dev sets `CODE_PROJECT_COMMAND_NAME`, `CODE_PROJECT_COMMAND_DESCRIPTION` (when provided), and `CODE_SESSION_CWD` so scripts can tailor their behaviour.
## Config reference
| Key | Type / Values | Notes |
| --- | --- | --- |
| `model` | string | Model to use (e.g., `gpt-5.1-codex`). |
| `model_provider` | string | Provider id from `model_providers` (default: `openai`). |
| `model` | string | Model to use (e.g., `zen5-coder`). |
| `model_provider` | string | Provider id from `model_providers` (default: `hanzo`). |
| `model_context_window` | number | Context window tokens. |
| `model_max_output_tokens` | number | Max output tokens. |
| `approval_policy` | `untrusted` \| `on-failure` \| `on-request` \| `never` | When to prompt for approval. |
+20 -19
View File
@@ -1,11 +1,11 @@
# Sample configuration
Use this example configuration as a starting point. For an explanation of each field and additional context, see [Configuration](./config.md). Copy the snippet below to `~/.codex/config.toml` and adjust values as needed.
Use this example configuration as a starting point. For an explanation of each field and additional context, see [Configuration](./config.md). Copy the snippet below to `~/.code/config.toml` and adjust values as needed.
```toml
# Codex example configuration (config.toml)
# Hanzo Dev example configuration (config.toml)
#
# This file lists all keys Codex reads from config.toml, their default values,
# This file lists all keys Dev reads from config.toml, their default values,
# and concise explanations. Values here mirror the effective defaults compiled
# into the CLI. Adjust as needed.
#
@@ -18,26 +18,26 @@ Use this example configuration as a starting point. For an explanation of each f
# Core Model Selection
################################################################################
# Primary model used by Codex. Default: "gpt-5.1-codex-max" on all platforms.
model = "gpt-5.1-codex-max"
# Primary model. Defaults follow the provider: "zen5-coder" on "hanzo".
model = "zen5-coder"
# Model used by the /review feature (code reviews). Default: "gpt-5.1-codex-max".
review_model = "gpt-5.1-codex-max"
# Model used by the /review feature (code reviews). Same default as `model`.
review_model = "zen5-coder"
# Provider id selected from [model_providers]. Default: "openai".
model_provider = "openai"
# Provider id selected from [model_providers]. Default: "hanzo".
model_provider = "hanzo"
# Optional manual model metadata. When unset, Codex auto-detects from model.
# Optional manual model metadata. When unset, Dev auto-detects from model.
# Uncomment to force values.
# model_context_window = 128000 # tokens; default: auto for model
# model_auto_compact_token_limit = 0 # disable/override auto; default: model family specific
# tool_output_token_limit = 10000 # tokens stored per tool output; default: 10000 for gpt-5.1-codex-max
# tool_output_token_limit = 10000 # tokens stored per tool output
################################################################################
# Reasoning & Verbosity (Responses API capable models)
################################################################################
# Reasoning effort: minimal | low | medium | high | xhigh (default: medium; xhigh on gpt-5.1-codex-max and gpt-5.2)
# Reasoning effort: minimal | low | medium | high | xhigh (default: medium)
model_reasoning_effort = "medium"
# Reasoning summary: auto | concise | detailed | none (default: auto)
@@ -152,10 +152,10 @@ disable_paste_burst = false
windows_wsl_setup_acknowledged = false
# External notifier program (argv array). When unset: disabled.
# Example: notify = ["notify-send", "Codex"]
# Example: notify = ["notify-send", "Dev"]
# notify = [ ]
# In-product notices (mostly set automatically by Codex).
# In-product notices (mostly set automatically by Dev).
[notice]
# hide_full_access_warning = true
# hide_rate_limit_model_nudge = true
@@ -173,7 +173,7 @@ chatgpt_base_url = "https://chatgpt.com/backend-api/"
# Restrict ChatGPT login to a specific workspace id. Default: unset.
# forced_chatgpt_workspace_id = ""
# Force login mechanism when Codex would normally auto-select. Default: unset.
# Force login mechanism when Dev would normally auto-select. Default: unset.
# Allowed values: chatgpt | api
# forced_login_method = "chatgpt"
@@ -255,6 +255,7 @@ experimental_use_freeform_apply_patch = false
################################################################################
# Built-ins include:
# - hanzo (default; Responses API at api.hanzo.ai/v1, bearer HANZO_USER_KEY)
# - openai (Responses API; requires login or OPENAI_API_KEY via auth flow)
# - oss (Chat Completions API; defaults to http://localhost:11434/v1)
@@ -298,8 +299,8 @@ experimental_use_freeform_apply_patch = false
[profiles]
# [profiles.default]
# model = "gpt-5.1-codex-max"
# model_provider = "openai"
# model = "zen5-coder"
# model_provider = "hanzo"
# approval_policy = "on-request"
# sandbox_mode = "read-only"
# model_reasoning_effort = "medium"
@@ -357,6 +358,6 @@ exporter = "none"
# [otel.exporter."otlp-http".tls]
# ca-certificate = "certs/otel-ca.pem"
# client-certificate = "/etc/codex/certs/client.pem"
# client-private-key = "/etc/codex/certs/client-key.pem"
# client-certificate = "/etc/code/certs/client.pem"
# client-private-key = "/etc/code/certs/client-key.pem"
```
+20 -20
View File
@@ -1,24 +1,24 @@
# Non-interactive mode
Use Every Code in non-interactive mode to automate common workflows.
Use Hanzo Dev in non-interactive mode to automate common workflows.
```shell
code exec "count the total number of lines of code in this project"
dev exec "count the total number of lines of code in this project"
```
In non-interactive mode, Code does not ask for command or edit approvals. By default it runs in `read-only` mode, so it cannot edit files or run commands that require network access.
In non-interactive mode, Dev does not ask for command or edit approvals. By default it runs in `read-only` mode, so it cannot edit files or run commands that require network access.
Use `code exec --full-auto` to allow file edits. Use `code exec --sandbox danger-full-access` to allow edits and networked commands.
Use `dev exec --full-auto` to allow file edits. Use `dev exec --sandbox danger-full-access` to allow edits and networked commands.
### Default output mode
By default, Code streams its activity to stderr and only writes the final message from the agent to stdout. This makes it easier to pipe `code exec` into another tool without extra filtering.
By default, Dev streams its activity to stderr and only writes the final message from the agent to stdout. This makes it easier to pipe `dev exec` into another tool without extra filtering.
To write the output of `code exec` to a file, in addition to using a shell redirect like `>`, there is also a dedicated flag to specify an output file: `-o`/`--output-last-message`.
To write the output of `dev exec` to a file, in addition to using a shell redirect like `>`, there is also a dedicated flag to specify an output file: `-o`/`--output-last-message`.
### JSON output mode
`code exec` supports a `--json` mode that streams events to stdout as JSON Lines (JSONL) while the agent runs.
`dev exec` supports a `--json` mode that streams events to stdout as JSON Lines (JSONL) while the agent runs.
Supported event types:
@@ -46,7 +46,7 @@ Sample output:
{"type":"turn.started"}
{"type":"item.completed","item":{"id":"item_0","item_type":"reasoning","text":"**Searching for README files**"}}
{"type":"item.started","item":{"id":"item_1","item_type":"command_execution","command":"bash -lc ls","aggregated_output":"","status":"in_progress"}}
{"type":"item.completed","item":{"id":"item_1","item_type":"command_execution","command":"bash -lc ls","aggregated_output":"AGENTS.md\nCHANGELOG.md\nREADME.md\ncode-rs\ncodex-rs\ncodex-cli\ndocs\nscripts\nsdk\n","exit_code":0,"status":"completed"}}
{"type":"item.completed","item":{"id":"item_1","item_type":"command_execution","command":"bash -lc ls","aggregated_output":"AGENTS.md\nCHANGELOG.md\nREADME.md\ncode-rs\ndocs\nscripts\nsdk\n","exit_code":0,"status":"completed"}}
{"type":"item.completed","item":{"id":"item_2","item_type":"reasoning","text":"**Checking repository root for README**"}}
{"type":"item.completed","item":{"id":"item_3","item_type":"assistant_message","text":"Yep — there’s a `README.md` in the repository root."}}
{"type":"turn.completed","usage":{"input_tokens":24763,"cached_input_tokens":24448,"output_tokens":122}}
@@ -73,40 +73,40 @@ Sample schema:
```
```shell
code exec "Extract details of the project" --output-schema ~/schema.json
dev exec "Extract details of the project" --output-schema ~/schema.json
...
{"project_name":"Every Code CLI","programming_languages":["Rust","TypeScript","Shell"]}
{"project_name":"Hanzo Dev","programming_languages":["Rust","TypeScript","Shell"]}
```
Combine `--output-schema` with `-o` to only print the final JSON output. You can also pass a file path to `-o` to save the JSON output to a file.
### Git repository requirement
Code requires a Git repository to avoid destructive changes. To disable this check, use `code exec --skip-git-repo-check`.
Dev requires a Git repository to avoid destructive changes. To disable this check, use `dev exec --skip-git-repo-check`.
### Resuming non-interactive sessions
Resume a previous non-interactive session with `code exec resume <SESSION_ID>` or `code exec resume --last`. This preserves conversation context so you can ask follow-up questions or give new tasks to the agent.
Resume a previous non-interactive session with `dev exec resume <SESSION_ID>` or `dev exec resume --last`. This preserves conversation context so you can ask follow-up questions or give new tasks to the agent.
```shell
code exec "Review the change, look for use-after-free issues"
code exec resume --last "Fix use-after-free issues"
dev exec "Review the change, look for use-after-free issues"
dev exec resume --last "Fix use-after-free issues"
```
Only the conversation context is preserved; you must still provide flags to customize Code behavior.
Only the conversation context is preserved; you must still provide flags to customize Dev behavior.
```shell
code exec --model gpt-5.1-codex --json "Review the change, look for use-after-free issues"
code exec --model gpt-5.1 --json resume --last "Fix use-after-free issues"
dev exec --model zen5-coder --json "Review the change, look for use-after-free issues"
dev exec --model enso --json resume --last "Fix use-after-free issues"
```
## Authentication
By default, `code exec` uses the same authentication method as the TUI and VSCode extension. You can override the API key by setting the `CODEX_API_KEY` environment variable.
By default, `dev exec` uses the same authentication as the TUI. On the `openai` provider you can override the API key by setting the `CODEX_API_KEY` environment variable.
```shell
CODEX_API_KEY=your-api-key-here code exec "Fix merge conflict"
CODEX_API_KEY=your-api-key-here dev exec "Fix merge conflict"
```
NOTE: `CODEX_API_KEY` is only supported in `code exec`.
NOTE: `CODEX_API_KEY` is only supported in `dev exec`.
-74
View File
@@ -1,74 +0,0 @@
# Execution policy
Every Code can enforce your own rules-based execution policy before it runs shell commands. Policies live in Starlark `.codexpolicy` files under `~/.code/policy` (Code still reads `~/.codex/policy` for backward compatibility).
## How to create and edit rules
### TUI interactions
Codex CLI will present the option to whitelist commands when a command causes a prompt.
<img width="513" height="168" alt="Screenshot 2025-12-04 at 9 23 54 AM" src="https://github.com/user-attachments/assets/4c8ee8ea-3101-4a81-bb13-3f4a9aa02502" />
Whitelisted commands will no longer require your permission to run in current and subsequent sessions.
Under the hood, when you approve and whitelist a command, codex will edit `~/.codex/rules/default.rules`.
### Editing `.rules` files
1. Create a policy directory: `mkdir -p ~/.code/policy`.
2. Add one or more `.codexpolicy` files in that folder. Code automatically loads every `.codexpolicy` file in there on startup.
3. Write `prefix_rule` entries to describe the commands you want to allow, prompt, or block:
```starlark
prefix_rule(
pattern = ["git", ["push", "fetch"]],
decision = "prompt", # allow | prompt | forbidden
match = [["git", "push", "origin", "main"]], # examples that must match
not_match = [["git", "status"]], # examples that must not match
)
```
- `pattern` is a list of shell tokens, evaluated from left to right; wrap tokens in a nested list to express alternatives (for example, match both `push` and `fetch`).
- `decision` sets the severity; Code picks the strictest decision when multiple rules match (forbidden > prompt > allow).
- `match` and `not_match` act as optional unit tests. Code validates them when it loads your policy, so you get feedback if an example has unexpected behavior.
In this example rule, if Code wants to run commands with the prefix `git push` or `git fetch`, it will first ask for user approval.
## Preview decisions
Use the `code execpolicy check` subcommand to preview decisions before you save a rule (see the [`codex-execpolicy` README](../code-rs/execpolicy/README.md) for syntax details):
```shell
code execpolicy check --policy ~/.code/policy/default.codexpolicy git push origin main
```
Pass multiple `--policy` flags to test how several files combine, and use `--pretty` for formatted JSON output. See the [`code-rs/execpolicy` README](../code-rs/execpolicy/README.md) for a more detailed walkthrough of the available syntax.
Example output when a rule matches:
```json
{
"matchedRules": [
{
"prefixRuleMatch": {
"matchedPrefix": ["git", "push"],
"decision": "prompt"
}
}
],
"decision": "prompt"
}
```
When no rules match, `matchedRules` is an empty array and `decision` is omitted.
```json
{
"matchedRules": []
}
```
## Status
`execpolicy` commands are still in preview. The API may have breaking changes in the future.
+3 -4
View File
@@ -1,8 +1,7 @@
# Exit and shutdown flow (tui)
This document describes how exit, shutdown, and interruption work in the Rust TUI (`codex-rs/tui`).
It is intended for Codex developers and Codex itself when reasoning about future exit/shutdown
changes.
This document describes how exit, shutdown, and interruption work in the Rust TUI (`code-rs/tui`).
It is intended for anyone reasoning about future exit/shutdown changes.
This doc replaces earlier separate history and design notes. High-level history is summarized
below; full details are captured in PR #8936.
@@ -91,6 +90,6 @@ At a minimum, we want coverage for:
## History (high level)
Codex has historically mixed "exit immediately" and "shutdown-first" across quit gestures, largely
The TUI has historically mixed "exit immediately" and "shutdown-first" across quit gestures, largely
due to incremental changes and regressions in state tracking. This doc reflects the current
unified, shutdown-first approach. See PR #8936 for the detailed history and rationale.
+12 -12
View File
@@ -1,28 +1,28 @@
## FAQ
### OpenAI released a model called Codex in 2021 - is this related?
Only by name. The 2021 Codex model was deprecated in March 2023. Every Code is a community fork of the `openai/codex` CLI and continues to evolve separately.
### Which models are supported?
We recommend the built-in Code presets that wrap GPT-5.4 (for example `code-gpt-5.4`). The default reasoning level is medium, and you can upgrade to high for complex tasks with `/model`.
The default is `zen5-coder`. The built-in presets also cover `zen5`, `zen5-pro`,
`zen5-flash`, `zen5-mini`, and the `enso` family. Pick one with `/model` in the
TUI or `--model` on the command line; the default reasoning level is medium.
You can also use older models by using API-based auth and launching Code with the `--model` flag.
The gateway is the authority on the catalog — there is no allowlist in the
client — so `curl https://catalog.hanzo.ai/v1/models` lists everything you can
pass to `--model`.
### Why does `o3` or `o4-mini` not work for me?
It's possible that your [API account needs to be verified](https://help.openai.com/en/articles/10910291-api-organization-verification) in order to start streaming responses and seeing chain of thought summaries from the API. If you're still running into issues, please let us know!
### How do I stop Code from editing my files?
### How do I stop Dev from editing my files?
By default, Code can modify files in your current working directory (Auto mode). To prevent edits, run `code` in read-only mode with the CLI flag `--sandbox read-only`. Alternatively, you can change the approval level mid-conversation with `/approvals`.
By default, Dev can modify files in your current working directory (Auto mode). To prevent edits, run `dev` in read-only mode with the CLI flag `--sandbox read-only`. Alternatively, you can change the approval level mid-conversation with `/approvals`.
### Does it work on Windows?
Running Code directly on Windows may work, but is not officially supported. We recommend using [Windows Subsystem for Linux (WSL2)](https://learn.microsoft.com/en-us/windows/wsl/install).
Running Dev directly on Windows may work, but is not officially supported. We recommend using [Windows Subsystem for Linux (WSL2)](https://learn.microsoft.com/en-us/windows/wsl/install).
### Why can't Code find my agents on Windows?
### Why can't Dev find my agents on Windows?
On Windows, agent discovery can be affected by PATH configuration and file extensions. If you see errors like `Agent 'xyz' could not be found`, try these solutions:
@@ -74,6 +74,6 @@ If npm's directory isn't in your PATH, you can either:
**4. Check file extensions:**
On Windows, Code looks for executables with these extensions: `.exe`, `.cmd`, `.bat`, `.com`. Ensure your agent command includes the correct extension when using absolute paths.
On Windows, Dev looks for executables with these extensions: `.exe`, `.cmd`, `.bat`, `.com`. Ensure your agent command includes the correct extension when using absolute paths.
**Related:** See the [Agent Configuration Guide](https://github.com/hanzoai/dev/blob/main/code-rs/config.md#agents) for more details.
**Related:** See [agents](./config.md#agents) in the configuration reference.
+24 -24
View File
@@ -1,28 +1,28 @@
# Getting started with Codex CLI
# Getting started
### CLI usage
| Command | Purpose | Example |
| ---------------- | ---------------------------------- | ----------------------------- |
| `code` | Interactive TUI | `code` |
| `code "..."` | Initial prompt for interactive TUI | `code "fix lint errors"` |
| `code exec "..."` | Non-interactive "automation mode" | `code exec "explain utils.ts"` |
| `dev` | Interactive TUI | `dev` |
| `dev "..."` | Initial prompt for interactive TUI | `dev "fix lint errors"` |
| `dev exec "..."` | Non-interactive "automation mode" | `dev exec "explain utils.ts"` |
Key flags: `--model/-m`, `--ask-for-approval/-a`.
### Running with a prompt as input
You can also run the Code CLI with a prompt as input:
You can also run Dev with a prompt as input:
```shell
code "explain this codebase to me"
dev "explain this codebase to me"
```
```shell
code --full-auto "create the fanciest todo-list app"
dev --full-auto "create the fanciest todo-list app"
```
That's it - Code will scaffold a file, run it inside a sandbox, install any
That's it - Dev will scaffold a file, run it inside a sandbox, install any
missing dependencies, and show you the live result. Approve the changes and
they'll be committed to your working directory.
@@ -32,19 +32,19 @@ Below are a few bite-size examples you can copy-paste. Replace the text in quote
| ✨ | What you type | What happens |
| --- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| 1 | `code "Refactor the Dashboard component to React Hooks"` | Code rewrites the class component, runs `npm test`, and shows the diff. |
| 2 | `code "Generate SQL migrations for adding a users table"` | Infers your ORM, creates migration files, and runs them in a sandboxed DB. |
| 3 | `code "Write unit tests for utils/date.ts"` | Generates tests, executes them, and iterates until they pass. |
| 4 | `code "Bulk-rename *.jpeg -> *.jpg with git mv"` | Safely renames files and updates imports/usages. |
| 5 | `code "Explain what this regex does: ^(?=.*[A-Z]).{8,}$"` | Outputs a step-by-step human explanation. |
| 6 | `code "Carefully review this repo, and propose 3 high impact well-scoped PRs"` | Suggests impactful PRs in the current codebase. |
| 7 | `code "Look for vulnerabilities and create a security review report"` | Finds and explains security bugs. |
| 1 | `dev "Refactor the Dashboard component to React Hooks"` | Dev rewrites the class component, runs `npm test`, and shows the diff. |
| 2 | `dev "Generate SQL migrations for adding a users table"` | Infers your ORM, creates migration files, and runs them in a sandboxed DB. |
| 3 | `dev "Write unit tests for utils/date.ts"` | Generates tests, executes them, and iterates until they pass. |
| 4 | `dev "Bulk-rename *.jpeg -> *.jpg with git mv"` | Safely renames files and updates imports/usages. |
| 5 | `dev "Explain what this regex does: ^(?=.*[A-Z]).{8,}$"` | Outputs a step-by-step human explanation. |
| 6 | `dev "Carefully review this repo, and propose 3 high impact well-scoped PRs"` | Suggests impactful PRs in the current codebase. |
| 7 | `dev "Look for vulnerabilities and create a security review report"` | Finds and explains security bugs. |
### Memory with AGENTS.md
You can give Every Code extra instructions and guidance using `AGENTS.md` files. Code looks for `AGENTS.md` files in the following places, and merges them top-down:
You can give Dev extra instructions and guidance using `AGENTS.md` files. Dev looks for `AGENTS.md` files in the following places, and merges them top-down:
1. `~/.code/AGENTS.md` - personal global guidance (Code will also read a legacy `~/.codex/AGENTS.md` if present)
1. `~/.code/AGENTS.md` - personal global guidance (a legacy `~/.codex/AGENTS.md` is also read if present)
2. `AGENTS.md` at repo root - shared project notes
3. `AGENTS.md` in the current working directory - sub-folder/feature specifics
@@ -61,13 +61,13 @@ Typing `@` triggers a fuzzy-filename search over the workspace root. Use up/down
Paste images directly into the composer (Ctrl+V / Cmd+V) to attach them to your prompt. You can also attach files via the CLI using `-i/--image` (comma‑separated):
```bash
code -i screenshot.png "Explain this error"
code --image img1.png,img2.jpg "Summarize these diagrams"
dev -i screenshot.png "Explain this error"
dev --image img1.png,img2.jpg "Summarize these diagrams"
```
#### Esc–Esc to edit a previous message
When the chat composer is empty, press Esc to prime “backtrack” mode. Press Esc again to open a transcript preview highlighting the last user message; press Esc repeatedly to step to older user messages. Press Enter to confirm and Code will fork the conversation from that point, trim the visible transcript accordingly, and pre‑fill the composer with the selected user message so you can edit and resubmit it.
When the chat composer is empty, press Esc to prime “backtrack” mode. Press Esc again to open a transcript preview highlighting the last user message; press Esc repeatedly to step to older user messages. Press Enter to confirm and Dev will fork the conversation from that point, trim the visible transcript accordingly, and pre‑fill the composer with the selected user message so you can edit and resubmit it.
In the transcript preview, the footer shows an `Esc edit prev` hint while editing is active.
@@ -76,11 +76,11 @@ In the transcript preview, the footer shows an `Esc edit prev` hint while editin
Generate shell completion scripts via:
```shell
code completion bash
code completion zsh
code completion fish
dev completion bash
dev completion zsh
dev completion fish
```
#### `--cd`/`-C` flag
Sometimes it is not convenient to `cd` to the directory you want Code to use as the "working root" before running. Fortunately, `code` supports a `--cd` option so you can specify whatever folder you want. You can confirm that Code is honoring `--cd` by double-checking the **workdir** it reports in the TUI at the start of a new session.
Sometimes it is not convenient to `cd` to the directory you want Dev to use as the "working root" before running. Fortunately, `dev` supports a `--cd` option so you can specify whatever folder you want. You can confirm that Dev is honoring `--cd` by double-checking the **workdir** it reports in the TUI at the start of a new session.
+10 -20
View File
@@ -1,30 +1,20 @@
Homebrew (macOS)
This repository now includes a helper script to generate a Homebrew formula
from the latest GitHub release artifacts. Publishing to Homebrew requires a
tap repository (for example, `hanzoai/homebrew-tap`). Once a tap exists,
you can generate and publish the formula like so:
`scripts/generate-homebrew-formula.sh` generates a Homebrew formula from the
latest GitHub release artifacts. It writes `Formula/hanzo-dev.rb` in the repo
root; the release workflow copies that into the `hanzoai/homebrew-tap` tap.
1) Generate the formula for the latest version:
```
scripts/generate-homebrew-formula.sh
```
2) Copy the generated `Code.rb` into your tap repo under `Formula/Code.rb`
and update the `url`/`sha256` if needed.
3) Users can then install with:
Users install with:
```
brew tap hanzoai/tap
brew install code
brew install hanzo-dev
```
Notes
- The formula expects release assets named like:
- `code-aarch64-apple-darwin.tar.gz`
- `code-x86_64-apple-darwin.tar.gz`
- The CLI is installed as `code` and `coder` shims for compatibility.
- The formula expects release assets named `dev-<target-triple>.tar.gz`, e.g.
`dev-aarch64-apple-darwin.tar.gz` and `dev-x86_64-unknown-linux-musl.tar.gz`.
- The CLI is installed as `dev`. The formula deliberately installs no other
shim, so it cannot collide with `hanzo.rb` (the Hanzo CLI, a different
program).
+5 -4
View File
@@ -1,6 +1,6 @@
# Every Code Documentation
# Hanzo Dev Documentation
Use these docs to install, configure, and operate Every Code (Code).
Use these docs to install, configure, and operate Hanzo Dev.
## Start Here
- [Getting started](getting-started.md)
@@ -8,19 +8,20 @@ Use these docs to install, configure, and operate Every Code (Code).
- [Authentication](authentication.md)
- [FAQ](faq.md)
## Using Code
## Using Dev
- [Executing commands](exec.md)
- [Execution policy](execpolicy.md)
- [Slash commands](slash-commands.md)
- [Auto Drive](auto-drive.md)
- [Agents & Subagents](agents.md)
- [Settings overlay](settings.md)
- [Prompts](prompts.md)
- [Skills](skills.md)
- [Advanced usage](advanced.md)
- [Zed integration](integration-zed.md)
## Configuration & Security
- [Configuration](config.md)
- [Sample configuration](example-config.md)
- [Sandboxing overview](sandbox.md)
- [Platform sandboxing](platform-sandboxing.md)
- [Windows sandbox security](platform-sandboxing.md#windows)
+3 -3
View File
@@ -10,14 +10,14 @@
### DotSlash
GitHub Releases also contain a [DotSlash](https://dotslash-cli.com/) shim named `code`. Checking the DotSlash file into your repo pins contributors to the same binary across platforms.
GitHub Releases also contain a [DotSlash](https://dotslash-cli.com/) shim named `dev`. Checking the DotSlash file into your repo pins contributors to the same binary across platforms.
### Build from source
```bash
# Clone the repository and navigate to the workspace root.
git clone https://github.com/hanzoai/dev.git
cd code
cd dev
# Install the Rust toolchain, if necessary.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
@@ -27,7 +27,7 @@ source "$HOME/.cargo/env"
./build-fast.sh
# Launch the TUI with a sample prompt.
./target/debug/code -- "explain this codebase to me"
./target/debug/dev -- "explain this codebase to me"
```
> [!NOTE]
+12 -13
View File
@@ -1,11 +1,11 @@
# Zed Integration
To point Zed at Code's ACP server, add this block to `settings.json`:
To point Zed at Dev's ACP server, add this block to `settings.json`:
```jsonc
{
"agent_servers": {
"Code": {
"Dev": {
"command": "npx",
"args": ["-y", "@hanzo/dev", "acp"]
}
@@ -17,16 +17,15 @@ Adjust the `command` or `args` only if you pin a different version or use a glob
## Zed prerequisites
- Zed Stable `0.201.5` (released August 27, 2025) or newer adds ACP support with the Agent Panel. Update via `Zed → Check for Updates` before wiring Code in. Zed’s docs call out ACP as the mechanism powering Gemini CLI and other external agents.
- External agents live inside the Agent Panel (`cmd-?`). Use the `+` button to start a new thread and pick `Code` from the external agent list. Zed runs our CLI as a subprocess over JSON‑RPC, so all prompts and diff previews stay local.
- Zed Stable `0.201.5` (released August 27, 2025) or newer adds ACP support with the Agent Panel. Update via `Zed → Check for Updates` before wiring Dev in. Zed’s docs call out ACP as the mechanism powering Gemini CLI and other external agents.
- External agents live inside the Agent Panel (`cmd-?`). Use the `+` button to start a new thread and pick `Dev` from the external agent list. Zed runs our CLI as a subprocess over JSON‑RPC, so all prompts and diff previews stay local.
- Zed installs dependencies per entry automatically. If you keep `command = "npx"`, Zed will download the published `@hanzo/dev` package the first time you trigger the integration.
## How Code implements ACP
## How Dev implements ACP
- The Rust MCP server exposes ACP tools: `session/new`, `session/prompt`, and fast interrupts via `session/cancel`. These are backed by the same conversation manager that powers the TUI, so approvals, confirm guards, and sandbox policies remain intact.
- Streaming `session/update` notifications bridge Codex events into Zed. You get Answer/Reasoning updates, shell command progress, approvals, and apply_patch diffs in the Zed UI without losing terminal parity.
- MCP configuration stays centralized in `CODEX_HOME/config.toml`. Use `[experimental_client_tools]` to delegate file read/write and permission requests back to Zed when you want its UI to handle approvals.
- MCP configuration stays centralized in `CODEX_HOME/config.toml`. Use `[experimental_client_tools]` to delegate file read/write and permission requests back to Zed when you want its UI to handle approvals. A minimal setup looks like:
- Streaming `session/update` notifications bridge Dev events into Zed. You get Answer/Reasoning updates, shell command progress, approvals, and apply_patch diffs in the Zed UI without losing terminal parity.
- MCP configuration stays centralized in `$CODE_HOME/config.toml`. Use `[experimental_client_tools]` to delegate file read/write and permission requests back to Zed when you want its UI to handle approvals. A minimal setup looks like:
```toml
[experimental_client_tools]
@@ -35,12 +34,12 @@ read_text_file = { mcp_server = "zed", tool_name = "readTextFile" }
write_text_file = { mcp_server = "zed", tool_name = "writeTextFile" }
```
Zed wires these tools automatically when you add the Code agent, so the identifiers above match the defaults.
- The CLI entry point (`npx @hanzo/dev acp`) is a thin wrapper over the Rust binary (`cargo run -p code-mcp-server -- --stdio`) that ships alongside the rest of Code. Build-from-source workflows plug in by swapping `command` for an absolute path to that binary.
Zed wires these tools automatically when you add the Dev agent, so the identifiers above match the defaults.
- The CLI entry point (`npx @hanzo/dev acp`) is a thin wrapper over the Rust binary (`cargo run -p code-mcp-server -- --stdio`) that ships alongside the rest of Dev. Build-from-source workflows plug in by swapping `command` for an absolute path to that binary.
## Tips and troubleshooting
- Need to inspect the handshake? Run Zed’s `dev: open acp logs` command from the Command Palette; the log shows JSON‑RPC requests and Codex replies.
- If prompts hang, make sure no other process is bound to the same MCP port and that your `CODEX_HOME` points to the intended config directory. The ACP server inherits all of Code’s sandbox settings, so restrictive policies (e.g., `approval_policy = "never"`) still apply.
- Need to inspect the handshake? Run Zed’s `dev: open acp logs` command from the Command Palette; the log shows JSON‑RPC requests and Dev replies.
- If prompts hang, make sure no other process is bound to the same MCP port and that your `CODE_HOME` points to the intended config directory. The ACP server inherits all of Dev’s sandbox settings, so restrictive policies (e.g., `approval_policy = "never"`) still apply.
- Zed currently skips history restores and checkpoint UI for third-party agents. Stick to the TUI if you rely on those features; ACP support is still evolving upstream.
- After a session starts, the model selector in Zed lists Code’s built-in presets (e.g., `gpt-5-codex`, `gpt-5` high/medium/low). Picking a new preset updates the running Codex session immediately, so you don’t have to restart the agent to change models.
- After a session starts, the model selector in Zed lists Dev’s built-in presets (e.g., `zen5-coder`, `enso`). Picking a new preset updates the running session immediately, so you don’t have to restart the agent to change models.
+3 -3
View File
@@ -1,16 +1,16 @@
### Platform sandboxing details
The mechanism Code uses to enforce sandboxing varies by OS.
The mechanism Dev uses to enforce sandboxing varies by OS.
## macOS 12+
- Uses Apple Seatbelt via `sandbox-exec` with a profile that matches the selected `--sandbox` mode.
## Linux
- Uses Landlock plus seccomp to apply the configured sandbox policy.
- In containerized environments (e.g., Docker) the host must support these APIs. If it does not, configure the container to provide the isolation you need and run Code with `--sandbox danger-full-access` (or `--dangerously-bypass-approvals-and-sandbox`) inside that container instead.
- In containerized environments (e.g., Docker) the host must support these APIs. If it does not, configure the container to provide the isolation you need and run Dev with `--sandbox danger-full-access` (or `--dangerously-bypass-approvals-and-sandbox`) inside that container instead.
## Windows
Code launches commands with a restricted Windows token and an allowlist tied to declared workspace roots. Writes are blocked outside those roots (and `%TEMP%` when workspace-write is requested); common escape vectors like alternate data streams, UNC paths, and device handles are proactively denied. The CLI also inserts stub executables (for example, wrapping `ssh`) ahead of the host `PATH` to intercept risky tools before they escape the sandbox.
Dev launches commands with a restricted Windows token and an allowlist tied to declared workspace roots. Writes are blocked outside those roots (and `%TEMP%` when workspace-write is requested); common escape vectors like alternate data streams, UNC paths, and device handles are proactively denied. The CLI also inserts stub executables (for example, wrapping `ssh`) ahead of the host `PATH` to intercept risky tools before they escape the sandbox.
### Known limitations (smoketests)
Running `python windows-sandbox-rs/sandbox_smoketests.py` with full filesystem and network access currently passes **37/41** cases. The remaining high-value gaps are:
+3 -3
View File
@@ -2,7 +2,7 @@
Save frequently used prompts as Markdown files and reuse them quickly from the slash menu.
- Location: Put files in `$CODE_HOME/prompts/` (defaults to `~/.code/prompts/`; Code also reads legacy `~/.codex/prompts/`).
- Location: Put files in `$CODE_HOME/prompts/` (defaults to `~/.code/prompts/`; Dev also reads legacy `~/.codex/prompts/`).
- File type: Only Markdown files with the `.md` extension are recognized.
- Name: The filename without the `.md` extension becomes the slash entry. For a file named `my-prompt.md`, type `/my-prompt`.
- Content: The file contents are sent as your message when you select the item in the slash popup and press Enter.
@@ -12,9 +12,9 @@ Save frequently used prompts as Markdown files and reuse them quickly from the s
- `$$` is preserved literally
- Quoted args: Wrap a single argument in double quotes to include spaces, e.g. `/review "docs/My File.md"`.
- How to use:
- Start a new session (Code loads custom prompts on session start).
- Start a new session (Dev loads custom prompts on session start).
- In the composer, type `/` to open the slash popup and begin typing your prompt name.
- Use Up/Down to select it. Press Enter to submit its contents, or Tab to autocomplete the name.
- Notes:
- Files with names that collide with built‑in commands (e.g. `/init`) are ignored and won’t appear.
- New or changed files are discovered on session start. If you add a new prompt while Code is running, start a new session to pick it up.
- New or changed files are discovered on session start. If you add a new prompt while Dev is running, start a new session to pick it up.
+16 -20
View File
@@ -2,35 +2,35 @@
### Approval modes
We've chosen a powerful default for how Code works on your computer: `Auto`. In this approval mode, Code can read files, make edits, and run commands in the working directory automatically. However, Code will need your approval to work outside the working directory or access network.
We've chosen a powerful default for how Dev works on your computer: `Auto`. In this approval mode, Dev can read files, make edits, and run commands in the working directory automatically. However, Dev will need your approval to work outside the working directory or access network.
When you just want to chat, or if you want to plan before diving in, you can switch to `Read Only` mode with the `/approvals` command.
If you need Code to read files, make edits, and run commands with network access, without approval, you can use `Full Access`. Exercise caution before doing so.
If you need Dev to read files, make edits, and run commands with network access, without approval, you can use `Full Access`. Exercise caution before doing so.
#### Defaults and recommendations
- Code runs in a sandbox by default with strong guardrails: it prevents editing files outside the workspace and blocks network access unless enabled.
- On launch, Code detects whether the folder is version-controlled and recommends:
- Dev runs in a sandbox by default with strong guardrails: it prevents editing files outside the workspace and blocks network access unless enabled.
- On launch, Dev detects whether the folder is version-controlled and recommends:
- Version-controlled folders: `Auto` (workspace write + on-request approvals)
- Non-version-controlled folders: `Read Only`
- The workspace includes the current directory and temporary directories like `/tmp`. Use the `/status` command to see which directories are in the workspace.
- You can set these explicitly:
- `code --sandbox workspace-write --ask-for-approval on-request`
- `code --sandbox read-only --ask-for-approval on-request`
- `dev --sandbox workspace-write --ask-for-approval on-request`
- `dev --sandbox read-only --ask-for-approval on-request`
### Can I run without ANY approvals?
Yes, you can disable all approval prompts with `--ask-for-approval never`. This option works with all `--sandbox` modes, so you still have full control over Code's level of autonomy. It will make its best attempt with whatever constraints you provide.
Yes, you can disable all approval prompts with `--ask-for-approval never`. This option works with all `--sandbox` modes, so you still have full control over Dev's level of autonomy. It will make its best attempt with whatever constraints you provide.
### Common sandbox + approvals combinations
| Intent | Flags | Effect |
| ---------------------------------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| Safe read-only browsing | `--sandbox read-only --ask-for-approval on-request` | Code can read files and answer questions. Code requires approval to make edits, run commands, or access network. |
| Safe read-only browsing | `--sandbox read-only --ask-for-approval on-request` | Dev can read files and answer questions. Dev requires approval to make edits, run commands, or access network. |
| Read-only non-interactive (CI) | `--sandbox read-only --ask-for-approval never` | Reads only; never escalates |
| Let it edit the repo, ask if risky | `--sandbox workspace-write --ask-for-approval on-request` | Code can read files, make edits, and run commands in the workspace. Code requires approval for actions outside the workspace or for network access. |
| Auto (preset) | `--full-auto` (equivalent to `--sandbox workspace-write` + `--ask-for-approval on-failure`) | Code can read files, make edits, and run commands in the workspace. Code requires approval when a sandboxed command fails or needs escalation. |
| Let it edit the repo, ask if risky | `--sandbox workspace-write --ask-for-approval on-request` | Dev can read files, make edits, and run commands in the workspace. Dev requires approval for actions outside the workspace or for network access. |
| Auto (preset) | `--full-auto` (equivalent to `--sandbox workspace-write` + `--ask-for-approval on-failure`) | Dev can read files, make edits, and run commands in the workspace. Dev requires approval when a sandboxed command fails or needs escalation. |
| YOLO (not recommended) | `--dangerously-bypass-approvals-and-sandbox` (alias: `--yolo`) | No sandbox; no prompts |
> Note: In `workspace-write`, network is disabled by default unless enabled in config (`[sandbox_workspace_write].network_access = true`).
@@ -63,27 +63,23 @@ approval_policy = "never"
sandbox_mode = "read-only"
```
### Experimenting with the Code Sandbox
### Experimenting with the Dev Sandbox
To test to see what happens when a command is run under the sandbox provided by Code, we provide the following subcommands in the CLI:
To see what happens when a command is run under the sandbox Dev provides:
```
# macOS
code sandbox macos [--full-auto] [COMMAND]...
dev debug seatbelt [--full-auto] [COMMAND]...
# Linux
code sandbox linux [--full-auto] [COMMAND]...
# Legacy aliases
code debug seatbelt [--full-auto] [COMMAND]...
code debug landlock [--full-auto] [COMMAND]...
dev debug landlock [--full-auto] [COMMAND]...
```
### Platform sandboxing details
The mechanism Code uses to implement the sandbox policy depends on your OS:
The mechanism Dev uses to implement the sandbox policy depends on your OS:
- **macOS 12+** uses **Apple Seatbelt** and runs commands using `sandbox-exec` with a profile (`-p`) that corresponds to the `--sandbox` that was specified.
- **Linux** uses a combination of Landlock/seccomp APIs to enforce the `sandbox` configuration.
Note that when running Linux in a containerized environment such as Docker, sandboxing may not work if the host/container configuration does not support the necessary Landlock/seccomp APIs. In such cases, we recommend configuring your Docker container so that it provides the sandbox guarantees you are looking for and then running `code` with `--sandbox danger-full-access` (or, more simply, the `--dangerously-bypass-approvals-and-sandbox` flag) within your container.
Note that when running Linux in a containerized environment such as Docker, sandboxing may not work if the host/container configuration does not support the necessary Landlock/seccomp APIs. In such cases, we recommend configuring your Docker container so that it provides the sandbox guarantees you are looking for and then running `dev` with `--sandbox danger-full-access` (or, more simply, the `--dangerously-bypass-approvals-and-sandbox` flag) within your container.
+1 -1
View File
@@ -1,6 +1,6 @@
# TUI Settings Overlay
Full-screen settings panel for Every Code’s TUI. Use it to change models, themes, Auto Drive defaults, agents, notifications, and more without leaving the chat.
Full-screen settings panel for Hanzo Dev’s TUI. Use it to change models, themes, Auto Drive defaults, agents, notifications, and more without leaving the chat.
## Open & navigate
- `/settings` opens the overview; `/settings <section>` jumps directly (section names below). `/auto settings` and `/update` route into their sections.
+12 -12
View File
@@ -2,20 +2,20 @@
> **Warning:** This is an experimental and non-stable feature. If you depend on it, please expect breaking changes over the coming weeks and understand that there is currently no guarantee that this works well. Use at your own risk!
Codex can automatically discover reusable "skills" you keep on disk. A skill is a small bundle with a name, a short description (what it does and when to use it), and an optional body of instructions you can open when needed. Codex injects only the name, description, and file path into the runtime context; the body stays on disk.
Dev can automatically discover reusable "skills" you keep on disk. A skill is a small bundle with a name, a short description (what it does and when to use it), and an optional body of instructions you can open when needed. Dev injects only the name, description, and file path into the runtime context; the body stays on disk.
## Enable skills
Skills are behind the experimental `skills` feature flag and are enabled by default.
- Disable in config (preferred): add the following to `$CODEX_HOME/config.toml` (usually `~/.codex/config.toml`) and restart Codex:
- Disable in config (preferred): add the following to `$CODE_HOME/config.toml` (usually `~/.code/config.toml`) and restart Dev:
```toml
[features]
skills = false
```
- Override for a single run when disabled in config: launch Codex with `codex --enable skills`
- Override for a single run when disabled in config: `dev -c features.skills=true`
## Where skills live
@@ -23,8 +23,8 @@ Skills are behind the experimental `skills` feature flag and are enabled by defa
- Repo: `.agents/skills/**/SKILL.md` from the current working directory up to the repo root.
- Repo (legacy): `.codex/skills/**/SKILL.md` from the current working directory up to the repo root.
- User: `$HOME/.agents/skills/**/SKILL.md`.
- User (legacy): `$CODEX_HOME/skills/**/SKILL.md` (usually `~/.code/skills`; legacy `~/.codex/skills` is still read for compatibility).
- System: bundled skills under `$CODEX_HOME/skills/.system/**/SKILL.md`.
- User (legacy): `$CODE_HOME/skills/**/SKILL.md` (usually `~/.code/skills`; legacy `~/.codex/skills` is still read for compatibility).
- System: bundled skills under `$CODE_HOME/skills/.system/**/SKILL.md`.
- Admin (optional): `/etc/codex/skills/**/SKILL.md`.
- Discovery is recursive and only files named exactly `SKILL.md` count.
- Hidden entries are skipped.
@@ -36,14 +36,14 @@ Skills are behind the experimental `skills` feature flag and are enabled by defa
- YAML frontmatter + body.
- Required:
- `name` (non-empty, ≤100 chars, sanitized to one line)
- `description` (non-empty, ≤500 chars, sanitized to one line)
- `name` (non-empty, ≤64 chars, sanitized to one line)
- `description` (non-empty, ≤1024 chars, sanitized to one line)
- Extra keys are ignored. The body can contain any Markdown; it is not injected into context.
## Loading and rendering
- Loaded once at startup.
- If valid skills exist, Codex appends a runtime-only `## Skills` section after `AGENTS.md`, one bullet per skill: `- <name>: <description> (file: /absolute/path/to/SKILL.md)`.
- If valid skills exist, Dev appends a runtime-only `## Skills` section after `AGENTS.md`, one bullet per skill: `- <name>: <description> (file: /absolute/path/to/SKILL.md)`.
- If no valid skills exist, the section is omitted. On-disk files are never modified.
## Using skills
@@ -57,7 +57,7 @@ Skills are behind the experimental `skills` feature flag and are enabled by defa
## Create a skill
1. Create `~/.codex/skills/<skill-name>/`.
1. Create `~/.code/skills/<skill-name>/`.
2. Add `SKILL.md`:
```
@@ -71,13 +71,13 @@ Skills are behind the experimental `skills` feature flag and are enabled by defa
```
3. Keep `name`/`description` within the limits; avoid newlines in those fields.
4. Restart Codex to load the new skill.
4. Restart Dev to load the new skill.
## Example
```
mkdir -p ~/.codex/skills/pdf-processing
cat <<'SKILL_EXAMPLE' > ~/.codex/skills/pdf-processing/SKILL.md
mkdir -p ~/.code/skills/pdf-processing
cat <<'SKILL_EXAMPLE' > ~/.code/skills/pdf-processing/SKILL.md
---
name: pdf-processing
description: Extract text and tables from PDFs; use when PDFs, forms, or document extraction are mentioned.
+10 -10
View File
@@ -1,6 +1,6 @@
# Slash Commands
The Code CLI supports a set of slash commands you can type at the start of the
Dev supports a set of slash commands you can type at the start of the
composer input. These commands provide quick actions, toggles, or expand into
full prompts. This document lists all built‑in commands and what they do.
@@ -19,21 +19,21 @@ Notes
- `/clear`: clear the terminal and start a new chat.
- `/resume`: resume a past session for this folder.
- `/rename <name>`: rename the current session (shown in the resume list).
- `/quit`: exit Code.
- `/exit`: exit Code.
- `/logout`: log out of Code.
- `/login`: manage Code sign-ins (select, add, or disconnect accounts).
- `/quit`: exit Dev.
- `/exit`: exit Dev.
- `/logout`: log out of Dev.
- `/login`: manage Dev sign-ins (select, add, or disconnect accounts).
- `/settings [section]`: open the settings panel. Optional section argument
jumps directly to `model`, `theme`, `agents`, `skills`, `auto`, `review`,
`validation`, `limits`, `chrome`, `mcp`, or `notifications`.
## Workspace & Git
- `/init`: create an `AGENTS.md` file with instructions for Code.
- `/init`: create an `AGENTS.md` file with instructions for Dev.
- `/diff`: show `git diff` (including untracked files).
- `/copy`: copy the last assistant response as markdown.
- `/undo`: open a snapshot picker so you can restore workspace files to a
previous Code snapshot and optionally rewind the conversation to that point.
previous Dev snapshot and optionally rewind the conversation to that point.
- `/branch [task]`: create a worktree branch and switch to it. If a
task/description is provided, it is used when naming the branch. Must be run
from the repository root (not inside another branch worktree). Set
@@ -42,7 +42,7 @@ Notes
directories are copied automatically.
- `/merge`: merge the current worktree branch back into the default branch and
remove the worktree. Run this from inside the worktree created by `/branch`.
- `/push`: tell Code to commit, push, and monitor workflows with guarded
- `/push`: tell Dev to commit, push, and monitor workflows with guarded
instructions. If no workflows appear right away, wait briefly and check again
before concluding none were triggered. Skips cleanup or GitHub monitoring
steps automatically when the workspace is already clean or required
@@ -51,9 +51,9 @@ Notes
the workspace, a specific commit, compare against another branch, or enter
custom instructions. With a focus argument, skips the picker and uses your
text directly. Configure Auto Resolve and the max re-reviews (defaults to 5)
from `/settings review` when you want Code to rerun fixes and follow-up
from `/settings review` when you want Dev to rerun fixes and follow-up
checks automatically.
- `/cloud`: browse Code Cloud tasks, view details, apply patches, and create
- `/cloud`: browse Dev Cloud tasks, view details, apply patches, and create
new tasks from the TUI.
- `/cmd <name>`: run a project command defined for the current workspace.
+35 -113
View File
@@ -1,130 +1,52 @@
# TUI Alternate Screen and Terminal Multiplexers
# TUI alternate screen and terminal multiplexers
## Overview
## The conflict
This document explains the design decision behind Codex's alternate screen handling, particularly in terminal multiplexers like Zellij. This addresses a fundamental conflict between fullscreen TUI behavior and terminal scrollback history preservation.
The TUI draws into the terminal's **alternate screen buffer**, which gives it the
whole viewport and leaves your scrollback untouched when it exits — the same
thing vim and less do.
## The Problem
The xterm specification says an alternate screen buffer has no scrollback, and
[Zellij](https://github.com/zellij-org/zellij/pull/1032) follows that strictly
and offers no setting to relax it. So inside Zellij the terminal's own scroll
keys do nothing while the TUI is in alternate screen: the scrollback the
multiplexer would show simply does not exist. This is the specification working
as written, not a bug in either program. tmux and screen are laxer and usually
scroll anyway.
### Fullscreen TUI Benefits
## What Hanzo Dev does about it
Codex's TUI uses the terminal's **alternate screen buffer** to provide a clean fullscreen experience. This approach:
**Ctrl+T** toggles between the two buffers at any time.
- Uses the entire viewport without polluting the terminal's scrollback history
- Provides a dedicated environment for the chat interface
- Mirrors the behavior of other terminal applications (vim, tmux, etc.)
Leaving the alternate screen replays the entire transcript into the normal
buffer, so the conversation lands in real terminal scrollback and your
multiplexer can page through it. Returning repaints the fullscreen view.
### The Zellij Conflict
Terminal multiplexers like **Zellij** strictly follow the xterm specification, which defines that alternate screen buffers should **not** have scrollback. This is intentional design, not a bug:
- **Zellij PR:** https://github.com/zellij-org/zellij/pull/1032
- **Rationale:** The xterm spec explicitly states that alternate screen mode disallows scrollback
- **Configurability:** This is not configurable in Zellij—there is no option to enable scrollback in alternate screen mode
When using Codex's TUI in Zellij, users cannot scroll back through the conversation history because:
1. The TUI runs in alternate screen mode (fullscreen)
2. Zellij disables scrollback in alternate screen buffers (per xterm spec)
3. The entire conversation becomes inaccessible via normal terminal scrolling
## The Solution
Codex implements a **pragmatic workaround** with three modes, controlled by `tui.alternate_screen` in `config.toml`:
### 1. `auto` (default)
- **Behavior:** Automatically detect the terminal multiplexer
- **In Zellij:** Disable alternate screen mode (inline mode, preserves scrollback)
- **Elsewhere:** Enable alternate screen mode (fullscreen experience)
- **Rationale:** Provides the best UX in each environment
### 2. `always`
- **Behavior:** Always use alternate screen mode (original behavior)
- **Use case:** Users who prefer fullscreen and don't use Zellij, or who have found a workaround
### 3. `never`
- **Behavior:** Never use alternate screen mode (inline mode)
- **Use case:** Users who always want scrollback history preserved
- **Trade-off:** Pollutes the terminal scrollback with TUI output
## Runtime Override
The `--no-alt-screen` CLI flag can override the config setting at runtime:
```bash
codex --no-alt-screen
```
This runs the TUI in inline mode regardless of the configuration, useful for:
- One-off sessions where scrollback is critical
- Debugging terminal-related issues
- Testing alternate screen behavior
## Implementation Details
### Auto-Detection
The `auto` mode detects Zellij by checking the `ZELLIJ` environment variable:
```rust
let terminal_info = codex_core::terminal::terminal_info();
!matches!(terminal_info.multiplexer, Some(Multiplexer::Zellij { .. }))
```
This detection happens in the helper function `determine_alt_screen_mode()` in `codex-rs/tui/src/lib.rs`.
### Configuration Schema
The `AltScreenMode` enum is defined in `codex-rs/protocol/src/config_types.rs` and serializes to lowercase TOML:
The choice is remembered: each toggle writes `tui.alternate_screen` to
`config.toml`, and that value decides which buffer the next session starts in.
Set it directly to pick a default:
```toml
[tui]
# Options: auto, always, never
alternate_screen = "auto"
alternate_screen = false # start in the normal buffer
```
### Why Not Just Disable Alternate Screen in Zellij Permanently?
## Where this lives
We use `auto` detection instead of always disabling in Zellij because:
| What | Where |
|---|---|
| Toggle behavior | `code-rs/tui/src/app/terminal.rs` `toggle_screen_mode()` |
| Buffer switching | `code-rs/tui/src/tui.rs` `enter_alt_screen_only()` / `leave_alt_screen_only()` |
| Startup buffer | `code-rs/tui/src/app/init.rs` |
| Persisting the choice | `code_core::config::set_tui_alternate_screen()` |
1. Many Zellij users don't care about scrollback and prefer the fullscreen experience
2. Some users may use tmux inside Zellij, creating a chain of multiplexers
3. Provides user choice without requiring manual configuration
## If a crash leaves the terminal wrong
## Related Issues and References
- **Original Issue:** [GitHub #2558](https://github.com/openai/codex/issues/2558) - "No scrollback in Zellij"
- **Implementation PR:** [GitHub #8555](https://github.com/openai/codex/pull/8555)
- **Zellij PR:** https://github.com/zellij-org/zellij/pull/1032 (why scrollback is disabled)
- **xterm Spec:** Alternate screen buffers should not have scrollback
## Future Considerations
### Alternative Approaches Considered
1. **Implement custom scrollback in TUI:** Would require significant architectural changes to buffer and render all historical output
2. **Request Zellij to add a config option:** Not viable—Zellij maintainers explicitly chose this behavior to follow the spec
3. **Disable alternate screen unconditionally:** Would degrade UX for non-Zellij users
### Transcript Pager
Codex's transcript pager (opened with Ctrl+T) provides an alternative way to review conversation history, even in fullscreen mode. However, this is not as seamless as natural scrollback.
## For Developers
When modifying TUI code, remember:
- The `determine_alt_screen_mode()` function encapsulates all the logic
- Configuration is in `config.tui_alternate_screen`
- CLI flag is in `cli.no_alt_screen`
- The behavior is applied via `tui.set_alt_screen_enabled()`
If you encounter issues with terminal state after running Codex, you can restore your terminal with:
```bash
```
reset
```
## Background
The scrollback problem was first reported against the upstream project in
[openai/codex#2558](https://github.com/openai/codex/issues/2558).
+6 -6
View File
@@ -5,11 +5,11 @@ for Windows terminals.
Primary implementations:
- `codex-rs/tui/src/bottom_pane/chat_composer.rs`
- `code-rs/tui/src/bottom_pane/chat_composer.rs`
Paste-burst detector:
- `codex-rs/tui/src/bottom_pane/paste_burst.rs`
- `code-rs/tui/src/bottom_pane/paste_burst.rs`
## What problem is being solved?
@@ -55,7 +55,7 @@ The solution is to detect paste-like _bursts_ and buffer them into a single expl
Up/Down recall is handled by `ChatComposerHistory` and merges two sources:
- **Persistent history** (cross-session, fetched from `~/.codex/history.jsonl`): text-only. It
- **Persistent history** (cross-session, fetched from `$CODE_HOME/history.jsonl`): text-only. It
does **not** carry text element ranges or image attachments, so recalling one of these entries
only restores the text.
- **Local history** (current session): stores the full submission payload, including text
@@ -76,7 +76,7 @@ The search query and composer text intentionally remain separate. A no-match res
## Config gating for reuse
`ChatComposer` now supports feature gating via `ChatComposerConfig`
(`codex-rs/tui/src/bottom_pane/chat_composer.rs`). The default config preserves current chat
(`code-rs/tui/src/bottom_pane/chat_composer.rs`). The default config preserves current chat
behavior.
Flags:
@@ -96,7 +96,7 @@ Key effects when disabled:
dropping the draft.
Built-in slash command availability is centralized in
`codex-rs/tui/src/bottom_pane/slash_commands.rs` and reused by both the composer and the command
`code-rs/core/src/slash_commands.rs` and reused by both the composer and the command
popup so gating stays in sync.
## Submission flow (Enter/Tab)
@@ -337,7 +337,7 @@ Non-char input must not leak burst state across unrelated actions:
The `PasteBurst` logic is currently exercised through `ChatComposer` integration tests.
- `codex-rs/tui/src/bottom_pane/chat_composer.rs`
- `code-rs/tui/src/bottom_pane/chat_composer.rs`
- `non_ascii_burst_handles_newline`
- `ascii_burst_treats_enter_as_newline`
- `question_mark_does_not_toggle_during_paste_burst`
-124
View File
@@ -1,124 +0,0 @@
# TUI Stream Chunking
This document explains how stream chunking in the TUI works and why it is
implemented this way.
## Problem
Streaming output can arrive faster than a one-line-per-tick animation can show
it. If commit speed stays fixed while arrival speed spikes, queued lines grow
and visible output lags behind received output.
## Design goals
- Preserve existing baseline behavior under normal load.
- Reduce display lag when backlog builds.
- Keep output order stable.
- Avoid abrupt single-frame flushes that look jumpy.
- Keep policy transport-agnostic and based only on queue state.
## Non-goals
- The policy does not schedule animation ticks.
- The policy does not depend on upstream source identity.
- The policy does not reorder queued output.
## Where the logic lives
- `codex-rs/tui/src/streaming/chunking.rs`
- Adaptive policy, mode transitions, and drain-plan selection.
- `codex-rs/tui/src/streaming/commit_tick.rs`
- Orchestration for each commit tick: snapshot, decide, drain, trace.
- `codex-rs/tui/src/streaming/controller.rs`
- Queue/drain primitives used by commit-tick orchestration.
- `codex-rs/tui/src/chatwidget.rs`
- Integration point that invokes commit-tick orchestration and handles UI
lifecycle events.
## Runtime flow
On each commit tick:
1. Build a queue snapshot across active controllers.
- `queued_lines`: total queued lines.
- `oldest_age`: max age of the oldest queued line across controllers.
2. Ask adaptive policy for a decision.
- Output: current mode and a drain plan.
3. Apply drain plan to each controller.
4. Emit drained `HistoryCell`s for insertion by the caller.
5. Emit trace logs for observability.
In `CatchUpOnly` scope, policy state still advances, but draining is skipped
unless mode is currently `CatchUp`.
## Modes and transitions
Two modes are used:
- `Smooth`
- Baseline behavior: one line drained per baseline commit tick.
- Baseline tick interval currently comes from
`tui/src/app.rs:COMMIT_ANIMATION_TICK` (~8.3ms, ~120fps).
- `CatchUp`
- Drain current queued backlog per tick via `Batch(queued_lines)`.
Entry and exit use hysteresis:
- Enter `CatchUp` when queue depth or queue age exceeds enter thresholds.
- Exit requires both depth and age to be below exit thresholds for a hold
window (`EXIT_HOLD`).
This prevents oscillation when load hovers near thresholds.
## Current experimental tuning values
These are the current values in `streaming/chunking.rs` plus the baseline
commit tick in `tui/src/app.rs`. They are
experimental and may change as we gather more trace data.
- Baseline commit tick: `~8.3ms` (`COMMIT_ANIMATION_TICK` in `app.rs`)
- Enter catch-up:
- `queued_lines >= 8` OR `oldest_age >= 120ms`
- Exit catch-up eligibility:
- `queued_lines <= 2` AND `oldest_age <= 40ms`
- Exit hold (`CatchUp -> Smooth`): `250ms`
- Re-entry hold after catch-up exit: `250ms`
- Severe backlog thresholds:
- `queued_lines >= 64` OR `oldest_age >= 300ms`
## Drain planning
In `Smooth`, plan is always `Single`.
In `CatchUp`, plan is `Batch(queued_lines)`, which drains the currently queued
backlog for immediate convergence.
## Why this design
This keeps normal animation semantics intact, while making backlog behavior
adaptive:
- Under normal load, behavior stays familiar and stable.
- Under pressure, queue age is reduced quickly without sacrificing ordering.
- Hysteresis avoids rapid mode flapping.
## Invariants
- Queue order is preserved.
- Empty queue resets policy back to `Smooth`.
- `CatchUp` exits only after sustained low pressure.
- Catch-up drains are immediate while in `CatchUp`.
## Observability
Trace events are emitted from commit-tick orchestration:
- `stream chunking commit tick`
- `mode`, `queued_lines`, `oldest_queued_age_ms`, `drain_plan`,
`has_controller`, `all_idle`
- `stream chunking mode transition`
- `prior_mode`, `new_mode`, `queued_lines`, `oldest_queued_age_ms`,
`entered_catch_up`
These events are intended to explain display lag by showing queue pressure,
selected drain behavior, and mode transitions over time.
-98
View File
@@ -1,98 +0,0 @@
# TUI Stream Chunking Tuning Guide
This document explains how to tune adaptive stream chunking constants without
changing the underlying policy shape.
## Scope
Use this guide when adjusting queue-pressure thresholds and hysteresis windows in
`codex-rs/tui/src/streaming/chunking.rs`, and baseline commit cadence in
`codex-rs/tui/src/app.rs`.
This guide is about tuning behavior, not redesigning the policy.
## Before tuning
- Keep the baseline behavior intact:
- `Smooth` mode drains one line per baseline tick.
- `CatchUp` mode drains queued backlog immediately.
- Capture trace logs with:
- `codex_tui::streaming::commit_tick`
- Evaluate on sustained, bursty, and mixed-output prompts.
See `docs/tui-stream-chunking-validation.md` for the measurement process.
## Tuning goals
Tune for all three goals together:
- low visible lag under bursty output
- low mode flapping (`Smooth <-> CatchUp` chatter)
- stable catch-up entry/exit behavior under mixed workloads
## Constants and what they control
### Baseline commit cadence
- `COMMIT_ANIMATION_TICK` (`tui/src/app.rs`)
- Lower values increase smooth-mode update cadence and reduce steady-state lag.
- Higher values increase smoothing and can increase perceived lag.
- This should usually move after chunking thresholds/holds are in a good range.
### Enter/exit thresholds
- `ENTER_QUEUE_DEPTH_LINES`, `ENTER_OLDEST_AGE`
- Lower values enter catch-up earlier (less lag, more mode switching risk).
- Higher values enter later (more lag tolerance, fewer mode switches).
- `EXIT_QUEUE_DEPTH_LINES`, `EXIT_OLDEST_AGE`
- Lower values keep catch-up active longer.
- Higher values allow earlier exit and may increase re-entry churn.
### Hysteresis holds
- `EXIT_HOLD`
- Longer hold reduces flip-flop exits when pressure is noisy.
- Too long can keep catch-up active after pressure has cleared.
- `REENTER_CATCH_UP_HOLD`
- Longer hold suppresses rapid re-entry after exit.
- Too long can delay needed catch-up for near-term bursts.
- Severe backlog bypasses this hold by design.
### Severe-backlog gates
- `SEVERE_QUEUE_DEPTH_LINES`, `SEVERE_OLDEST_AGE`
- Lower values bypass re-entry hold earlier.
- Higher values reserve hold bypass for only extreme pressure.
## Recommended tuning order
Tune in this order to keep cause/effect clear:
1. Entry/exit thresholds (`ENTER_*`, `EXIT_*`)
2. Hold windows (`EXIT_HOLD`, `REENTER_CATCH_UP_HOLD`)
3. Severe gates (`SEVERE_*`)
4. Baseline cadence (`COMMIT_ANIMATION_TICK`)
Change one logical group at a time and re-measure before the next group.
## Symptom-driven adjustments
- Too much lag before catch-up starts:
- lower `ENTER_QUEUE_DEPTH_LINES` and/or `ENTER_OLDEST_AGE`
- Frequent `Smooth -> CatchUp -> Smooth` chatter:
- increase `EXIT_HOLD`
- increase `REENTER_CATCH_UP_HOLD`
- tighten exit thresholds (lower `EXIT_*`)
- Catch-up engages too often for short bursts:
- increase `ENTER_QUEUE_DEPTH_LINES` and/or `ENTER_OLDEST_AGE`
- increase `REENTER_CATCH_UP_HOLD`
- Catch-up engages too late:
- lower `ENTER_QUEUE_DEPTH_LINES` and/or `ENTER_OLDEST_AGE`
- lower severe gates (`SEVERE_*`) to bypass re-entry hold sooner
## Validation checklist after each tuning pass
- `cargo test -p codex-tui` passes.
- Trace window shows bounded queue-age behavior.
- Mode transitions are not concentrated in repeated short-interval cycles.
- Catch-up clears backlog quickly once mode enters `CatchUp`.
-107
View File
@@ -1,107 +0,0 @@
# TUI Stream Chunking Validation Process
This document records the process used to validate adaptive stream chunking
and anti-flap behavior.
## Scope
The goal is to verify two properties from runtime traces:
- display lag is reduced when queue pressure rises
- mode transitions remain stable instead of rapidly flapping
## Trace targets
Chunking observability is emitted by:
- `codex_tui::streaming::commit_tick`
Two trace messages are used:
- `stream chunking commit tick`
- `stream chunking mode transition`
## Runtime command
Run Codex with chunking traces enabled:
```bash
RUST_LOG='codex_tui::streaming::commit_tick=trace,codex_tui=info,codex_core=info,codex_rmcp_client=info' \
just codex --enable=responses_websockets
```
## Log capture process
Tip: for one-off measurements, run with `-c log_dir=...` to direct logs to a fresh directory and avoid mixing sessions.
1. Record the current size of `~/.codex/log/codex-tui.log` as a start offset.
2. Run an interactive prompt that produces sustained streamed output.
3. Stop the run.
4. Parse only log bytes written after the recorded offset.
This avoids mixing earlier sessions with the current measurement window.
## Metrics reviewed
For each measured window:
- `commit_ticks`
- `mode_transitions`
- `smooth_ticks`
- `catchup_ticks`
- drain-plan distribution (`Single`, `Batch(n)`)
- queue depth (`max`, `p95`, `p99`)
- oldest queued age (`max`, `p95`, `p99`)
- rapid re-entry count:
- number of `Smooth -> CatchUp` transitions within 1 second of a
`CatchUp -> Smooth` transition
## Interpretation
- Healthy behavior:
- queue age remains bounded while backlog is drained
- transition count is low relative to total ticks
- rapid re-entry events are infrequent and localized to burst boundaries
- Regressed behavior:
- repeated short-interval mode toggles across an extended window
- persistent queue-age growth while in smooth mode
- long catch-up runs without backlog reduction
## Experiment history
This section captures the major tuning passes so future work can build on
what has already been tried.
- Baseline
- One-line smooth draining with a 50ms commit tick.
- This preserved familiar pacing but could feel laggy under sustained
backlog.
- Pass 1: instant catch-up, baseline tick unchanged
- Kept smooth-mode semantics but made catch-up drain the full queued
backlog each catch-up tick.
- Result: queue lag dropped faster, but perceived motion could still feel
stepped because smooth-mode cadence remained coarse.
- Pass 2: faster baseline tick (25ms)
- Improved smooth-mode cadence and reduced visible stepping.
- Result: better, but still not aligned with draw cadence.
- Pass 3: frame-aligned baseline tick (~16.7ms)
- Set baseline commit cadence to approximately 60fps.
- Result: smoother perceived progression while retaining hysteresis and
fast backlog convergence.
- Pass 4: higher frame-aligned baseline tick (~8.3ms)
- Set baseline commit cadence to approximately 120fps.
- Result: further reduced smooth-mode stepping while preserving the same
adaptive catch-up policy shape.
Current state combines:
- instant catch-up draining in `CatchUp`
- hysteresis for mode-entry/exit stability
- frame-aligned smooth-mode commit cadence (~8.3ms)
## Notes
- Validation is source-agnostic and does not rely on naming any specific
upstream provider.
- This process intentionally preserves existing baseline smooth behavior and
focuses on burst/backlog handling behavior.