## What changed
- Add mouse selection, word and line selection, drag autoscrolling, and keyboard selection with `Ctrl+Space`. Support copying selected text and opening links with a modified click.
- Anchor reading positions and selections to source text so resizing, streaming completion, and history pagination preserve the displayed content. Preserve hard line breaks, indentation, tabs, and graphemes when copying, while excluding display gutters and soft wraps.
- Rejoin activity groups split across history pages while retaining the reader's displayed revision.
- Distinguish confirmed clipboard writes from unconfirmed terminal requests, and retain native clipboard ownership after the transcript overlay closes.
- Manage mouse capture and keyboard modes across overlay transitions, editor handoffs, and suspend/resume.
## Testing
Add regression tests for selection during live updates and pagination, source-text copying across resize, clipboard confirmation and lifetime, and terminal mode restoration.
GitOrigin-RevId: 6b2438f576567cbba755b2405915a25acf009b8d
## Why
Persisted transcripts rendered tool calls individually and displayed reasoning differently from live replay. Enabling raw reasoning also replaced the summary instead of retaining it.
## What changed
- Group computer activity and compatible exploration commands across intervening reasoning, retaining details for the expanded transcript. Respect visible content, command failure boundaries, and turn boundaries.
- Separate paginated history at every turn boundary before filtering hidden items, while adding completion metadata only for successful turns.
- Keep persisted reasoning out of the compact display, preserve hyperlinks in detailed rendering, and append enabled raw reasoning to the summary. Preserve standalone reasoning Markdown in transcript exports.
- Add helpers to rejoin activity groups and attach reasoning across page boundaries using persisted item identities and turn adjacency.
## Testing
Add regression coverage for reasoning replay parity, computer groups split across history pages, turn boundaries, and grouped terminal input. Update export and raw-reasoning tests to verify retained summaries and Markdown.
GitOrigin-RevId: a716db571440f891cc2c6894ae93fbe0e149aed4
## Why
Loaded transcripts reduce several tool calls and file changes to basic status summaries, losing details available in live history cells.
## What changed
- Reuse rich history cells for completed commands, MCP calls, patches, agent activity, image generation, and notices.
- Add dynamic tool cells with bounded output previews while retaining arguments and full output in detailed and raw views.
- Preserve last-known statuses for incomplete calls, unavailable results, and declined or failed operations. Keep legacy command text and terminal interaction output when rich reconstruction is unavailable.
- Remove redundant move annotations from patch diffs and retain patch activity IDs.
- Filter untrusted control characters before emitting terminal scrollback, while preserving semantic hyperlinks.
## Testing
Add unit and snapshot coverage for compact and detailed tool rendering, status fallbacks, retained output, patch restoration, and control-character filtering with and without hyperlinks.
GitOrigin-RevId: 73d754262768cf6d91f3ea4040116bf93cf87784
## Why
Async questions answered on another client should disappear from the TUI without losing drafts for other questions, even when questions have identical titles.
## What changed
- Send answers using the desktop reply envelope with stable per-question IDs, and resolve matching questions from committed messages and replayed history.
- Render replies as readable question-and-answer text in transcripts, queue previews, and input history.
- Preserve separate reply envelopes and message order when retrying rejected or interrupted input.
- Account for JSON escaping in input limits and fall back to plain text for oversized question IDs.
## Testing
Add regression coverage for cross-client dismissal, draft preservation, replay ordering, reply parsing, IDE context, distinct replies with identical text, and retry ordering. Update the async question scenario to use the reply envelope.
GitOrigin-RevId: 9b9e4b1e140508590401622d96cfc16fc192eb7c
## What changed
- Render web activity on one line with width-aware truncation and labels for searches, opened pages, and in-page searches. Preserve all batched queries in full details.
- Show viewed images by filename in chat while retaining their original paths in expanded transcripts and raw output. Use these activity renderers for persisted transcripts and exports.
- Display code-mode tool titles without the `Calling` or `Called` prefix and truncate headers to the available width while preserving full transcript titles and failure details.
- Keep `Returned image` markers inside the originating MCP call, alongside result text, and use the same wording in transcript exports.
## Testing
Add regression tests and snapshots for narrow displays, missing web action details, batched queries, image paths, MCP image results, matching live and replay rendering, and complete web and image details in persisted exports.
GitOrigin-RevId: 5d3f0a0031818c985378ad3ee4b24084d3868c98
## What changed
- Render spoken user prompts with a bold red chevron, preserving its color during live transcript animation. Trim leading whitespace for display while retaining the raw transcript text.
- Underline and link file references such as `src/lib.rs:42` in spoken assistant transcripts using terminal hyperlinks. Preserve existing links and support Windows-style relative separators.
- Restrict generated file links to existing files with allowed extensions inside the workspace, rejecting hidden paths, traversal, and symlink escapes.
## Testing
Add rendering and transcript tests for the spoken marker, raw text preservation, file links, Unicode column offsets, and Windows-style paths, plus validation tests for rejected file destinations.
GitOrigin-RevId: 5fa180aa606acdc579a916441520602cb2bf3655
## Why
TUI preferences and persistence paths belong to the local client, while thread
configuration and account requirements may come from the active app server.
Keeping both in the same resolved `Config` can replace live local preferences
when a thread is resumed, forked, reconnected, or switched.
## What changed
- Add `LocalSettings` as the TUI-owned source for UI, history, notice, and local
persistence settings, and preserve it across session lifecycle transitions.
- Write preference changes to the selected user config file and reload local
settings from disk when changing roots.
- Use the app server's account response for authentication-dependent onboarding
and status UI instead of the local model-provider configuration.
- Retain platform family and OS metadata reported by remote app servers.
## Testing
- Cover local setting defaults, overrides, persistence destinations, reloads,
and preservation across widget replacement and root switching.
- Cover remote platform metadata and server-controlled authentication UI.
GitOrigin-RevId: dbc2965fb1d6cbecb3f973f6133f3dcd4467b753
## Why
Delegated prompts should retain the authority of the TUI tool that sent them instead of being recorded as user input.
## What changed
- Start delegated `create_thread` and `send_message_to_thread` turns with a namespaced tool output and an empty user input list.
- Recognize delegated outputs from trusted Codex namespaces when building activity summaries.
- Render replayed delegation outputs in history and transcripts with their source task attribution, without adding them to composer history.
## Testing
- Cover turn request encoding, namespace filtering, activity summaries, and replayed history/transcript rendering.
GitOrigin-RevId: aeb2f5c8ad2f2a898c80e8fc791ed879a0ab655d
## What changed
- Add an optional `toolOutput` to `turn/start` for starting or steering a turn with a named function-call output instead of user input.
- Emit standalone outputs as `functionCallOutput` thread items, persist them in durable history, and include them in resumed threads.
- Validate that tool outputs have a name, are not combined with nonempty `input`, satisfy the text-size limit, and use supported image URLs.
## Testing
- Cover standalone tool-output notifications, model input, and resumed history in both legacy and paginated history modes.
- Cover the text-size limit for structured tool output.
GitOrigin-RevId: a1eeec7b9b7de67b1a1c5e829a54552b85ec118b
## Why
Inline visualization viewer documents must remain outside locations that a
sandboxed session can modify before they are opened in a browser.
## What changed
- Materialize viewer documents in a dedicated cache under `CODEX_HOME`, keyed
by the source and artifact thread IDs, instead of alongside visualization
artifacts.
- Create visualization links only when the active filesystem policy cannot
write to the viewer cache. This also disables links for full-disk-write
sessions and applies the policy consistently when loading transcript history.
- Reject viewer cache paths containing symbolic links and track materialized
documents in memory so unchanged viewers are reused without trusting existing
file contents.
## Testing
- Verify that rendering an unchanged visualization reuses the existing viewer
file, while an updated fragment refreshes it.
GitOrigin-RevId: 12b7fbe522a68076e5d683a987b7801940d131c2
## Why
Paginated sessions can have visible messages beyond the first item page, so
bounded hydration could leave resumed history or transcript previews empty and
the transcript viewer incomplete.
## What changed
- Scan paginated history until the configured rendered-row budget is filled,
while retaining the configured scrollback beyond the visible viewport.
- Fully hydrate transcripts opened from the resume picker and build previews
from bounded item pages, including when non-visible items precede messages.
- Stop pagination on repeated cursors and let `Esc` cancel an in-flight
transcript load.
- Replay restored token usage for cold metadata-only resumes when its stored
turn can be identified.
## Testing
- Add coverage for paginated and legacy transcript loading, bounded resume
hydration, repeated cursors, transcript cancellation, and resize reflow.
GitOrigin-RevId: 2ce69f7d5eae88e2b09a27c333b00b1830ff17bf
## Why
Paginated threads should not require the TUI to load and render their entire
history when a session is resumed.
## What changed
- Hydrate a bounded initial history page for paginated resumes and forks,
respecting the configured terminal reflow row budget.
- Load older transcript items in the background as users navigate upward, while
preserving the viewport, live output, and backtrack selection.
- Reconcile review-mode prompts across page boundaries and keep restored token
usage hidden until it can be attributed to a persisted turn.
## Testing
- Added coverage for paginated resume and fork hydration, older-page merging,
transcript prepending, backtrack behavior, review prompt filtering, and token
usage restoration.
GitOrigin-RevId: 42160b943a9f6a1ba0cfe4b195c24ddf410b747d
## What changed
Make `thread_to_transcript_cells` consume its `Thread` so transcript rendering can
move owned turn items, message content, IDs, and plan text into history cells
instead of cloning them.
GitOrigin-RevId: 80200ba8928a3ea0e91cbff8a13dd00e21432426
## Why
Assistant-authored inline visualizations need a terminal fallback that lets users open generated artifacts in a browser.
## What changed
- Recognize `::codex-inline-vis{file="..."}` directives in assistant Markdown and replace them with browser links during streaming, finalized history rendering, and local transcript previews.
- Materialize visualization fragments in sandboxed viewer documents with a content security policy, while restricting artifacts to HTML files within the thread's visualization directory and limiting their size.
- Show an explicit unavailable message for invalid or missing artifacts, hide incomplete streaming directives, and preserve directive text in code blocks and user Markdown.
- Add a trusted file-link path for generated viewers without enabling arbitrary `file:` links in Markdown.
## Testing
Add coverage for directive rewriting, streaming and replay, artifact validation, sandboxed viewer generation, trusted terminal hyperlinks, and literal preservation.
GitOrigin-RevId: a666b4ebc82bb5798ad45bd137fd815d538e1de2
## What changed
- Add remote and local audio variants to core and app-server user inputs, including generated JSON and TypeScript schemas.
- Preserve audio fields when converting app-server inputs and response content into thread items.
- Keep unsupported audio out of model requests, TUI rendering, text extraction, and truncated tool output, using explicit text placeholders where audio is submitted as a model input.
## Testing
- Cover app-server media conversion, unsupported-input placeholders, TUI omission, and tool-output truncation.
GitOrigin-RevId: 16152bf3af674575ce569764a8b472e032e7569d
## What changed
- Define `SleepItem` in `codex-extension-items` and carry `clock.sleep` events through `TurnItem::Extension`.
- Preserve sleep persistence, thread-history reconstruction, and the app-server's `type: "sleep"` schema while reusing the extension-owned type.
## Testing
- Add serialization coverage for the `clock.sleep` extension wire shape and its protocol wrapper.
- Update sleep lifecycle and thread-history tests to exercise the extension-owned item.
GitOrigin-RevId: 34bb33ed9b90a09bf4744aafdb56e019c717a168
## Why
Reasoning summaries can contain an empty HTML comment placeholder, `<!--
-->`, when a generated summary part has no prose. The TUI treated that
placeholder as visible summary content, so it leaked into both the
completed conversation history and persisted transcript. Multi-part
empty summaries could also leave later generated status headings visible
as orphaned transcript content.
## What
- Strip the empty reasoning-summary placeholder at the shared
`ReasoningSummaryCell` boundary.
- Suppress the cell when removing placeholders leaves only generated
bold status headings.
- Cover the multi-part placeholder-only shape with a rendering
regression test for both normal history and transcript output.
## How to Test
1. Start Codex TUI with reasoning summaries visible, for example with
`hide_agent_reasoning = false` and `model_reasoning_summary =
"detailed"`.
2. Run a turn that receives an empty generated reasoning-summary part.
3. Confirm that the in-progress status heading may appear while the turn
is running, but the completed history and transcript contain neither
literal `<!-- -->` tokens nor orphaned reasoning headings.
4. Confirm that a reasoning summary with actual prose still renders
normally.
The model output is nondeterministic, so the targeted regression covers
the exact multi-part placeholder shape from the report:
- `just test -p codex-tui
reasoning_summary_block_hides_empty_html_comment_parts`
## Description
This PR migrates standalone web search onto the extension-owned
turn-item path introduced in #31283.
Standalone web search now emits `ExtensionItem::WebSearch` through
generic `TurnItem::Extension`, while app-server still exposes the
existing typed `ThreadItem::WebSearch` JSON shape. Hosted Responses API
web search stays on core-owned `TurnItem::WebSearch`.
## What changed
- Added `web_search::WebSearchItem` and `WebSearchAction` to
`codex-extension-items` under the stable `web.search` kind.
- Collapsed `ExtensionTurnItem` to generic `{ item, legacy_events }` now
that no typed extension special cases remain.
- Kept the existing `WebSearchBegin` / `WebSearchEnd` compatibility
events and canonical-first ordering.
- Updated app-server projection/history and generated TypeScript; the
app-server JSON schema is unchanged.
## Description
This PR adds a `codex-extension-items` crate for extension-owned
`TurnItem` schemas, and updates standalone image generation to start
using it via `TurnItem::Extension`.
This gives us a way to prevent Core from having to be aware of all
extension items. App-server still exposes the existing public
`ThreadItem::ImageGeneration` shape, now by wrapping the same shared
`image_generation::ImageGenerationItem` type.
The new `codex-extension-items` crate is necessary because the image gen
extension item is used by:
- `codex-image-generation-extension`, which produces it.
- `codex-tools / core`, which carry it generically.
- `codex-protocol`, which serializes it into lifecycle events and
rollouts.
- `app-server protocol`, which wraps it in public
`ThreadItem::ImageGeneration`
```
extension implementation
↓
codex-extension-items
↓
protocol / tools / app-server
```
We keep the hosted Responses API image generation as
`TurnItem::ImageGeneration` because core still owns its persistence and
legacy fanout.
### Before
Standalone image generation is implemented as an extension, but its item
representation previously lived in the core protocol. This sets the
precedent that core is aware of all extension items, which would be good
to avoid.
```
image-gen extension
→ constructs codex_protocol::ImageGenerationItem
→ emits ExtensionTurnItem::ImageGeneration
→ core matches ImageGeneration specially
→ protocol stores TurnItem::ImageGeneration
```
### After
```
image-gen extension
→ constructs extension-owned ImageGenerationItem
→ emits generic ExtensionItem
→ core transports/persists it generically
→ app-server wraps ImageGenerationItem as ThreadItem::ImageGeneration
```
Future extension items can have typed app-server APIs without adding a
new `TurnItem` variant, `ExtensionTurnItem` variant, or core emitter
match arm.
## What changed
- Added `codex-extension-items` with the closed `ExtensionItem` enum and
shared `image_generation::ImageGenerationItem` schema.
- Added generic `TurnItem::Extension(ExtensionItem)` and
`ExtensionTurnItem::Extension { item, legacy_events }` paths.
- Updated standalone image generation to emit a typed extension item and
provide its existing legacy `ImageGenerationBegin` /
`ImageGenerationEnd` events explicitly.
- Kept canonical lifecycle ordering: core emits `ItemStarted` /
`ItemCompleted` before extension-provided legacy events.
## Follow-up
Standalone web search still uses its typed special-case path. Migrating
it later would let `ExtensionTurnItem` collapse into a single
extension-item struct.
## Why
view_image needs to support foreign OS remote executors.
## What
- resolve image paths against the selected environment as `PathUri` and
read them through that environment's filesystem
- keep app-server's public path field wire-compatible as
`LegacyAppPathString`, with purpose-specific UI rendering
- cover relative and absolute target-native paths in the core
integration test and run the full `view_image` suite under wine-exec
without skips
## Why
Models sometimes need to pause briefly while waiting for external work,
but using a shell command for that delay ties the wait to a process and
does not naturally resume when new turn input arrives.
## What changed
- add a built-in `sleep` tool behind the under-development `sleep_tool`
feature
- accept a bounded `duration_ms` argument, matching the millisecond
convention used by unified exec
- end the sleep early when either steered user input or mailbox input
arrives
- include elapsed wall-clock time in completed and interrupted outputs
- emit a dedicated core `SleepItem` through `item/started` and
`item/completed`
- expose the sleep item as app-server v2 `ThreadItem::Sleep` and retain
it in reconstructed thread history
- regenerate the configuration schema for the new feature flag
- regenerate app-server JSON and TypeScript schema fixtures
## Test plan
- `just test -p codex-core sleep_tool_follows_feature_gate`
- `just test -p codex-core any_new_input_interrupts_sleep`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server
sleep_emits_started_and_completed_items`
## Why
Multi-agent v2 identifies agents by canonical paths, but its tool
handlers still emitted the larger legacy collaboration begin/end events
built around nickname and role metadata. App-server, rollout-trace,
analytics, and TUI consumers therefore lacked one compact path-based
completion signal that behaved consistently across live events and
replay.
The TUI also needs a bounded `/agent` status surface for v2 agents. It
should use recent local activity for previews, refresh liveness without
loading full histories, and keep the legacy picker available when no
path-backed v2 agent is known.
## What changed
- Replace the v2 `spawn_agent`, `send_message`, `followup_task`, and
`interrupt_agent` legacy lifecycle emissions with a success-only
`SubAgentActivity` event. The event records the tool call ID, occurrence
time, affected thread, canonical agent path, and `started`,
`interacted`, or `interrupted` kind.
- Expose the activity as a completion-only app-server v2
`subAgentActivity` thread item in live notifications and reconstructed
history, regenerate the protocol schemas, and count it in sub-agent tool
analytics.
- Track canonical paths from live activity and loaded-thread metadata in
the TUI, and render the activity in live and replayed transcripts.
- Make `/agent` list running path-backed agents with summaries from
bounded local event buffers. Each summary is capped at 240 graphemes,
the scan is capped at six recent items, only the last three wrapped
lines are shown, and command output is omitted. Liveness falls back to
metadata-only `thread/read` when local turn state is unavailable.
- Persist the activity as a terminal rollout-trace runtime payload and
reduce it to the corresponding spawn, send, follow-up, or close
interaction edge. `interrupt_agent` is classified as a close-edge
operation.
- Preserve the legacy picker when no path-backed v2 agent is known.
## Compatibility
App-server v2 clients that consumed `collabAgentToolCall` begin/end
pairs for these tools must handle the new completion-only
`subAgentActivity` item. Legacy v1 collaboration behavior is unchanged.
## Screenshot
<img width="684" height="288" alt="Screenshot 2026-06-08 at 15 40 47"
src="https://github.com/user-attachments/assets/194b3cd0-619d-45fb-b587-cf3e2b1b8a1d"
/>
## Testing
- `just test -p codex-app-server-protocol`
- `just test -p codex-rollout-trace`
- Added focused coverage for activity analytics, terminal trace
serialization, spawn-edge reduction, `interrupt_agent` classification,
TUI status rendering without aggregated command output, and clearing
stale running state after a completed turn.