notes

codex manual

First published: Last updated: 7123 words · 2 lines of code

Overview

codex.el provides an Emacs interface to the OpenAI Codex CLI, allowing you to interact with the Codex agent directly from within Emacs. The package is modeled after claude-code.el and shares a similar architecture and design philosophy.

The package runs Codex through the native app-server renderer or a terminal backend (eat by default, with vterm available separately), giving you a full-featured Codex experience without leaving your editor. You can start, stop, and manage multiple Codex instances across different projects, send commands and code from any buffer, toggle the Codex window on and off, and access all of the CLI’s slash commands through a transient menu.

The main capabilities of codex.el can be grouped thematically:

  • Session management — start Codex in the current project, resume or fork previous sessions, run multiple named instances side by side, and kill instances individually or all at once.
  • Sending commands and context — send freeform commands, send commands annotated with file and line context, send the active region or entire buffer, send file paths and images, and ask Codex to fix errors at point.
  • Terminal and native rendering backends — run new Codex sessions through the Eat terminal TUI by default for compatibility; keep the app-server renderer available when assistant messages, Markdown tables, and post-table text should not depend on terminal screen history.
  • Window and buffer management — toggle the Codex window, switch between instances, select from all running instances, and toggle read-only mode.
  • Hooks and notifications — auto-configure the Codex CLI hooks system so that Emacs receives lifecycle events (session start, tool use, permission requests, stop); trigger desktop notifications when Codex finishes and awaits input.
  • Transient menus — a main command menu and a slash commands menu, both accessible from the keyboard.
  • Model and configuration — change the model, reasoning effort, sandbox mode, approval policy, and profile on the fly through transient infixes.

The package requires Emacs 28.1 or later, transient 0.9.3 or later, inheritenv, and eat. The default backend is eat, which runs the Codex terminal TUI. Set codex-terminal-backend to app-server or to vterm if you prefer those terminal backends.

The development repository is on GitHub.

User options

Core settings

The user option codex-program specifies the path to the Codex binary. The default value is "codex", which relies on the binary being in your PATH. Change this if you have installed Codex to a non-standard location.

The user option codex-program-switches is a list of extra CLI flags to pass to terminal Codex sessions. The default value is nil. Use this for terminal-backend flags that you always want applied but that are not covered by the dedicated user options below.

The user option codex-terminal-backend selects the Codex backend. The choices are eat (the default), app-server, and vterm. The eat and vterm choices run the Codex terminal TUI. The app-server backend starts codex app-server --listen stdio://, parses its newline-delimited JSON-RPC event stream from standard output, and renders assistant messages directly in the Emacs buffer. Standard error is kept out of the protocol renderer and its side buffer is cleaned up with the app-server process, so CLI status logs do not appear as malformed app-server messages or leave process prompts behind when a session exits. This avoids terminal redraw and scrollback loss for wide Markdown tables. On the app-server backend, codex-resume and codex-fork work natively: they list previous threads with thread/list, prompt for one, resume or fork it through thread/resume or thread/fork, and replay the prior user-visible JSONL transcript when available, including the CLI-style padded user prompt rows, separators around replayed tool groups, Markdown-visible wrapping, relative file-link display, continuation indentation for replayed assistant messages, and the idle warning/composer/status block, falling back to the app-server turn history only when the transcript is unavailable.

New sessions started with codex or codex-new-instance use the global default value of codex-terminal-backend. Existing Codex session buffers keep their actual backend in a buffer-local value so commands that act on that buffer continue to dispatch correctly.

When an app-server session connects, codex.el renders the same startup banner shape as the terminal TUI: Codex version, model, reasoning effort, service tier, working directory, and the standard keymap tip. App-server notifications are rendered only when they belong to the buffer’s current thread, so sub-agent or side-thread events do not leak command output into the parent thread’s buffer.

The app-server buffer presents an editable input region after a prompt at the end of the buffer. Type a message there and press the send key to submit it; conversation output renders above the prompt while the rendered history stays read-only and fully scrollable. The send and newline keys follow codex-newline-keybinding-style, so a multi-line prompt is composed with the newline key and submitted with the send key. As in the Codex CLI, sending while a turn is active steers the current turn. Pressing TAB accepts the visible idle suggestion, completes a slash command or $ skill reference when idle, and queues the input to run as the next turn while a turn is in progress. Queued inputs render in a live • Queued follow-up inputs block (one line each), exactly as the CLI shows them; M-<up> pulls the last queued input back into the composer to edit it. While a turn is active, a • Working (Ns • esc to interrupt) line shows above the prompt, and ESC (or C-g) interrupts the turn like the CLI’s Esc. Several composer affordances match the CLI: a leading ! runs the rest of the line as a shell command in the thread, the idle suggestion appears after the cursor through Emacs completion preview with Codex’s autosuggestion styling when that native preview facility is available and the composer is empty, typing @ completes a project file path into the message, M-p and M-n cycle through previously sent prompts (with C-c C-r searching them by completion), C-c C-e opens a separate buffer to compose a long prompt that is sent back with C-c C-c, and C-c C-<up> / C-c C-<down> raise and lower the reasoning effort for upcoming turns (matching the CLI’s reasoning up/down). The composer remains the last buffer text so moving to the end of the buffer lands in editable input. The user option codex-app-server-prompt-string sets the prompt shown before the input region; the default is "\n› ".

