4.6 KiB
4.6 KiB
Codex ACP Session Persistence & Resume Investigation
Summary
- PR #66 adds real session persistence to
@zed-industries/codex-acp: CLI flags/env vars enable it, and each session is persisted in${CODEX_HOME}/sessions/manifest.jsonlwith rollout paths, MCP servers, cwd, approval/mode settings, and timestamps.loadSessionpulls that manifest entry, restores MCP config, and callsConversationManager::resume_conversation_from_rolloutwith the saved rollout JSONL. Internal state resumes correctly. - The ACP protocol surface still only returns mode/model selectors during
loadSession(codex-acp/src/conversation.rs:1585-1650). Historical chat updates are not replayed:ConversationActor::handle_loadnever emits priorSessionUpdates, and the event dispatcher drops any replay stream because there’s no active submission entry to consume it (codex-acp/src/conversation.rs:1830-1840). Clients are expected to have stored the transcript themselves. - Our voice-dev server currently treats Codex as non-resumable (
supportsSessionPersistence: falseinpackages/server/src/server/acp/agent-types.ts).AgentManageronly attemptsloadSessionfor Claude agents, so Codex sessions that the app starts get lost once the daemon dies. Agents launched outside the app aren’t tracked anywhere either. - For CloudCode we solved this by forking the ACP package to replay history and by persisting agent metadata (session ids, rollout paths) in
agents.json. Codex’s manifest already contains the same data; we can read it after eachnewSessionand store it alongside the agent entry. On restart we can resume by calling/session/loadwith that data and replaying the rollout ourselves to rebuild UI history.
Key Details
- CLI & Manifest (PR #66)
codex-acp/src/cli.rsparses--session-persist,--session-persist=<dir>,--no-session-persist, and the env varsCODEX_SESSION_PERSIST/CODEX_SESSION_DIR.SessionPersistClifeeds intoSessionPersistenceSettings::resolve, defaulting to${CODEX_HOME}/sessions(codex-acp/src/session_store.rs:55-94).SessionRecordcaptures session id, conversation id, rollout path, cwd, MCP server definitions (including HTTP headers), model/mode ids, approval/sandbox policies, reasoning effort, and timestamps (codex-acp/src/session_store.rs:21-90).SessionStorewrites JSONL manifest entries and exposesrecord_session,update_model,update_mode, etc.
- Resume Flow
- When a new session is created, Codex ACP records a manifest entry before returning (
codex-acp/src/codex_agent.rs:373-414). - On resume, Codex ACP reads the manifest, clones the saved MCP config/cwd, feeds it to
ConversationManager::resume_conversation_from_rollout, and updates the manifest (codex-acp/src/codex_agent.rs:415-498). ConversationManagerloads the rollout history viaRolloutRecorder::get_rollout_historyand spawns Codex with that history (codex-rs/core/src/conversation_manager.rs:128-177), so Codex internally has all previous turns.
- When a new session is created, Codex ACP records a manifest entry before returning (
- History Replay Gap
ConversationActor::handle_loadsimply returnsLoadSessionResponse { modes, models }; no previousSessionUpdates are sent (codex-acp/src/conversation.rs:1585-1650).- The conversation event loop only routes events to active submissions stored in
self.submissions; replaying the rollout would immediately warn “unknown submission ID” and drop everything (codex-acp/src/conversation.rs:1830-1840). Result: clients must retain chat logs themselves.
- Voice-dev State
AgentManageronly considers Claude resumable becausesupportsSessionPersistenceis false for Codex (packages/server/src/server/acp/agent-types.ts:33-67).AgentPersistencewritesagents.jsonfor app-started agents but currently stores only Claude’s session ids; Codex sessions disappear once the process exits (packages/server/src/server/acp/agent-persistence.ts:1-89).
Next Steps (not implemented yet)
- Install/run Codex ACP from PR #66 (or the author’s fork) with
--session-persistso every session we start writes a manifest entry. - Extend our agent persistence to capture Codex session metadata (session id + rollout path + cwd + MCP servers) by reading Codex’s manifest immediately after
newSessionsucceeds. - Flip Codex’s
supportsSessionPersistenceflag and teachAgentManagerto call/session/loadfor persisted Codex agents, replaying history ourselves by parsing the saved rollout (mirroring our Claude fork). - Expose resume UI/UX for Codex agents started from the app; later we can explore listing Codex’s manifest directly for sessions started outside voice-dev.