Build codex-ide.nvim as a real Neovim Codex IDE client by integrating with
codex app-server, not by wrapping the terminal UI or calling the raw OpenAI API
directly.
The app-server protocol is the closest available interface to the official IDE extension model. It exposes JSON-RPC methods and notifications for Codex-native concepts such as threads, turns, items, reviews, approvals, filesystem access, account state, model selection, and streaming updates.
The first version should prioritize the Codex-facing architecture and basic end-to-end IDE flows. Chat polish can come later.
- Use
codex app-server --listen stdio://as the primary runtime integration. - Implement the plugin core in Lua and keep Neovim as the main runtime.
- Use generated app-server JSON schemas as the protocol reference.
- Use
snacks.nvimas the required UI foundation for pickers, floating panels, notifications, and layout primitives. - Do not build v1 around the Python Codex SDK. It is useful as a reference, but the documented SDK is experimental and expects a local Codex repository checkout.
- Do not build v1 around the TypeScript SDK either. It can serve as a reference or future test harness, but requiring Node for the plugin core would add an unnecessary second runtime.
- Treat Agents SDK concepts as background only. The important ideas are tools, MCP, handoffs, guardrails, sessions, streaming events, tracing, and human approval flows, but this plugin should mirror Codex app-server concepts first.
- Done: spawn and stop
codex app-server --listen stdio://. - Done: send
initializewithclientInfo.name = "codex_nvim". - Done: implement newline-delimited JSON-RPC over stdio.
- Done: implement request/response correlation.
- Done: dispatch server notifications by method name.
- Done: detect server-to-client requests and return
method not foundfor unimplemented handlers. - Done: add LuaLS annotations for key transport/client protocol shapes.
- Done: add basic lifecycle commands:
:CodexStart:CodexStop:CodexStatus
- Done: implement thread APIs:
thread/startthread/resumethread/listthread/read
- Done: implement turn APIs:
turn/startturn/interrupt
- Done: render basic streaming conversation output from app-server events.
- Done: track important notifications:
thread/*turn/*item/*errorwarning- token usage and status updates
- Done: build a basic
snacks.nvimchat/sidebar surface. - Done: add commands:
:CodexChat:CodexNew [prompt]:CodexSend [prompt]:CodexThreads:CodexRead [thread_id]:CodexInterrupt
- Verified: app-server initialization, thread creation, thread listing, and a
real
turn/startsmoke test that streamed state back into Neovim.
- Improve commands that mirror official IDE extension intent:
- refine open Codex panel behavior
- refine start new chat/thread behavior
- refine resume thread behavior
- attach current file
- attach visual selection
- implement selected TODO
- review current changes
- Add model selection through
model/list. - Add reasoning effort controls.
- Add approval mode controls.
- Replace the temporary
vim.ui.selectthread picker with a propersnacks.nvimpicker/history surface. - Add persistent user config for default model, effort, approval mode, and sandbox/permission preferences.
- Add basic status metadata in the chat surface: model, cwd, active turn, thread id, and token usage.
- Improve the chat feed renderer:
- separate turns with user-message blocks
- keep normal
agentMessagetext unboxed - render non-text activity as boxed feed items, including reasoning, plans, commands, file changes, MCP/dynamic tools, web search, images, review mode, context compaction, and hook prompts
- reuse boxed styling later for synthetic plugin/system events such as auth, app-server disconnects, model switches, approvals, and MCP server status
- Implement
review/start. - Render
turn/diff/updatedand file-change events. - Handle approval server requests for:
- command execution
- file changes
- permission changes
- MCP elicitation
- tool user input
- Route approve and deny actions through native Neovim UI.
- Use the transport
ASYNCsentinel for approval requests that require user interaction before responding to app-server.
- Treat CLI "IDE data" as editor-provided context: current file, current
selection, open files, active editor metadata, and similar context used by
/ideor auto-context. - First implement explicit context attachments through app-server turn input items and mention-style payloads.
- Later investigate the CLI local IDE context IPC path so the standalone Codex TUI can request context from Neovim as well.
The repository now has a working Phase 1 and Phase 2 implementation.
Implemented files:
lua/codex_ide/config.lualua/codex_ide/transport.lualua/codex_ide/client.lualua/codex_ide/thread.lualua/codex_ide/ui/chat.lualua/codex_ide/commands.lualua/codex_ide/init.luaplugin/codex_ide.lua
Documentation files:
PLAN.mdCOMMUNICATION.md
The current plugin can:
- start and initialize app-server
- create a Codex thread
- list existing threads
- resume/read a thread
- send a prompt as a turn
- receive streamed assistant deltas
- track thread/turn/item state
- open a basic chat window
- interrupt an active turn
- Context attachment module:
- current file as a Codex input item
- visual selection as a Codex input item
- stable formatting for file path, range, and selected text
- Picker module:
- proper
snacks.nvimthread picker - model picker from
model/list - approval mode picker
- reasoning effort picker
- proper
- UI improvements:
- better chat buffer rendering
- active model/cwd/thread metadata
- active turn indicator
- token usage display
- clearer warning/error rendering
- Approval module:
- map app-server approval request methods
- show native approval UI
- respond with app-server-compatible approval payloads
- Review module:
- start review from current thread
- target current git changes
- render review results and diffs
- Tests:
- lightweight Lua tests for JSON-RPC routing
- state update tests for item deltas
- command smoke tests
- context payload construction tests
- Done:
lua/codex_ide/config.lua: user config and defaults. - Done:
lua/codex_ide/transport.lua: app-server process and JSON-RPC transport. - Done:
lua/codex_ide/client.lua: app-server method wrappers and event dispatch. - Done:
lua/codex_ide/thread.lua: thread state and thread operations. - Remaining:
lua/codex_ide/context.lua: current file and visual selection attachment. - Remaining:
lua/codex_ide/review.lua: review entry points. - Remaining:
lua/codex_ide/approval.lua: approval request handling. - Remaining:
lua/codex_ide/ui/init.lua: UI coordination. - Done:
lua/codex_ide/ui/chat.lua: basic conversation surface. - Remaining:
lua/codex_ide/ui/pickers.lua: snacks-backed pickers. - Done:
lua/codex_ide/commands.lua: user commands. - Done:
plugin/codex_ide.lua: thin plugin entrypoint.
- Done: verify app-server startup and
initialize. - Generate schemas with:
codex app-server generate-json-schema --experimental --out /tmp/codex-schema- Smoke-test implementation flows:
- Done: create a thread
- Done: send a prompt
- Done: stream assistant response
- Done: list threads
- Partial: resume/read a thread
- Remaining: attach current file
- Remaining: attach visual selection
- Done: interrupt a turn
- Remaining: start review
- Remaining: answer an approval request
- Add Lua unit tests for:
- JSON-RPC framing
- request correlation
- notification dispatch
- context attachment payload construction
codex app-serveris the correct foundation because it is the Codex interface exposed for IDE and app integrations.snacks.nvimremains the required UI dependency.- v1 should prioritize local Codex IDE parity over cloud delegation.
- Cloud tasks, image generation polish, realtime voice, and full CLI
/ideIPC compatibility are later features.