A small Neovim plugin for running and resuming the Codex CLI in a configurable Neovim terminal window.
Requires Neovim 0.12 or later.
The complete default configuration is:
---@type mini.codex.Config
local DEFAULT_CONFIG = {
daemon = true,
win = {
win = 0,
split = "right",
vertical = true,
width = math.max(1, math.floor(vim.o.columns * 0.5)),
},
input = {
enabled = false,
pin = true,
prompt = "",
win = {
win = 0,
split = "below",
},
keymap = {
jump = "<C-g>",
prev = "<M-p>",
next = "<M-n>",
},
lsp = true,
lsp_cmd = "codex-prompt-lsp",
},
output = {
enabled = false,
win = {
win = 0,
split = "right",
vertical = true,
},
keymap = {
toggle = "<C-t>",
refresh = "<C-r>",
prev = "<M-p>",
next = "<M-n>",
detail = "<CR>",
},
},
}
Set daemon = false to start Codex with --no-daemon, running the terminal
session without the shared background app-server. Disabling the daemon requires
Codex 0.154.0 or later.
Customize it only when needed by passing configuration tables to setup(). The win table is passed directly to nvim_open_win(), so it can also define a floating window.
---@type mini.codex.Config
local opts = {
win = {
relative = "editor",
row = 2,
col = 4,
width = 80,
height = 30,
style = "minimal",
border = "rounded",
},
}
require("mini.codex").setup(opts)
The window label is automatically Codex [session-id].
Codex’s built-in Vim mode is too limited for full Neovim editing workflows, so mini.codex offers an optional input pane backed by a real normal buffer. It is not loaded or opened by default. Enable it with an input table; mini.codex divides the Codex window into an upper terminal and lower input buffer.
By default, the input opens below the Codex window with a height of 30% of the main window. The win table is passed directly to nvim_open_win(), so split and floating layouts, dimensions, position, and appearance are controlled by native Neovim window configuration. For a floating Codex window, the default input follows the main window’s position, width, and 30% height; use relative = "win" for the same behavior with a custom floating configuration. An explicitly positioned relative = "editor" configuration is kept unchanged. Resizing one split follows Neovim’s native behavior.
The buffer uses the markdown.codex filetype, allowing the codex-prompt-lsp Neovim adapter to attach automatically and provide completions. The adapter is optional; mini.codex does not depend on it.
If you are migrating from ishi-o/nvim-codex-lsp, change the plugin source to
ishi-o/codex-prompt-lsp; the Neovim adapter’s require("nvim-codex-lsp")
module name remains unchanged.
Enter behaves normally, so it inserts a newline in insert mode and never submits to Codex.<C-g>) opens the mapping input with Codex’s complete current draft. Press it again to replace Codex’s draft with the edited text and return to the terminal.<M-p> and <M-n>) use Codex’s own Up/Down prompt history and load the selected prompt into the mapping input.Synchronization uses Codex’s external-editor support inside the current Neovim instance. The plugin sets VISUAL only for the Codex process.
The input pane automatically attaches the editor-neutral
codex-prompt-lsp --stdio executable when it is available. Install
codex-prompt-lsp with npm or Mason; no additional configuration is needed:
---@type mini.codex.Config
local opts = {
input = {
enabled = true,
},
}
require("mini.codex").setup(opts)
This standalone integration provides the server’s completions and hover
information. It deliberately does not enable the Neovim adapter’s mention
highlighting or atomic completion deletion. The lsp option defaults to
true, but has no effect when nvim-codex-lsp can be loaded: mini.codex
always leaves server startup to that adapter. The adapter provides the richer
integration, including Codex buffer detection, mention highlighting, and
atomic completion deletion. Set lsp = false to disable standalone startup,
or set lsp_cmd when the executable is not named codex-prompt-lsp.
Enable and configure it with the input table. Set input.enabled = false to disable it again:
---@type mini.codex.Config
local opts = {
input = {
enabled = true,
pin = true, -- keep the input pane visible when it is not focused
prompt = "",
win = {
win = 0,
split = "below",
height = math.max(1, math.floor(vim.o.lines * 0.3)),
},
keymap = {
jump = "<C-g>", -- key that synchronizes and switches inputs
prev = "<M-p>", -- select the previous Codex prompt
next = "<M-n>", -- select the next Codex prompt
},
lsp = true, -- attach codex-prompt-lsp --stdio when available
lsp_cmd = "codex-prompt-lsp",
},
}
require("mini.codex").setup(opts)
mini.codex.Config, mini.codex.InputConfig, mini.codex.OutputConfig, mini.codex.OutputChatTurnKind, and mini.codex.OutputChatTurnLabel are exported LuaLS annotations. win uses Neovim’s vim.api.keyset.win_config, so native window fields also receive completion and diagnostics.
The optional output preview displays one complete chat from the active Codex session in a dedicated read-only window. It is disabled by default. User and assistant messages are shown in full; every other internal turn is compacted to its type, state, and a short description for fast rendering. Each turn uses a # heading and no horizontal separator.
Enable it with an output table:
---@type mini.codex.Config
local opts = {
output = {
enabled = true,
win = {
relative = "editor",
row = 2,
col = 4,
width = 80,
height = 30,
style = "minimal",
border = "rounded",
},
keymap = {
toggle = "<C-t>",
refresh = "<C-r>",
prev = "<M-p>", -- show the previous chat
next = "<M-n>", -- show the next chat
detail = "<CR>", -- show or dismiss the turn under the cursor
},
},
}
require("mini.codex").setup(opts)
The output.win table uses Neovim’s native window configuration. By default, the preview is a split to the right of the Codex window, with a width of 50% of the Codex window’s width and the same height. When both input and output are enabled, the preview occupies the full right column, while the Codex window stays above the input pane on the left. The combined region keeps the bounds that the Codex/input stack had before the preview opened. An explicit split, win, width, or height is respected, including left-side and horizontal splits. For a floating preview, use relative = "editor" with the desired position and dimensions. Toggling preserves the surrounding layout, the main window view, and preview sizes changed manually after opening. The refresh key (default <C-r>) reloads the session while preserving the selected chat when possible. Put the cursor on a turn and press the detail key (default <CR>) to load only that turn’s full database record; press it again to return to the compact chat.
:Codex # toggle codex window
:Codex toggle # toggle codex window
:Codex new # new a codex session
:Codex last # codex resume --last
:Codex pick # pick a session
:Codex prev # previous session, pick the last if there is no active session now
:Codex next # next session
:Codex stop # close current session
:CodexDaemon enable # use the shared daemon for future Codex sessions
:CodexDaemon disable # start future Codex sessions with --no-daemon
:CodexDaemon restart # restart the shared app-server daemon
Session and output navigation read Codex’s local $CODEX_HOME/state_5.sqlite and $CODEX_HOME/thread_history_1.sqlite databases, falling back to ~/.codex/.