# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.129.0] - 2026-05-15
### Added
- **100% method coverage** of the Codex app-server v2 JSON Schema. Every method enumerated in `ServerNotification.oneOf` (63) and `ClientRequest.oneOf` (76) is now modeled — 139/139.
- **`cargo run --example schema_coverage`** scorecard tool that walks the upstream JSON Schema bundle, cross-references against the crate's typed surface, and reports `✓` (modeled + sample validates) / `◐` (modeled, no sample yet) / `⚠` (drift) / `✗` (missing) per method. Override the schema path with `CODEX_SCHEMA_PATH=/path/to/freshly-generated.json` to validate against a fresh schema.
- **Typed notification variants** for the 48 previously-unmodeled methods: `item/fileChange/patchUpdated`, `item/plan/delta`, `turn/plan/updated`, `turn/diff/updated`, `item/reasoning/summaryPartAdded`, `item/reasoning/textDelta`, `mcpServer/oauthLogin/completed`, `account/login/completed`, `account/updated`, `app/list/updated`, `command/exec/outputDelta`, `configWarning`, `deprecationNotice`, `externalAgentConfig/import/completed`, `fs/changed`, `fuzzyFileSearch/session{Completed,Updated}`, `guardianWarning`, `hook/{started,completed}`, `item/autoApprovalReview/{started,completed}`, `item/commandExecution/terminalInteraction`, `item/mcpToolCall/progress`, `model/{rerouted,verification}`, `process/{exited,outputDelta}`, `serverRequest/resolved`, `skills/changed`, `thread/{archived,closed,unarchived,compacted,goal/{updated,cleared},name/updated}`, the `thread/realtime/*` family (8 variants), `warning`, `windows/worldWritableWarning`, `windowsSandbox/setupCompleted`. All wired through `Notification::from_envelope()`, `into_envelope()`, and the strict typed-message audit.
- **Method-name constants** for all 70 previously-unmodeled client → server requests under `protocol::methods` (e.g. `THREAD_LIST`, `FS_WRITEFILE`, `COMMAND_EXEC`, `MCPSERVER_TOOL_CALL`, the `plugin/*`, `marketplace/*`, `experimentalFeature/*`, and `account/*` families).
- **`jsonschema` dev-dependency** powering the scorecard's wire-shape validation.
- **Workspace snapshot** of the upstream `codex_app_server_protocol.v2.schemas.json` at `codex-codes/tests/schemas/` so the scorecard runs offline.
### Changed
- Many new notification stubs use `#[serde(transparent)] pub struct Foo(pub Value)` so the wire shape is preserved end-to-end while field-level typing is deferred. Upgrade path is mechanical: replace the `Value` payload with named fields when callers need them; the dispatch surface doesn't change.
### Notes
- **Drift findings surfaced by the scorecard but not fixed here**:
- `PatchChangeKind` in `io/items.rs` is still a bare string enum; upstream moved to an internally-tagged object enum with `{"type":"update","move_path":...}`. Fixing requires regenerating the test fixtures against a live Codex CLI. Root cause of [issue #128](https://github.com/meawoppl/rust-code-agent-sdks/issues/128)'s `unknown variant 'type'` reports.
- `FileUpdateChange` is missing the required `diff: String` field upstream now sends.
- The scorecard reports `1/139 (1%)` with validating samples — only `error`. Sample registry is open to grow in follow-ups; each new sample drift-checks one more method end-to-end.
## [0.128.1] - 2026-05-15
### Added
- **`ParseError` struct** — Carries `raw_line`, `raw_json`, `error_message`, and an optional `method` for parsing failures, mirroring [`claude_codes::ParseError`](https://docs.rs/claude-codes/latest/claude_codes/struct.ParseError.html). Two constructors:
- `ParseError::from_line(line, error)` — for bare-JSON / envelope-shape failures; populates `raw_json` if the line was valid JSON.
- `ParseError::from_envelope(method, params, error)` — for typed-decode failures whose envelope parsed but whose `params` did not match; preserves the JSON-RPC `method` and `params`, and reconstructs a wire-equivalent `raw_line` for bug reports.
- **Regression tests in `tests/integration_tests.rs`** — three new tests that pin the exact code path used by `next_message`, including one reproducing the `missing field "callId"` failure mode from issue #128.
### Changed
- **`Error::Deserialization`** is now `Error::Deserialization(ParseError)` (was `Error::Deserialization(String)`). Code that matched the previous string payload should read `pe.error_message` / `pe.raw_line` / `pe.method` instead. Shipped as a patch — pre-1.0 crate, only this workspace's `cc-proxy` is a known downstream consumer.
- **`AsyncClient::next_message` / `SyncClient::next_message`** — On typed-decode failures (`Notification::from_envelope` / `ServerRequest::from_envelope`), the error now carries the original `method` and `params` via `Error::Deserialization(ParseError)` instead of dropping them in an opaque `Error::Json(serde_json::Error)`. Consumers can render the offending frame for bug reports without snooping `DEBUG`-level tracing for the raw line (fixes #128).
## [0.128.0] - 2026-05-14
Version jumps from 0.101.x into the 0.1xx range that tracks the Codex CLI it
targets (same convention as the sibling `claude-codes` crate, which mirrors
the Claude Code CLI version). Released as `0.128.0` rather than `0.130.0`
intentionally — the bindings have only been validated against a single live
turn so far and the underlying behavior is still evolving; sitting a couple
of patch numbers behind the CLI leaves room to bump in lockstep once the
typed surface is more battle-tested.
### Added
- **Typed message dispatch** — New module [`crate::messages`] introduces closed enums [`Notification`] and [`ServerRequest`] that wrap the per-method param structs. The clients now return the typed [`ServerMessage`] from `next_message()`/`events()` instead of the loose `{ method, params }` shape. Mirrors the [`ContentBlock`]-style dispatch in the sibling `claude-codes` crate: hand-written `Serialize`/`Deserialize` impls inspect the `method` discriminant, route known cases through their typed struct, and route unknown methods to an `Unknown { method, params }` fallback for forward compatibility. Known methods whose payload doesn't fit error loudly — the typing contract is enforced.
- **New typed notifications** — `AccountRateLimitsUpdatedNotification` (`account/rateLimits/updated`), `McpServerStartupStatusUpdatedNotification` (`mcpServer/startupStatus/updated`), `RemoteControlStatusChangedNotification` (`remoteControl/status/changed`). The app-server emits all three during normal operation; previously they fell through to the raw fallback.
- **`RateLimits` / `RateLimitWindow` / `TokenCounts`** — Supporting structs for the above and for the new nested `TokenUsage` shape.
- **`UserMessageItem` / `UserMessageContent`** — Added `ThreadItem::UserMessage` variant for the user-prompt item the app-server emits at the start of each turn (the exec JSONL protocol doesn't typically emit this).
- **Strict typed-message audit test** — `tests/live_client_tests.rs::test_typed_message_audit_strict` runs a real turn and asserts that every notification and server request resolves to a typed variant (no `Unknown`).
### Fixed
- **`ThreadStartedNotification`** — Was `{ thread_id: String }`; the wire actually sends `{ thread: ThreadInfo }` with the full info object.
- **`TurnStartedNotification` / `TurnCompletedNotification`** — Had a top-level `turn_id` field that doesn't exist on the wire (the id lives inside `turn.id`). Both now carry `{ thread_id, turn: Turn }`.
- **`ThreadStatusChangedNotification` / `ThreadStatus`** — Status was modeled as a bare string enum; the wire actually sends an internally-tagged enum (`{"type":"idle"}`, `{"type":"active","activeFlags":[]}`). `ThreadStatus` is now `#[serde(tag = "type")]` with the `Active` variant carrying `active_flags`.
- **`ThreadTokenUsageUpdatedNotification`** — Field was named `usage` but the wire sends `tokenUsage`. The notification also carries `turn_id` which wasn't modeled. Plus the inner `TokenUsage` is actually a wrapper of `{last, total, modelContextWindow}` over a `TokenCounts` struct with `inputTokens`, `outputTokens`, `cachedInputTokens`, `reasoningOutputTokens`, `totalTokens` — restructured accordingly.
- **`ItemStartedNotification` / `ItemCompletedNotification`** — Now include `started_at_ms` / `completed_at_ms` from the wire.
- **`CommandExecutionItem`** — Was snake_case-only (`aggregated_output`, `exit_code`); the app-server protocol uses camelCase. Now carries `#[serde(rename_all = "camelCase")]` with snake_case aliases so both protocols deserialize cleanly. `aggregated_output` is now `Option<String>` since the app-server sends `null` while a command is still in progress.
### Changed (breaking)
- **`ServerMessage` shape** — `ServerMessage::Notification { method, params }` is now `ServerMessage::Notification(Notification)`; `ServerMessage::Request { id, method, params }` is now `ServerMessage::Request { id, request: ServerRequest }`. Update call sites to match on the typed enum variants instead of method-string comparisons.
- **`CommandExecutionItem.aggregated_output`** — Type changed from `String` to `Option<String>` (see above).
- **`TokenUsage`** — Restructured from a flat counts struct to `{last, total, modelContextWindow}` over `TokenCounts`. Old direct field access (`usage.input_tokens`) becomes `usage.last.input_tokens` or `usage.total.input_tokens`.
- **`ThreadStatus`** — Now a `#[serde(tag = "type")]` enum; the `Active` variant has an `active_flags: Vec<Value>` field. Pattern matches need updating.
## [0.101.2] - 2026-05-14
### Fixed
- **Stderr pipe deadlock** — `AsyncClient` and `SyncClient` now drain the app-server's stderr in a background task/thread instead of leaving it pinned to an unread `BufReader`. The Codex CLI emits ~200 KB/s of tracing to stderr, which would fill the ~64 KB kernel pipe within a fraction of a second and block the child process — manifesting as the client hanging on the first non-trivial request. Drained lines are forwarded through the `log` crate at the level encoded in the line (`error!`/`warn!`/`debug!`/`trace!`), with ANSI color codes stripped. INFO tracing (the vast majority of volume) is routed to `trace!` so `RUST_LOG=info` stays quiet by default while WARN/ERROR remain visible.
### Removed
- **`AsyncClient::take_stderr()`** — Replaced by automatic background draining; the method is incompatible with the new design and is removed without a deprecation cycle (no known external callers).
## [0.101.1] - 2026-03-17
### Added
- **Binary path resolution via `which`** — `AppServerBuilder::spawn()` and `spawn_sync()` now resolve non-absolute binary paths using `which` at spawn time, producing a clear `BinaryNotFound` error instead of an opaque OS "file not found" (#102)
- **`Error::BinaryNotFound`** — New error variant for when the CLI binary isn't found on PATH
### Changed
- **`spawn_sync()` return type** — Now returns `crate::error::Result<Child>` instead of `std::io::Result<Child>` for consistent error handling
## [0.101.0] - 2026-02-23
### Added
- **`initialize` handshake** — `AsyncClient::start()` and `SyncClient::start()` now send the required `initialize` request followed by an `initialized` notification before returning, fixing compatibility with Codex CLI 0.104.0+ which requires this handshake before accepting other methods (#87)
- **`InitializeParams`, `InitializeResponse`, `ClientInfo`, `InitializeCapabilities`** — New protocol types for the initialization handshake
- **`AsyncClient::spawn()` / `SyncClient::spawn()`** — Low-level constructors that skip automatic initialization, for callers that need custom `InitializeParams`
- **`AsyncClient::initialize()` / `SyncClient::initialize()`** — Explicit initialization method for use with `spawn()`
- **`methods::INITIALIZE` / `methods::INITIALIZED`** — Method name constants for the initialization handshake
- **`ThreadInfo`** — New struct for thread metadata returned inside `ThreadStartResponse`
- **Integration tests** — Live client tests against a real Codex app-server process (behind `integration-tests` feature flag)
### Changed
- **`ThreadStartResponse`** — Updated to match the actual app-server wire format: now contains a `thread: ThreadInfo` field with the thread ID and metadata, plus optional `model` field. Use `response.thread_id()` to get the thread ID.
### Breaking
- `ThreadStartResponse.thread_id` field replaced by `ThreadStartResponse.thread_id()` method
## [0.100.1] - 2026-02-21
### Changed
- **Replaced `codex exec` with `codex app-server` JSON-RPC protocol** — The crate now wraps `codex app-server --listen stdio://` instead of the one-shot `codex exec --json -`. This enables multi-turn conversations, approval flows, and streaming notifications.
### Added
- **`jsonrpc` module** — JSON-RPC message types (`JsonRpcMessage`, `JsonRpcRequest`, `JsonRpcResponse`, `JsonRpcError`, `JsonRpcNotification`, `RequestId`) matching the app-server wire format (no `"jsonrpc":"2.0"` field)
- **`protocol` module** — App-server v2 protocol types including thread/turn lifecycle params, server notifications, approval flow types, and method name constants
- **`AppServerBuilder`** — Replaces `CodexCliBuilder` for spawning the long-lived app-server process
- **Multi-turn `AsyncClient`** — JSON-RPC client with `thread_start`, `turn_start`, `turn_interrupt`, `thread_archive`, `respond`, and `next_message` methods
- **Multi-turn `SyncClient`** — Blocking counterpart with the same API surface
- **Approval flow support** — `CommandExecutionApprovalParams/Response` and `FileChangeApprovalParams/Response` for handling server-to-client approval requests
- **Streaming delta notifications** — `AgentMessageDeltaNotification`, `CmdOutputDeltaNotification`, `FileChangeOutputDeltaNotification`, `ReasoningDeltaNotification`
- **camelCase serde aliases** on `ThreadItem` variants and status enums for app-server compatibility (snake_case exec format still supported)
- **`Declined` variant** on `CommandExecutionStatus` for commands rejected via approval flow
- **Comprehensive documentation** — Module-level docs with examples, lifecycle guides, error conditions, notification reference tables, and rustdoc examples across all public modules
### Removed
- `CodexCliBuilder` (replaced by `AppServerBuilder`)
- One-shot exec client API
## [0.100.0] - 2026-02-17
### Added
- Initial release of `codex-codes` crate
- Typed Rust bindings for the OpenAI Codex CLI JSON protocol
- `ThreadEvent` and `ThreadItem` types for parsing exec-format JSONL events
- `ThreadOptions` configuration types (`ApprovalMode`, `SandboxMode`, `WebSearchMode`)
- Sync and async clients wrapping `codex exec --json -`
- Feature flags: `types` (WASM-compatible), `sync-client`, `async-client`
- Integration tests with captured protocol message test cases
- Version compatibility checking against installed Codex CLI