Skill completion searches the configured codex-app-server-skill-directories and project-local .claude/skills, .claude/programmatic-skills, .codex/skills, and .codex/programmatic-skills directories in the Codex session directory and its ancestors.

The app-server backend renders conversation items the way the Codex CLI does, using the same item prefixes: user messages lead with and every agent-side item (assistant messages, reasoning, commands, file changes, plans) leads with , with continuation lines indented to align under the bullet and one blank line between items. Command executions are collapsed exactly like the CLI: a • Ran COMMAND header (or ✗ Ran COMMAND (exit N) on failure), then the first codex-app-server-max-command-output-lines output lines (default 3, matching the CLI), a … +N lines marker, and the final output line, indented under a connector. Commands with no output render just the command header. This avoids dumping full command output (which can be megabytes) into the buffer; the full output is available with codex-app-server-expand-output (C-c C-o). Commands that only read files are grouped into a • Explored block with a └ Read FILE, FILE line and no output dump, exactly as the CLI collapses pure file reads. Reasoning summaries render as dimmed text; file changes render as a • Edited FILE (+N -M) header followed by the diff numbered and marked like the CLI (~ 4 -four~ / ~ 4 +FOUR~), with added and removed line faces; MCP tool calls render as • Called SERVER.TOOL(ARGS) with the folded text result under , like the CLI; web searches render as • Searched the web for QUERY like the CLI; and the turn plan renders as a • Updated Plan tree with for completed and for pending steps, updating in place as steps complete. Turn errors render as a status line showing the server’s error message, including the message nested under a turn error, so they are not silently dropped.

When Codex requests approval, codex.el prompts with the same choices the CLI offers for that request. For a command, the choices come from the request’s availableDecisions – approve once, approve and stop asking for this command (the execpolicy amendment), or decline – so the decision sent back is always one the server accepts. For a file change, the choices are apply once, apply for the rest of the session, decline, or cancel the turn.

While a turn is running, codex.el shows a • Working (Ns • esc to interrupt) line above the prompt, matching the CLI status line, plus a mode-line indicator that also reports token usage. Both clear when the turn completes.

