Purpose: This document describes the JSON-RPC 2.0 API methods exposed by codex-app-server for managing thread and turn lifecycles. These APIs power IDE extensions and other clients that need to create, resume, fork, list, and control conversations with the Codex agent.
Scope: This page covers thread lifecycle operations (thread/start, thread/resume, thread/fork, thread/list, thread/archive, etc.) and turn lifecycle operations (turn/start, turn/interrupt, turn/steer). For general app server architecture and initialization, see App Server and IDE Integration. For event streaming and notifications, see Event Translation and Streaming.
The API exposes three hierarchical primitives:
| Primitive | Description | Lifespan | Identifier |
|---|---|---|---|
| Thread | A conversation between user and agent | Persisted in $CODEX_HOME/sessions/<thread_id>.jsonl | ThreadId (e.g. "thr_123") |
| Turn | One round-trip exchange in the conversation | Begins with user input, ends with agent completion or interruption | Embedded in thread as turn_id |
| Item | Individual message, tool call, or event within a turn | Duration of turn execution | item.id within turn context |
Sources: codex-rs/app-server/README.md46-53 codex-rs/app-server-protocol/src/protocol/v2.rs1-1000
Sources: codex-rs/app-server/src/codex_message_processor.rs497-535
thread/startCreates a new thread with optional configuration overrides. The server generates a unique ThreadId, persists a rollout file, and auto-subscribes the connection to turn/item events.
Request Handler: CodexMessageProcessor::thread_start codex-rs/app-server/src/codex_message_processor.rs789-1012
Key Parameters:
model: Override default model (e.g. "gpt-5.1-codex")cwd: Working directory for the sessionapprovalPolicy: "untrusted" | "on-request" | "never"sandboxPolicy: Sandbox configuration (see Sandbox and Approval Policies)personality: "friendly" | "pragmatic" | "none"dynamicTools: Array of dynamic tool specifications (experimental)persistExtendedHistory: Persist richer ThreadItems for lossless resume (experimental)Response: Returns Thread object with id, preview, modelProvider, createdAt
Emits: thread/started notification to the connection
Implementation Flow:
Sources: codex-rs/app-server/src/codex_message_processor.rs789-1012 codex-rs/app-server-protocol/src/protocol/v2.rs186-189
thread/resumeReopens an existing thread by loading its rollout file from disk. Subsequent turn/start calls append to the loaded history.
Request Handler: CodexMessageProcessor::thread_resume codex-rs/app-server/src/codex_message_processor.rs1014-1175
Key Parameters:
threadId: Existing thread identifier (e.g. "thr_123")thread/start)Implementation:
find_thread_path_by_id_str to locate rollout file codex-rs/app-server/src/codex_message_processor.rs1028-1042find_archived_thread_path_by_id_str if not found in active sessionsInitialHistory::ResumeWithConversationIdThreadManager::create_thread with resume parametersResponse: Same Thread object structure as thread/start
No notifications emitted (unlike thread/start, thread/resume does not emit thread/started)
Sources: codex-rs/app-server/src/codex_message_processor.rs1014-1175 codex-rs/app-server/README.md194-202
thread/forkCreates a new thread by copying the history from an existing thread. The new thread receives a fresh ThreadId and can diverge independently.
Request Handler: CodexMessageProcessor::thread_fork codex-rs/app-server/src/codex_message_processor.rs1177-1344
Parameters:
threadId: Source thread to fork frompersistExtendedHistory: Same as thread/start (experimental)Implementation:
InitialHistory::ForkFromRollout with source path and new ThreadIdResponse: Returns new Thread with different id than source
Emits: thread/started notification for the new thread
Sources: codex-rs/app-server/src/codex_message_processor.rs1177-1344 codex-rs/app-server/README.md204-210
thread/listPaginated listing of persisted threads with filtering and sorting options.
Request Handler: CodexMessageProcessor::thread_list codex-rs/app-server/src/codex_message_processor.rs2036-2363
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | null | null | Opaque pagination cursor from previous response |
limit | usize | 25 | Page size (max 100) |
sortKey | "created_at" | "updated_at" | "created_at" | Sort criterion |
modelProviders | string[] | all | Filter by provider IDs |
sourceKinds | ThreadSourceKind[] | interactive only | Filter by session source |
archived | boolean | false | List archived vs active threads |
cwd | string | any | Filter by exact working directory |
Constants: codex-rs/app-server/src/codex_message_processor.rs266-267
Implementation:
SessionMetaLine from rollout files codex-rs/app-server/src/codex_message_processor.rs2121-2179compute_source_filters and source_kind_matches codex-rs/app-server/src/codex_message_processor.rs2190-2195created_at or updated_at using file metadata codex-rs/app-server/src/codex_message_processor.rs2214-2243ConversationSummary objects with id, preview, modelProvider, timestampsResponse:
Sources: codex-rs/app-server/src/codex_message_processor.rs2036-2363 codex-rs/app-server/README.md215-244
thread/loaded/listReturns thread IDs currently loaded in the ThreadManager's in-memory cache.
Request Handler: CodexMessageProcessor::thread_loaded_list codex-rs/app-server/src/codex_message_processor.rs2365-2385
Parameters: None
Response:
Use Case: Useful for IDE extensions to check which threads are active without scanning disk.
Sources: codex-rs/app-server/src/codex_message_processor.rs2365-2385 codex-rs/app-server/README.md246-254
thread/readReads a thread's metadata and optionally its full turn history without activating it.
Request Handler: CodexMessageProcessor::thread_read codex-rs/app-server/src/codex_message_processor.rs2387-2510
Parameters:
threadId: Thread to readincludeTurns: Boolean flag to load full rollout historyImplementation:
includeTurns is false, reads only SessionMetaLine for preview codex-rs/app-server/src/codex_message_processor.rs2402-2408true, reads full rollout and builds turns via build_turns_from_rollout_items codex-rs/app-server/src/codex_message_processor.rs2410-2503Response: Thread object with turns array populated if requested
Sources: codex-rs/app-server/src/codex_message_processor.rs2387-2510 codex-rs/app-server/README.md256-268
thread/archiveMoves a thread's rollout file from $CODEX_HOME/sessions/ to $CODEX_HOME/archived_sessions/.
Request Handler: CodexMessageProcessor::thread_archive codex-rs/app-server/src/codex_message_processor.rs1346-1425
Parameters: threadId
Implementation:
find_thread_path_by_id_strstd::fs::rename codex-rs/app-server/src/codex_message_processor.rs1382-1394Response: Empty {} on success
Note: Archived threads do not appear in thread/list unless archived: true is specified.
Sources: codex-rs/app-server/src/codex_message_processor.rs1346-1425 codex-rs/app-server/README.md270-279
thread/unarchiveRestores an archived thread to the active sessions directory.
Request Handler: CodexMessageProcessor::thread_unarchive codex-rs/app-server/src/codex_message_processor.rs1582-1676
Parameters: threadId
Implementation: Reverse of thread/archive - moves from archived_sessions/ back to sessions/
Response: Returns restored Thread object
Sources: codex-rs/app-server/src/codex_message_processor.rs1582-1676 codex-rs/app-server/README.md281-288
thread/name/setSets or updates a user-facing name for a thread. Names are persisted in a state database.
Request Handler: CodexMessageProcessor::thread_set_name codex-rs/app-server/src/codex_message_processor.rs1427-1480
Parameters:
threadIdname: String (not required to be unique)Storage: Uses StateDbHandle::get_state_db and updates via db.set_thread_name codex-rs/app-server/src/codex_message_processor.rs1449-1472
Response: Empty {} on success
Emits: thread/nameUpdated notification to subscribed connections codex-rs/app-server/src/codex_message_processor.rs1474-1478
Sources: codex-rs/app-server/src/codex_message_processor.rs1427-1480 codex-rs/app-server/README.md124
thread/rollbackDrops the last N turns from a thread's in-memory context and persists a rollback marker in the rollout.
Request Handler: CodexMessageProcessor::thread_rollback codex-rs/app-server/src/codex_message_processor.rs1678-1785
Parameters:
threadIdtoTurnId: Target turn ID to roll back toImplementation:
Op::Rollback operation to thread codex-rs/app-server/src/codex_message_processor.rs1738-1743Response: Returns updated Thread with turns populated showing remaining turns
Sources: codex-rs/app-server/src/codex_message_processor.rs1678-1785 codex-rs/app-server/README.md128
thread/compact/startTriggers manual conversation history compaction to reduce token usage.
Request Handler: CodexMessageProcessor::thread_compact_start codex-rs/app-server/src/codex_message_processor.rs1482-1529
Parameters: threadId
Implementation:
Op::Compact operation codex-rs/app-server/src/codex_message_processor.rs1500-1504{}item/started, item/completed notificationsResponse: Empty {} (compaction happens asynchronously)
Emits:
item/started with item.type = "contextCompaction"item/completed when compaction finishesSources: codex-rs/app-server/src/codex_message_processor.rs1482-1529 codex-rs/app-server/README.md290-304
thread/backgroundTerminals/clean (Experimental)Terminates all running background terminals associated with a thread.
Request Handler: CodexMessageProcessor::thread_background_terminals_clean codex-rs/app-server/src/codex_message_processor.rs1531-1580
Parameters: threadId
Requirements: Requires capabilities.experimentalApi = true in initialize
Implementation: Submits Op::CleanBackgroundTerminals to the thread
Response: Empty {} when cleanup request is accepted
Sources: codex-rs/app-server/src/codex_message_processor.rs1531-1580 codex-rs/app-server/README.md402-411
Sources: codex-rs/app-server-protocol/src/protocol/v2.rs1-100
turn/startInitiates a new turn by submitting user input to a thread and triggering agent generation.
Request Handler: CodexMessageProcessor::turn_start codex-rs/app-server/src/codex_message_processor.rs3168-3458
Request Structure:
User Input Types codex-rs/app-server-protocol/src/protocol/v2.rs1230-1305:
| Type | Fields | Use Case |
|---|---|---|
text | text: string | Plain text message |
image | url: string | Remote image URL |
localImage | path: string | Local file path |
skill | name: string, path: string | Explicit skill invocation |
mention | name: string, path: string | App/connector mention |
Implementation Flow:
Configuration Normalization: If collaborationMode.settings.developer_instructions is null, the handler looks up built-in instructions from ThreadManager::list_collaboration_modes codex-rs/app-server/src/codex_message_processor.rs408-425
Response: Initial Turn object with id, status: "inProgress", empty items array
Emits:
turn/started notification with initial turn stateitem/started, item/delta, item/completed notificationsturn/completed notification with final status and token usageSources: codex-rs/app-server/src/codex_message_processor.rs3168-3458 codex-rs/app-server/README.md306-346
turn/interruptCancels a running turn by requesting cancellation of active subprocesses.
Request Handler: CodexMessageProcessor::turn_interrupt codex-rs/app-server/src/codex_message_processor.rs3577-3637
Parameters:
threadIdturnId: The active turn to interruptImplementation:
load_thread codex-rs/app-server/src/codex_message_processor.rs3586-3587Op::Interrupt { turn_id } codex-rs/app-server/src/codex_message_processor.rs3589-3593Response: Empty {} on success
Cleanup: The thread emits turn/completed with status: "interrupted" when cleanup finishes. Clients should wait for this notification before considering the turn fully stopped.
Sources: codex-rs/app-server/src/codex_message_processor.rs3577-3637 codex-rs/app-server/README.md388-400
turn/steerAppends additional user input to an already in-flight turn without starting a new turn.
Request Handler: CodexMessageProcessor::turn_steer codex-rs/app-server/src/codex_message_processor.rs3460-3575
Parameters:
threadIdinput: Array of UserInput (same types as turn/start)expectedTurnId: Required; must match the current active turnValidation: If no turn is active or expectedTurnId doesn't match, returns JSON-RPC error with code INVALID_REQUEST_ERROR_CODE codex-rs/app-server/src/codex_message_processor.rs3493-3571
Implementation:
expectedTurnIdOp::SteerInput with new input itemsSteerInputError::NotReady by returning error to clientResponse: { turnId: string } - confirms the turn that accepted the input
Does not emit: turn/started (input is appended to existing turn)
Sources: codex-rs/app-server/src/codex_message_processor.rs3460-3575 codex-rs/app-server/README.md413-428
All thread and turn APIs follow JSON-RPC 2.0 error conventions:
Common Error Codes:
| Code | Constant | Meaning |
|---|---|---|
-32600 | INVALID_REQUEST_ERROR_CODE | Invalid parameters or request structure |
-32603 | INTERNAL_ERROR_CODE | Server-side failure |
Thread Not Found: Returns code: -32600, message: "thread not found: {thread_id}" codex-rs/app-server/src/codex_message_processor.rs350-354
Not Initialized: Returns code: -32600, message: "Not initialized" if client hasn't completed handshake codex-rs/app-server/src/message_processor.rs250-268
Sources: codex-rs/app-server/src/codex_message_processor.rs335-357 codex-rs/app-server/src/error_code.rs1-10
Each transport connection maintains isolated state via ConnectionSessionState:
Source: codex-rs/app-server/src/message_processor.rs131-136
The ThreadStateManager tracks per-thread, per-connection state:
Purpose: Tracks which connections are subscribed to which threads, and which items have been started (to avoid duplicate item/started notifications).
Source: codex-rs/app-server/src/thread_state.rs1-100
When a client calls thread/start, thread/resume, or thread/fork, the connection is automatically subscribed to events from that thread. The subscription is registered in ThreadStateManager::ensure_thread_entry_and_subscribe codex-rs/app-server/src/codex_message_processor.rs746-787
The ThreadWatchManager tracks and broadcasts thread status changes to all subscribed connections. It monitors thread lifecycle events like turn starts, completions, permission requests, and user input requests.
Status Types codex-rs/app-server-protocol/src/protocol/v2.rs1150-1200:
| Status Type | Description | Active Flags |
|---|---|---|
notLoaded | Thread not currently loaded in memory | N/A |
idle | Thread loaded but no active operations | N/A |
active | Thread has ongoing operations | Array of ThreadActiveFlag |
systemError | Thread encountered an error | Error message |
ThreadActiveFlag Variants:
running - Turn is executingpermissionRequested - Waiting for user approvaluserInputRequested - Waiting for user input (tool elicitation)Sources: codex-rs/app-server/src/bespoke_event_handling.rs125-153 codex-rs/app-server/src/thread_status.rs1-300
The ThreadWatchManager uses RAII guards to track temporary states:
This ensures permission flags are automatically cleared even if the approval task is cancelled or panics.
Sources: codex-rs/app-server/src/bespoke_event_handling.rs176-195 codex-rs/app-server/src/thread_status.rs1-100
The resolve_thread_status function computes the current status from active flags:
Called By:
thread_list when populating thread summaries codex-rs/app-server/src/codex_message_processor.rs2250-2280thread_read when returning thread details codex-rs/app-server/src/codex_message_processor.rs2470-2490Sources: codex-rs/app-server/src/thread_status.rs1-150 codex-rs/app-server/src/codex_message_processor.rs2250-2280
thread/status/changedEmitted whenever a thread's status changes. Clients use this to update UI indicators (spinners, approval badges, etc.).
Example Notification:
Sources: codex-rs/app-server-protocol/src/protocol/v2.rs1150-1200 codex-rs/app-server/README.md256-268
Event Processing Architecture
Event Processing: apply_bespoke_event_handling translates core EventMsg types to protocol notifications codex-rs/app-server/src/bespoke_event_handling.rs107-523
Status Tracking: ThreadWatchManager monitors turn lifecycle and broadcasts thread/status/changed notifications codex-rs/app-server/src/thread_status.rs1-300
Listener Filtering: ThreadScopedOutgoingMessageSender only sends to connections subscribed to that thread codex-rs/app-server/src/outgoing_message.rs54-108
Connection Queues: OutgoingMessageSender maintains per-connection bounded queues with backpressure codex-rs/app-server/src/outgoing_message.rs1-250
Sources: codex-rs/app-server/src/bespoke_event_handling.rs107-200 codex-rs/app-server/src/thread_status.rs1-150 codex-rs/app-server/src/outgoing_message.rs54-108
| Function | Purpose | Location |
|---|---|---|
ThreadWatchManager::note_turn_started | Mark thread as running | codex-rs/app-server/src/thread_status.rs1-100 |
ThreadWatchManager::note_turn_completed | Clear running flag | codex-rs/app-server/src/thread_status.rs1-100 |
ThreadWatchManager::note_permission_requested | Add permissionRequested flag, return guard | codex-rs/app-server/src/thread_status.rs1-100 |
ThreadWatchManager::note_user_input_requested | Add userInputRequested flag, return guard | codex-rs/app-server/src/thread_status.rs1-100 |
resolve_thread_status | Compute status from active flags | codex-rs/app-server/src/thread_status.rs1-150 |
Component Relationships
| Component | Responsibility | Location |
|---|---|---|
CodexMessageProcessor | Request routing and thread lifecycle | codex-rs/app-server/src/codex_message_processor.rs301-400 |
ThreadManager | Thread creation and registry | codex-core |
CodexThread | Event stream and turn execution | codex-core |
ThreadStateManager | Per-thread listener subscriptions | codex-rs/app-server/src/thread_state.rs1-100 |
ThreadWatchManager | Status tracking and broadcasting | codex-rs/app-server/src/thread_status.rs1-300 |
apply_bespoke_event_handling | Event translation core→protocol | codex-rs/app-server/src/bespoke_event_handling.rs107-200 |
OutgoingMessageSender | Connection-scoped message queuing | codex-rs/app-server/src/outgoing_message.rs1-250 |
Sources: codex-rs/app-server/src/codex_message_processor.rs301-383 codex-rs/app-server/src/thread_state.rs1-100 codex-rs/app-server/src/thread_status.rs1-300
The test suite validates thread and turn operations through integration tests:
| Test Module | Coverage |
|---|---|
tests/suite/v2/thread_start.rs | Thread creation, config overrides, notifications |
tests/suite/v2/thread_resume.rs | Resume from rollout, fallback to archived |
tests/suite/v2/thread_fork.rs | Fork mechanics, history copying |
tests/suite/v2/thread_list.rs | Pagination, filtering, sorting |
tests/suite/v2/thread_archive.rs | Archive/unarchive round-trips |
tests/suite/v2/thread_rollback.rs | Rollback validation |
tests/suite/v2/turn_start.rs | User input handling, streaming |
tests/suite/v2/turn_interrupt.rs | Cancellation, cleanup |
tests/suite/v2/turn_steer.rs | Steer validation, expected turn ID |
Test Helper: McpProcess provides a test harness with helpers like send_thread_start_request, send_turn_start_request codex-rs/app-server/tests/common/mcp_process.rs1-800
Sources: codex-rs/app-server/tests/suite/v2/mod.rs1-31 codex-rs/app-server/tests/common/mcp_process.rs1-100
Refresh this wiki