April 24, 2025
Today, Codex CLI is written in TypeScript and requires Node.js 22+ to run it. For a number of users, this runtime requirement inhibits adoption: they would be better served by a standalone executable. As maintainers, we want Codex to run efficiently in a wide range of environments with minimal overhead. We also want to take advantage of operating system-specific APIs to provide better sandboxing, where possible.
To that end, we are moving forward with a Rust implementation of Codex CLI contained in this folder, which has the following benefits:
- The CLI compiles to small, standalone, platform-specific binaries.
- Can make direct, native calls to seccomp and landlock in order to support sandboxing on Linux.
- No runtime garbage collection, resulting in lower memory consumption and better, more predictable performance.
Currently, the Rust implementation is materially behind the TypeScript implementation in functionality, so continue to use the TypeScript implmentation for the time being. We will publish native executables via GitHub Releases as soon as we feel the Rust version is usable.
This folder is the root of a Cargo workspace. It contains quite a bit of experimental code, but here are the key crates:
core/
contains the business logic for Codex. Ultimately, we hope this to be a library crate that is generally useful for building other Rust/native applications that use Codex.exec/
"headless" CLI for use in automation.tui/
CLI that launches a fullscreen TUI built with Ratatui.cli/
CLI multitool that provides the aforementioned CLIs via subcommands.
The CLI can be configured via ~/.codex/config.toml
. It supports the following options:
The model that Codex should use.
model = "o3" # overrides the default of "o4-mini"
Determines when the user should be prompted to approve whether Codex can execute a command:
# This is analogous to --suggest in the TypeScript Codex CLI
approval_policy = "unless-allow-listed"
# If the command fails when run in the sandbox, Codex asks for permission to
# retry the command outside the sandbox.
approval_policy = "on-failure"
# User is never prompted: if the command fails, Codex will automatically try
# something out. Note the `exec` subcommand always uses this mode.
approval_policy = "never"
List of permissions to grant to the sandbox that Codex uses to execute untrusted commands:
# This is comparable to --full-auto in the TypeScript Codex CLI, though
# specifying `disk-write-platform-global-temp-folder` adds /tmp as a writable
# folder in addition to $TMPDIR.
sandbox_permissions = [
"disk-full-read-access",
"disk-write-platform-user-temp-folder",
"disk-write-platform-global-temp-folder",
"disk-write-cwd",
]
To add additional writable folders, use disk-write-folder
, which takes a parameter (this can be specified multiple times):
sandbox_permissions = [
# ...
"disk-write-folder=/Users/mbolin/.pyenv/shims",
]
Currently, customers whose accounts are set to use Zero Data Retention (ZDR) must set disable_response_storage
to true
so that Codex uses an alternative to the Responses API that works with ZDR:
disable_response_storage = true
Specify a program that will be executed to get notified about events generated by Codex. Note that the program will receive the notification argument as a string of JSON, e.g.:
{
"type": "agent-turn-complete",
"turn-id": "12345",
"input-messages": ["Rename `foo` to `bar` and update the callsites."],
"last-assistant-message": "Rename complete and verified `cargo build` succeeds."
}
The "type"
property will always be set. Currently, "agent-turn-complete"
is the only notification type that is supported.
As an example, here is a Python script that parses the JSON and decides whether to show a desktop push notification using terminal-notifier on macOS:
#!/usr/bin/env python3
import json
import subprocess
import sys
def main() -> int:
if len(sys.argv) != 2:
print("Usage: notify.py <NOTIFICATION_JSON>")
return 1
try:
notification = json.loads(sys.argv[1])
except json.JSONDecodeError:
return 1
match notification_type := notification.get("type"):
case "agent-turn-complete":
assistant_message = notification.get("last-assistant-message")
if assistant_message:
title = f"Codex: {assistant_message}"
else:
title = "Codex: Turn Complete!"
input_messages = notification.get("input_messages", [])
message = " ".join(input_messages)
title += message
case _:
print(f"not sending a push notification for: {notification_type}")
return 0
subprocess.check_output(
[
"terminal-notifier",
"-title",
title,
"-message",
message,
"-group",
"codex",
"-ignoreDnD",
"-activate",
"com.googlecode.iterm2",
]
)
return 0
if __name__ == "__main__":
sys.exit(main())
To have Codex use this script for notifications, you would configure it via notify
in ~/.codex/config.toml
using the appropriate path to notify.py
on your computer:
notify = ["python3", "/Users/mbolin/.codex/notify.py"]