On the app-server backend, slash commands typed into the input are dispatched locally instead of being sent to the model: /compact compacts the conversation, /clear clears the display, /status shows model and token usage, /diff shows the working-tree diff, /copy copies the last reply, /new, /resume, /fork, /permissions, /quit map to the matching commands, /model lists and switches the model and reasoning effort through thread/settings/update, /mention attaches a file, /agent switches between Codex buffers, /side starts a new session, /theme and /vim map to the Emacs theme and Vim-mode equivalents, /keymap describes the buffer keymap, /raw toggles Markdown rendering, /goal, /title, /rename, /archive, /memories, /personality, /plan, and /stop drive the matching thread/* requests (/rename and /title rename the thread; /archive archives it), and /init and /review are sent as prompts. The TAB-completion set mirrors the CLI’s full slash-command list. Every other documented slash command (/fast, /mcp, /ps, /ide, /logout, /experimental, /plugins, /hooks, /approve, /debug-config, /feedback) is recognized and reports how it is configured, so no slash command is sent to the model as text. Lifecycle hook events (hook/started, hook/completed) render as dimmed status lines when codex-app-server-show-hooks is enabled, and primary rate-limit usage is recorded and shown by /status. The app-server backend reads account rate limits during startup; when weekly usage is high, the CLI-style weekly-limit warning renders above the idle composer. Other warnings, deprecation and guardian notices, conversation compaction, model reroutes, MCP server startup progress and failures, and thread name and goal updates also render as status lines.

The experimental realtime channel is handled too: codex-app-server-realtime-start, codex-app-server-realtime-stop, and codex-app-server-realtime-send-text control a text-output realtime session, and realtime lifecycle and transcript events render in the buffer (audio streaming and SDP signaling are accepted but not rendered, since they have no text representation).

Because command output is folded, codex-app-server-expand-output (bound to C-c C-o) shows the full, unfolded output of the command block at point in a dedicated buffer, mirroring the CLI transcript view.

Images can be attached to a turn on the app-server backend: codex-default-images are attached to the first prompt, codex-app-server-attach-image attaches an image file to the next turn, and codex-app-server-paste-image (bound to C-v, matching the Codex CLI’s Ctrl+V) attaches an image directly from the system clipboard and inserts an [Image #N] placeholder into the composer at point, exactly as the CLI does. Attached images are sent as localImage input items.

Completed assistant messages in app-server buffers are rendered as Markdown the way the Codex CLI renders them. When markdown-mode is available, codex.el fontifies each message through gfm-mode and, like the CLI, hides only the inline emphasis markers (so **bold** and `code` show as styled text without the delimiters) while keeping block markers such as heading # and list - visible and syntax-coloured. The user option codex-app-server-render-markdown enables this rendering; the default is t. When it is nil, or when markdown-mode is not installed, a lightweight built-in highlighter is used instead.

The user option codex-app-server-listen-url controls the transport passed to codex app-server --listen. The default is "stdio://", which keeps the server private to the Emacs process.

The user option codex-app-server-program-switches is a list of extra CLI flags to pass to codex app-server. The default value is nil.

The user option codex-use-alt-screen controls whether terminal backends run Codex in its default alternate-screen TUI mode. The default is nil, so codex.el starts terminal sessions with --no-alt-screen for inline scrollback mode. This avoids recurring stale-screen failures seen when Codex’s alternate-screen TUI and Emacs terminal buffers lose synchronization after interrupts, prompt editing, or heavy redraws. Set it to non-nil only if you explicitly want Codex’s alt-screen TUI.

The user option codex-disable-terminal-resize-reflow controls whether codex.el passes --disable terminal_resize_reflow to new terminal-backend Codex sessions. The default is t because Codex’s experimental terminal reflow rebuilds scrollback after width changes, while Emacs terminal buffers use the buffer itself as retained session history. Disable this option only if you prefer Codex’s own terminal reflow behavior.

The user option codex-term-name overrides the terminal type reported to Codex by terminal backends. The default is nil, meaning codex.el chooses a backend-appropriate TERM value. For eat, Codex buffers use Eat’s bundled eat-* terminfo even if the global eat-term-name has been customized; for vterm, Codex buffers keep vterm’s own default. Set this to a string such as "xterm-256color" only when your terminal environment requires a specific TERM value. The value is applied when the terminal subprocess starts, so changes affect new Codex buffers rather than already-running sessions.

In eat buffers, codex.el disables Eat shell integration for the Codex subprocess and ignores Eat’s private UI-command channel in the outer terminal, including in existing Codex buffers after codex.el is reloaded. Codex is itself a TUI that captures and re-renders tool output; if nested shell commands emit Eat-private OSC sequences, those sequences can leak into captured tool output and corrupt the outer terminal display.

In eat Codex buffers, codex.el also coalesces terminal output chunks that end in the middle of a CSI escape sequence. This protects Codex sessions from a known failure mode where the CLI emits a cursor-shape sequence such as ESC [ 0 SPC q across two process-output chunks and Eat tries to parse the incomplete first half as a complete sequence. Codex additionally strips aborted CSI fragments — a CSI sequence terminated by ESC instead of a final byte — because Eat misroutes the abort byte as part of the CSI function, desynchronising its cursor tracking and tripping an assertion in eat--t-cur-left on the next cursor move. If Eat still rejects an output chunk, codex.el logs the parser error, retries that chunk as plain readable text with terminal controls removed, and then keeps processing later queued output instead of letting one malformed chunk abort the whole burst. Codex’s post-output maintenance hooks are also isolated from Eat’s output queue, so display remapping or prompt autosuggestion errors are logged instead of repeatedly aborting eat--process-output-queue.

The user option codex-startup-delay is a number of seconds to wait after starting the Codex process before displaying the buffer. The default is 0.1. Increasing this value can help fix terminal layout issues that occur when the buffer is displayed before Codex has fully initialized.

The user option codex-confirm-kill controls whether codex-kill and codex-kill-all ask for confirmation before killing instances. The default is t. Set it to nil if you prefer to kill instances without a prompt.

The user option codex-newline-keybinding-style controls how the return key behaves in Codex buffers. The default, newline-on-shift-return, makes S-RET insert a line break and plain RET submit the prompt, mirroring the behavior of claude-code.el. The other choices are newline-on-alt-return (M-RET for newline, RET to submit), shift-return-to-send (RET for newline, S-RET to submit), and super-return-to-send (RET for newline, s-RET — the COMMAND key on macOS — to submit). The line-break action is delivered to Codex as Ctrl+J (byte 0x0A), which the Codex CLI binds to its insert_newline editor action by default; submission is delivered as a plain Return.

In eat buffers, plain Return is dispatched as the same RET character event used by normal terminal input; Escape also goes through Eat’s key-event input path rather than raw string insertion. This keeps programmatic TUI actions aligned with real keypresses.

The user option codex-enable-prompt-autosuggestions controls whether codex.el styles prompt autosuggestions in eat buffers. The default is t. Codex renders placeholder and suggestion text after the terminal cursor; when that text arrives in Emacs without the CLI’s dim styling, codex.el recognizes known suggestions and applies codex-prompt-autosuggestion-face, which inherits shadow without forcing italic text. While an autosuggestion is visible, codex.el keeps point at the prompt cursor rather than the footer line that Codex renders below the prompt. The options codex-prompt-autosuggestion-placeholders, codex-prompt-autosuggestion-history-path, and codex-prompt-autosuggestion-history-limit control which built-in placeholder strings and recent history entries are recognized as autosuggestions. In eat Codex buffers, TAB first accepts the visible autosuggestion when there is one; otherwise it is sent through to the Codex TUI as a normal tab.

Sandbox and approval

The user option codex-sandbox-mode controls the sandboxing level for Codex. When nil (the default), the CLI’s own default is used. The other choices are read-only, workspace-write, and danger-full-access, which correspond to the CLI’s --sandbox flag values. This option is ignored when codex-full-auto is non-nil.

The user option codex-approval-policy sets the approval policy for tool use. When nil (the default), the CLI default applies. The choices are untrusted, on-request, and never, corresponding to the --ask-for-approval flag. This option is also ignored when codex-full-auto is non-nil.

The user option codex-full-auto enables fully autonomous mode by passing --dangerously-bypass-approvals-and-sandbox to Codex. The default is nil. When non-nil, this overrides both codex-sandbox-mode and codex-approval-policy. Use with caution.

Model and profile

The user option codex-model specifies a model override (e.g., "gpt-5.4"). The default is nil, which uses the CLI’s default model.

The user option codex-profile names a configuration profile. The default is nil, meaning the CLI default profile is used. Profiles allow you to maintain separate sets of configuration for different workflows.

The user option codex-reasoning-effort overrides the reasoning effort level. The default is nil. When set to a string value, it is passed via -c as the model_reasoning_effort configuration value.

Hooks integration

The user option codex-enable-hooks controls whether codex.el automatically configures the Codex CLI hooks system. The default is t. When enabled, activating codex-mode ensures that config.toml has hooks = true under [features] and that hooks.json contains entries for all supported hook types. The installed hook wrapper forwards only sessions that codex.el launched with CODEX_BUFFER_NAME set; other Codex sessions consume the hook input and continue without contacting Emacs.

The user option codex-hooks-config-path is the path to the Codex config.toml file. The default is "~/.codex/config.toml".

The user option codex-hooks-json-path is the path to the Codex hooks.json file. The default is "~/.codex/hooks.json".

The user option codex-emacsclient-program specifies the emacsclient executable used by the hook wrapper. The default is nil, meaning codex.el records the first emacsclient found in PATH when hooks are configured.

Background and contrast remapping

The Codex CLI has its own theme system, and the colors it emits do not always match the Emacs theme. Mismatches make terminal text unreadable in two directions: the CLI may paint light backgrounds on a dark Emacs theme (bright rectangles containing dark text), or dark backgrounds on a light Emacs theme (dark rectangles containing light text). A third kind of mismatch is low-contrast foreground colors that wash out against the effective background (e.g. bright cyan on a light default background, or dark red on a dark diff background). The remapping system runs after each batch of terminal output and addresses all three.

The user option codex-remap-light-backgrounds is the master switch. The default is t. When non-nil, background colors whose WCAG contrast against the Emacs default background exceeds codex-background-contrast-threshold are stripped (or replaced), and — when codex-minimum-contrast-ratio is also non-nil — low-contrast foregrounds are stripped as well.

The user option codex-card-background specifies the replacement color for clashing backgrounds. When nil (the default), clashing backgrounds are stripped entirely so the Emacs buffer background shows through. Set this to a color string (e.g. "#1a1b2e") to use a fixed replacement color instead.

The user option codex-background-contrast-threshold is a WCAG contrast ratio above which a CLI background is considered to clash with the Emacs theme. The default is 1.0, which strips any explicit background that is not identical to the Emacs default background — the cleanest result for users who want the Emacs theme to fully own the rendering. Codex’s diff foregrounds (colored + / - glyphs) still distinguish added and removed lines after the bg strip. Raise this to 3.0 (the WCAG AA threshold for large text) to preserve subtle low-contrast tints (e.g. light-green diff backgrounds on a light theme at contrast 1.04:1) and only strip clashing rectangles. Because the comparison is against the Emacs default background, the same threshold handles mismatches in either direction.

The user option codex-minimum-contrast-ratio is a WCAG contrast ratio below which the explicit foreground is stripped so the Emacs theme’s default foreground takes over. The default is 3.0. Set this to nil to disable contrast-based foreground remapping while keeping background remapping. Stripping the foreground rather than the background preserves the semantic tint of diff-added and diff-removed backgrounds while ensuring the text itself remains readable.

Because the remapping pass runs after every batch of terminal output, it only inspects the current eat display plus newly appended output since the previous pass, not the full retained scrollback. Perceived luminance results are also memoized in codex--color-luminance-cache — a process-wide hash table keyed by color string. The cache is small (one entry per distinct color) and is preserved across reloads of the package, so repeated contrast comparisons reduce to O(1) hash lookups instead of repeated color-name-to-rgb calls.

Why is this a post-hoc remap instead of a clean fix?

This feature exists because the Codex CLI emits 24-bit RGB escape codes for card backgrounds and some foregrounds. Those land as literal :foreground / :background text properties in the eat buffer, bypassing the Emacs face system entirely — there is no indirection point where the Emacs theme gets to participate.

The clean alternative would be to downgrade Codex to 256-color (which eat routes through eat-term-color-* faces that the Emacs theme already controls). That was attempted by setting COLORTERM= (empty) in the Codex subprocess environment. It did not work: Codex’s Rust UI code calls Color::Rgb(...) directly in several places (chat composer, diff blocks), bypassing its own stdout_color_level() detection. No env var or config key currently turns those call sites off, and NO_COLOR=1 is too aggressive (it disables all color).

This machinery should be revisited and deleted if Codex stops hardcoding Color::Rgb in its UI code, grows a config option to use the terminal palette, or starts honoring COLORTERM consistently. To verify: start a fresh Codex session and check whether the buffer contains literal #RRGGBB hex colors in its face text properties — if all colors route through eat-term-color-* faces, this whole section can go.

Notifications

The user option codex-enable-notifications controls whether notifications are shown when Codex finishes a task and is waiting for input. The default is t. Notifications are triggered by bell characters from the terminal or by Stop hook events.

The user option codex-notification-function specifies the function called for notifications. The function receives two arguments: a title string and a message string. The default is codex-default-notification, which displays a message in the echo area and pulses the mode line (Notification functions).

Window management

The user option codex-no-delete-other-windows prevents Codex windows from being deleted by delete-other-windows. The default is nil. Set this to t if you want the Codex window to persist when you use C-x 1 or similar commands.

The user option codex-toggle-auto-select controls whether codex-toggle automatically selects the Codex window after opening it. The default is nil, meaning the window is displayed but focus stays in the current window.

The user option codex-optimize-window-resize controls whether terminal reflows are suppressed when the window size has not changed. The default is t. This avoids redundant redraws while still keeping the terminal dimensions synchronized after width or height changes.

The user option codex-display-window-fn specifies the function used to display the Codex window. It must accept a buffer argument. The default is codex-display-buffer-same-window, which displays the Codex buffer in the current window. An alternative codex-display-buffer-below is also provided, which displays it below the currently selected window.

Images

The user option codex-default-images is a list of image file paths to attach at startup via the --image flag. The default is nil. Use this to always include certain screenshots or diagrams as context.

Emacs hooks

The hook codex-start-hook runs after a Codex instance starts. Use it to perform additional setup in the Codex buffer, such as enabling minor modes or customizing keybindings.

The abnormal hook codex-command-submitted-hook runs before input is submitted to a Codex session; each function receives the session buffer, with that buffer current, and must be idempotent because a single submission may run the hook more than once.

The abnormal hook codex-process-environment-functions lets you inject environment variables into the Codex process. Each function receives two arguments: the Codex buffer name and the project directory. Each function should return a list of strings in "VAR=VALUE" format.

The hook codex-event-hook runs when the Codex CLI triggers lifecycle events through the hooks system. This is an abnormal hook: functions are called with a single plist argument containing :type, :buffer-name, :json-data, and :args, and dispatch stops at the first non-nil return value. That value is returned to the Codex CLI hook process, which lets permission and tool hooks approve, deny, or block.

The user option codex-transcript-catch-up-on-stop controls whether Stop hooks repair stale terminal output from Codex JSONL transcripts. This catch-up repair applies only to the eat and vterm terminal backends. The app-server backend uses JSONL transcripts for resumed history replay when available, but live app-server turns still render from structured protocol events and do not use Stop-hook catch-up. The default is nil because Stop hooks can run before the JSONL transcript has recorded the just-finished turn, and an automatic repair may otherwise append an older assistant message into the live buffer. When enabled, codex.el tracks the session id from hook JSON, finds the transcript under codex-transcript-sessions-directory, and inserts only the missing suffix when the terminal buffer already shows the beginning of the answer. Repair text is placed at the visible truncation point only when transcript lines match the buffer in order, or before the active prompt, so unrelated repeated lines earlier in scrollback do not suppress repair. Prefer calling codex-refresh-from-transcript explicitly to repair a known stale buffer after the transcript has settled.

Eat terminal settings

The user option codex-eat-read-only-mode-cursor-type specifies the cursor appearance when the eat terminal is in read-only mode. The value is a list of the form (CURSOR-ON BLINKING-FREQUENCY CURSOR-OFF). The default is (box nil nil), which shows a non-blinking filled box cursor.

The user option codex-eat-disable-cursor-blink controls whether Codex eat buffers map blinking terminal cursor states to non-blinking equivalents. The default is t. This keeps the terminal cursor visible while avoiding Eat’s graphical cursor blink timer, which redraws the whole frame and can flicker on macOS. Set this to nil if you want Codex to honor blinking cursor states exactly as emitted by the CLI.

The user option codex-eat-scrollback-size controls how much scrollback eat keeps for Codex buffers. The default is nil, meaning unlimited scrollback. This avoids losing earlier Codex output in long sessions; set it to a number of characters if you want a bounded buffer.

The user option codex-eat-preserve-scrollback controls whether Codex eat buffers strip CSI erase-display commands that can delete retained history before Eat processes output. The default is t. Codex runs with --no-alt-screen by default so the Emacs buffer can serve as session history, but TUI redraws can still emit erase-above, erase-all, or erase-scrollback sequences that make Eat delete retained buffer text. Ordinary erase-below redraw commands still pass through so prompt menus and status areas can clear stale text.

The package also defines faces for the eat terminal that inherit from the corresponding eat faces: codex-eat-prompt-annotation-running-face, codex-eat-prompt-annotation-success-face, codex-eat-prompt-annotation-failure-face, codex-eat-term-bold-face, codex-eat-term-faint-face, codex-eat-term-italic-face, codex-eat-term-slow-blink-face, codex-eat-term-fast-blink-face, and font faces codex-eat-term-font-0-face through codex-eat-term-font-9-face. Customize these faces if you want the Codex terminal to look different from other eat buffers.

Vterm terminal settings

The user option codex-vterm-buffer-multiline-output controls whether multi-line terminal output is buffered to prevent flickering. The default is t. When enabled, rapid successive output chunks containing cursor movement sequences are accumulated and flushed as a single update.

The user option codex-vterm-multiline-delay sets the delay (in seconds) before processing buffered vterm output. The default is 0.01. Increase this if you still see flickering with the buffering enabled.

The user option codex-vterm-max-scrollback controls how many scrollback lines vterm keeps for Codex buffers. The default is 100000, which is vterm’s built-in maximum unless its native module is recompiled with a larger limit.

Commands

Session management

The command codex starts a Codex instance in the current project root or, if not in a project, in the directory of the current file. If exactly one Codex instance is already running for that directory, it displays that instance instead of prompting for another name. If multiple instances are running, you are prompted for an instance name so that a new instance can coexist with them. With a single prefix argument (C-u), the cursor switches to the Codex buffer after starting or reusing it. With a double prefix argument (C-u C-u), you are prompted for the project directory.

The command codex-start-in-directory always prompts for a directory before starting Codex, regardless of the current project. With a prefix argument, it also switches to the Codex buffer.

The command codex-resume resumes a previous Codex session. On the app-server backend, it starts a native app-server buffer, lists prior threads with thread/list, resumes the selected thread with thread/resume, and replays the prior conversation history into the buffer. Internal callers that already know the session ID can use the same app-server path without opening the terminal TUI. Codex buffers also maintain a canonical session identity from the app-server thread id, hook metadata, and JSONL transcript path, so callers can resume the current session without depending on backend-specific buffer variables. On terminal backends, the command runs the Codex CLI’s resume subcommand. If other instances already exist for the directory, you are prompted for an instance name; otherwise the name defaults to "default". With a prefix argument, it resumes the most recent session.

The command codex-fork forks a previous session by running codex fork. Like codex-resume, it only prompts for an instance name when other instances exist, and accepts a prefix argument for --last.

The command codex-new-instance creates a new Codex instance and always prompts for an instance name, even if no other instances are running. This is useful when you want to name your instance from the start, or when codex would otherwise reuse the sole running instance for the directory. It accepts the same prefix argument conventions as codex.

The command codex-kill kills the Codex instance associated with the current directory. If multiple instances are running for the directory, you are prompted to select one. If codex-confirm-kill is non-nil (the default), confirmation is required.

The command codex-kill-all kills all Codex instances across all directories. It reports the number of instances killed and, like codex-kill, respects the codex-confirm-kill setting.

Sending commands and context

The command codex-send-command reads a command from the minibuffer and sends it to the Codex instance for the current project. Input history is maintained in codex-command-history. With a prefix argument, the cursor switches to the Codex buffer after sending.

Programmatic callers that already know the target session can use the same terminal ordering through codex--send-command-to-buffer. It sends the command text literally to that specific Codex buffer, selects the buffer’s window, then submits it by calling codex--terminal-send-return interactively. Literal sending preserves tabs and other text that would otherwise be interpreted as Emacs or Codex key bindings. Dollar commands trigger Codex’s skill completion UI, so they receive the additional Return events needed to accept the skill completion and submit the resulting prompt.

The command codex-send-command-with-context works like codex-send-command but appends a file reference (in @file:line format) to the command. If a region is active, it includes the line range of the region. This is particularly useful when you want to direct Codex’s attention to a specific location in your code.

The command codex-send-region sends the active region to Codex, or the entire buffer if no region is active. With a single prefix argument, it prompts for instructions to prepend to the text. With a double prefix argument, it also switches to the Codex buffer.

The command codex-send-buffer-file sends the file path of the current buffer to Codex, prefixed with @. This tells Codex to read the file. With a prefix argument, it prompts for instructions to include alongside the file reference. With a double prefix argument, it also switches to the Codex buffer.

The command codex-send-image prompts for an image file and sends its path to Codex prefixed with @. Use this to attach screenshots or diagrams as context for your request.

The command codex-fix-error-at-point examines the error at point (using Flycheck or help-at-pt), formats it with the file and line reference, and sends it to Codex with instructions to fix the error. With a prefix argument, it switches to the Codex buffer.

TUI key sequences

These commands send specific key sequences to the Codex TUI, allowing you to interact with Codex without switching to the terminal buffer.

The command codex-send-return sends a return key press. This is equivalent to pressing Enter in the Codex TUI and is often used to confirm actions.

The command codex-send-escape sends an escape key press, typically used to cancel or dismiss prompts. In eat buffers, C-g is also bound to this command.

The commands codex-previous-agent and codex-next-agent send Codex’s agent-navigation key sequences. In terminal buffers, M-<left> and M-<right> are bound to these commands so multi-agent sessions can switch between the main thread and subagent threads when Codex accepts agent navigation.

The command codex-edit-previous-message sends Esc Esc to walk back and edit the previous message. After sending the sequence, it switches to the Codex buffer so you can edit inline.

The command codex-queue-followup sends a Tab key press to queue a follow-up prompt while Codex is still working.

The command codex-inject-mid-turn sends a Return key press to inject instructions while Codex is in the middle of processing.

The command codex-header-search sends Ctrl+K to open the header search overlay in the Codex TUI.

The command codex-accept-prompt-autosuggestion accepts the visible prompt autosuggestion in an eat Codex buffer by sending only the suggested suffix to the terminal. It returns non-nil when it accepted a suggestion, which lets TAB handlers use it before falling back to a raw tab for Codex’s own queue/submit behavior.

The commands codex-send-1, codex-send-2, and codex-send-3 send the corresponding digit to the Codex TUI. These are useful for selecting numbered options in menus.

Buffer and window management

The command codex-toggle shows or hides the Codex window. If the Codex buffer is currently visible and another window exists, it deletes the Codex window; if the Codex window is the only window, it buries the buffer instead. If the buffer is hidden, it displays it using codex-display-window-fn. The codex-no-delete-other-windows parameter is applied to the window. If codex-toggle-auto-select is non-nil, focus moves to the Codex window when it is shown (Window management).

The command codex-switch-to-buffer switches to the Codex buffer for the current project. If multiple instances are running, you are prompted to select one. With a prefix argument, it shows all live Codex instances across all directories. Buffers whose terminal process has exited are ignored even if their names still match the Codex buffer pattern.

The command codex-select-buffer prompts you to select from all live Codex instances across all directories and switches to the selected one.

The command codex-toggle-read-only-mode toggles the terminal between read-only mode and interactive mode. In read-only mode (eat’s Emacs mode or vterm’s copy mode), you can navigate and copy text using normal Emacs keybindings. In interactive mode, keystrokes are sent to the terminal.

Model and permissions

The command codex-cycle-permissions sends /permissions to the Codex TUI to cycle through approval modes.

Diagnostics

When the Codex buffer displays rendering artifacts — such as colored rectangles with invisible text — these diagnostic commands help identify the root cause by inspecting the face properties that the terminal emulator has applied.

The command codex-diagnose-faces-at-point reports the face plist at point, including the explicit and effective foreground and background colors, the WCAG contrast ratio between them, the :inherit chain, and whether the background remapping system would process this span. Run this with point on a visually corrupted region to see whether the issue is a low-contrast color combination, a missing foreground, or a background that falls below the remapping threshold (Background color remapping).

The command codex-diagnose-faces-in-region audits all face property spans between BEG and END, reporting any non-whitespace text with a contrast ratio below 3:1. With no active region, it audits the visible portion of the buffer. The output lists the line number, contrast ratio, foreground, background, and a text excerpt for each problematic span.

The command codex-redraw asks the Codex TUI to repaint and then forces the Emacs terminal backend to redisplay. It is bound to C-l in Codex buffers and to l in codex-command-map. This is mainly a recovery command for existing or explicitly opted-in alt-screen sessions; new sessions avoid that failure class by default because codex-use-alt-screen is nil.

Functions

Session API functions

The function codex-start-session starts a Codex session from explicit keyword parameters (:directory, :instance-name, :initial-prompt, :resume-id, :terminal-backend) and returns its buffer.

The function codex-prompt-input returns the pending prompt input text in a Codex session buffer, or nil when the prompt is empty.

The function codex-session-identity returns a session buffer’s identity as a plist with keys :directory, :instance, :session-id, and :terminal-backend, or nil for buffers that are not Codex sessions.

Notification functions

The function codex-default-notification is the default notification handler. It takes a title and message, displays them in the echo area, and pulses the mode line three times. You can replace this by setting codex-notification-function to a custom function, for example one that uses alert.el or the system notification center (Notifications).

The function codex-display-buffer-same-window displays the Codex buffer in the current window using display-buffer-same-window. It is the default value of codex-display-window-fn (Window management).

The function codex-display-buffer-below displays the Codex buffer below the currently selected window using display-buffer-below-selected.

Hook handling

The hook path has two stages. The codex-hook-wrapper shell script is the command recorded in hooks.json. When the hook did not come from a codex.el-launched session, indicated by a missing CODEX_BUFFER_NAME, the wrapper consumes standard input and exits successfully without calling emacsclient. For Emacs-owned sessions, it reads the hook JSON on standard input, writes that JSON to a private temporary file, and calls codex-handle-hook-from-emacsclient via emacsclient targeted at the Emacs server that configured the hooks. The wrapper retries transient emacsclient socket failures briefly; if dispatch still fails for non-permission lifecycle/tool-state hooks such as PreToolUse, PostToolUse, Stop, SessionStart, UserPromptSubmit, PreCompact, or PostCompact, it fails open so an unavailable Emacs server does not block ordinary Codex work after the dedicated shell policy hooks have already run. PermissionRequest remains fail-closed because it is a live approval gate. The argv protocol after the hook type and buffer name is json-file JSON-FILE response-file RESPONSE-FILE ..., so large or sensitive hook JSON does not travel through argv and Emacs can write a hook response back to the wrapper. Hook installation also replaces older notify-emacs-hook.sh entries so stale wrappers cannot feed hook JSON back to Codex as terminal input.

The function codex-handle-hook-from-emacsclient parses that protocol from server-eval-args-left and delegates to codex-handle-hook. Direct Elisp callers can call codex-handle-hook with a hook type (e.g., "Stop", "PreToolUse"), a buffer name, hook JSON data, and optional additional arguments. It constructs a plist and runs codex-event-hook with it until the first handler returns non-nil. Hooks marked for notification, currently "Stop", also trigger a notification (Notifications).

Before user hook handlers run, codex-handle-hook also updates the target buffer’s transcript metadata. When hook JSON includes an explicit transcript path, that path is recorded directly. When only a session id is available, codex.el looks up the matching JSONL file under codex-transcript-sessions-directory and caches successful lookups so later hooks for the same session do not rescan the whole sessions tree. If codex-transcript-catch-up-on-stop is enabled, Stop events can repair the final recorded agent message internally; by default this automatic repair is disabled to avoid racing the transcript writer.

Transient menus

codex.el provides two transient menus for convenient access to its commands.

The transient codex-transient is the main command menu (titled “Codex Menu”), organized into five columns: Start/Stop Codex, Send Commands, Manage Codex, Quick Responses, and Model & Config. The Model & Config column contains transient infixes that let you change codex-model, codex-reasoning-effort, codex-sandbox-mode, codex-approval-policy, and codex-profile on the fly without modifying your configuration. These infixes use two-key sequences prefixed with g (e.g. g m for model, g e for reasoning effort, g s for sandbox mode, g a for approval policy, g p for profile).

The transient codex-slash-commands provides quick access to all Codex CLI slash commands, organized into five groups: Core (help, clear, compact, status, new, quit), Navigation & Review (diff, review, fork, resume, copy), Configuration (permissions, model, fast, plan, init, statusline, theme, debug config), Features & Tools (experimental, MCP, agent, apps, mention, ps), and Account & Identity (logout, personality, feedback).

Both transients are available from the codex-command-map keymap, bound to m and / respectively.

Keymap

The codex-command-map keymap provides quick access to all commands. You should bind this map to a prefix key of your choice, for example:

(global-set-key (kbd "C-c x") codex-command-map)

The default bindings are:

KeyCommand
ccodex
dcodex-start-in-directory
Rcodex-resume
fcodex-fork
icodex-new-instance
kcodex-kill
Kcodex-kill-all
scodex-send-command
xcodex-send-command-with-context
rcodex-send-region
ocodex-send-buffer-file
Icodex-send-image
ecodex-fix-error-at-point
/codex-slash-commands
tcodex-toggle
bcodex-switch-to-buffer
Bcodex-select-buffer
lcodex-redraw
zcodex-toggle-read-only-mode
Mcodex-cycle-permissions
ycodex-send-return
ncodex-send-escape
Ecodex-edit-previous-message
TABcodex-queue-followup
1codex-send-1
2codex-send-2
3codex-send-3
mcodex-transient

Minor mode

The global minor mode codex-mode auto-configures the Codex CLI hooks system by ensuring that config.toml and hooks.json are set up correctly (Hooks integration). The mode also adds a Codex lighter to the mode line.

Activate the mode with:

(codex-mode 1)

Or add it to your init file to configure hooks on startup.

Hooks system

The Codex CLI supports a hooks mechanism that notifies external programs of lifecycle events. codex.el takes advantage of this by shipping a bin/codex-hook-wrapper shell script that calls emacsclient to relay events from Emacs-owned Codex sessions back to the Emacs server that enabled codex-mode.

When codex-enable-hooks is non-nil and codex-mode is activated, codex.el automatically:

  1. Ensures that config.toml has hooks = true under the [features] section.
  2. Ensures that hooks.json has entries for all eight supported hook types: Stop, SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, PreCompact, and PostCompact.

Each hook entry points to the codex-hook-wrapper script, which ignores sessions without CODEX_BUFFER_NAME and otherwise reads JSON from stdin into a private temporary file before asking emacsclient to pass that file to codex-handle-hook. Existing user-defined hooks in hooks.json are preserved; codex.el appends its own entries if they are absent and repairs them if their matcher, command, type, or timeout drifts.

You can respond to these events by adding functions to codex-event-hook (Emacs hooks).

Indices

Function index

Variable index