Commit Graph

1013 Commits

  • chore: sanbox extraction (#4286)
    # Extract and Centralize Sandboxing
    - Goal: Improve safety and clarity by centralizing sandbox planning and
    execution.
      - Approach:
    - Add planner (ExecPlan) and backend registry (Direct/Seatbelt/Linux)
    with run_with_plan.
    - Refactor codex.rs to plan-then-execute; handle failures/escalation via
    the plan.
    - Delegate apply_patch to the codex binary and run it with an empty env
    for determinism.
  • Fix Callback URL for staging and prod environments (#4533)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
  • fix: remove mcp-types from app server protocol (#4537)
    We continue the separation between `codex app-server` and `codex
    mcp-server`.
    
    In particular, we introduce a new crate, `codex-app-server-protocol`,
    and migrate `codex-rs/protocol/src/mcp_protocol.rs` into it, renaming it
    `codex-rs/app-server-protocol/src/protocol.rs`.
    
    Because `ConversationId` was defined in `mcp_protocol.rs`, we move it
    into its own file, `codex-rs/protocol/src/conversation_id.rs`, and
    because it is referenced in a ton of places, we have to touch a lot of
    files as part of this PR.
    
    We also decide to get away from proper JSON-RPC 2.0 semantics, so we
    also introduce `codex-rs/app-server-protocol/src/jsonrpc_lite.rs`, which
    is basically the same `JSONRPCMessage` type defined in `mcp-types`
    except with all of the `"jsonrpc": "2.0"` removed.
    
    Getting rid of `"jsonrpc": "2.0"` makes our serialization logic
    considerably simpler, as we can lean heavier on serde to serialize
    directly into the wire format that we use now.
  • fix: use macros to ensure request/response symmetry (#4529)
    Manually curating `protocol-ts/src/lib.rs` was error-prone, as expected.
    I finally asked Codex to write some Rust macros so we can ensure that:
    
    - For every variant of `ClientRequest` and `ServerRequest`, there is an
    associated `params` and `response` type.
    - All response types are included automatically in the output of `codex
    generate-ts`.
  • Remove legacy codex exec --json format (#4525)
    `codex exec --json` now maps to the behavior of `codex exec
    --experimental-json` with new event and item shapes.
    
    Thread events:
    - thread.started
    - turn.started
    - turn.completed
    - turn.failed
    - item.started
    - item.updated
    - item.completed
    
    Item types: 
    - assistant_message
    - reasoning
    - command_execution
    - file_change
    - mcp_tool_call
    - web_search
    - todo_list
    - error
    
    Sample output:
    
    <details>
    `codex exec "list my assigned github issues"  --json | jq`
    
    ```
    {
      "type": "thread.started",
      "thread_id": "01999ce5-f229-7661-8570-53312bd47ea3"
    }
    {
      "type": "turn.started"
    }
    {
      "type": "item.completed",
      "item": {
        "id": "item_0",
        "item_type": "reasoning",
        "text": "**Planning to list assigned GitHub issues**"
      }
    }
    {
      "type": "item.started",
      "item": {
        "id": "item_1",
        "item_type": "mcp_tool_call",
        "server": "github",
        "tool": "search_issues",
        "status": "in_progress"
      }
    }
    {
      "type": "item.completed",
      "item": {
        "id": "item_1",
        "item_type": "mcp_tool_call",
        "server": "github",
        "tool": "search_issues",
        "status": "completed"
      }
    }
    {
      "type": "item.completed",
      "item": {
        "id": "item_2",
        "item_type": "reasoning",
        "text": "**Organizing final message structure**"
      }
    }
    {
      "type": "item.completed",
      "item": {
        "id": "item_3",
        "item_type": "assistant_message",
        "text": "**Assigned Issues**\n- openai/codex#3267 – “stream error: stream disconnected before completion…” (bug) – last update 2025-09-08\n- openai/codex#3257 – “You've hit your usage limit. Try again in 4 days 20 hours 9 minutes.” – last update 2025-09-23\n- openai/codex#3054 – “reqwest SSL panic (library has no ciphers)” (bug) – last update 2025-09-03\n- openai/codex#3051 – “thread 'main' panicked at linux-sandbox/src/linux_run_main.rs:53:5:” (bug) – last update 2025-09-10\n- openai/codex#3004 – “Auto-compact when approaching context limit” (enhancement) – last update 2025-09-26\n- openai/codex#2916 – “Feature request: Add OpenAI service tier support for cost optimization” – last update 2025-09-12\n- openai/codex#1581 – “stream error: stream disconnected before completion: stream closed before response.complete; retrying...” (bug) – last update 2025-09-17"
      }
    }
    {
      "type": "turn.completed",
      "usage": {
        "input_tokens": 34785,
        "cached_input_tokens": 12544,
        "output_tokens": 560
      }
    }
    ```
    
    </details>
  • wrap markdown at render time (#4506)
    This results in correctly indenting list items with long lines.
    
    <img width="1006" height="251" alt="Screenshot 2025-09-30 at 10 00
    48 AM"
    src="https://github.com/user-attachments/assets/0a076cf6-ca3c-4efb-b3af-dc07617cdb6f"
    />
  • fix: enable process hardening in Codex CLI for release builds (#4521)
    I don't believe there is any upside in making process hardening opt-in
    for Codex CLI releases. If you want to tinker with Codex CLI, then build
    from source (or run as `root`)?
  • fix: clean up TypeScript exports (#4518)
    Fixes:
    
    - Removed overdeclaration of types that were unnecessary because they
    were already included by induction.
    - Reordered list of response types to match the enum order, making it
    easier to identify what was missing.
    - Added `ExecArbitraryCommandResponse` because it was missing.
    - Leveraged `use codex_protocol::mcp_protocol::*;` to make the file more
    readable.
    - Removed crate dependency on `mcp-types` now that we have separate the
    app server from the MCP server:
    https://github.com/openai/codex/pull/4471
    
    My next move is to come up with some scheme that ensures request types
    always have a response type and that the response type is automatically
    included with the output of `codex generate-ts`.
  • fix: ensure every variant of ClientRequest has a params field (#4512)
    This ensures changes the generated TypeScript type for `ClientRequest`
    so that instead of this:
    
    ```typescript
    /**
     * Request from the client to the server.
     */
    export type ClientRequest =
      | { method: "initialize"; id: RequestId; params: InitializeParams }
      | { method: "newConversation"; id: RequestId; params: NewConversationParams }
      // ...
      | { method: "getUserAgent"; id: RequestId }
      | { method: "userInfo"; id: RequestId }
      // ...
    ```
    
    we have this:
    
    ```typescript
    /**
     * Request from the client to the server.
     */
    export type ClientRequest =
      | { method: "initialize"; id: RequestId; params: InitializeParams }
      | { method: "newConversation"; id: RequestId; params: NewConversationParams }
      // ...
      | { method: "getUserAgent"; id: RequestId; params: undefined }
      | { method: "userInfo"; id: RequestId; params: undefined }
      // ...
    ```
    
    which makes TypeScript happier when it comes to destructuring instances
    of `ClientRequest` because it does not complain about `params` not being
    guaranteed to exist anymore.
  • Wire up web search item (#4511)
    Add handling for web search events.
  • chore: prompt update to enforce good usage of apply_patch (#3846)
    Update prompt to prevent codex to use Python script or fancy commands to
    edit files.
    
    ## Testing:
    3 scenarios have been considered:
    1. Rename codex to meca_code. Proceed to the whole refactor file by
    file. Don't ask for approval at each step
    2. Add a description to every single function you can find in the repo
    3. Rewrite codex.rs in a more idiomatic way. Make sure to touch ONLY
    this file and that clippy does not complain at the end
    
    Before this update, 22% (estimation as it's sometimes hard to find all
    the creative way the model find to edit files) of the file editions
    where made using something else than a raw `apply_patch`
    
    After this update, not a single edition without `apply_patch` was found
    
    [EDIT]
    I managed to have a few `["bash", "-lc", "apply_path"]` when reaching <
    10% context left
  • Named args for custom prompts (#4474)
    Here's the logic:
    
    1. If text is empty and selector is open:
    - Enter on a prompt without args should autosubmit the prompt
    - Enter on a prompt with numeric args should add `/prompts:name ` to the
    text input
    - Enter on a prompt with named args should add `/prompts:name ARG1=""
    ARG2=""` to the text input
    2. If text is not empty but no args are passed:
    - For prompts with numeric args -> we allow it to submit (params are
    optional)
    - For prompts with named args -> we throw an error (all params should
    have values)
    
    <img width="454" height="246" alt="Screenshot 2025-09-23 at 2 23 21 PM"
    src="https://github.com/user-attachments/assets/fd180a1b-7d17-42ec-b231-8da48828b811"
    />
  • Add cloud tasks (#3197)
    Adds a TUI for managing, applying, and creating cloud tasks
  • fix: separate codex mcp into codex mcp-server and codex app-server (#4471)
    This is a very large PR with some non-backwards-compatible changes.
    
    Historically, `codex mcp` (or `codex mcp serve`) started a JSON-RPC-ish
    server that had two overlapping responsibilities:
    
    - Running an MCP server, providing some basic tool calls.
    - Running the app server used to power experiences such as the VS Code
    extension.
    
    This PR aims to separate these into distinct concepts:
    
    - `codex mcp-server` for the MCP server
    - `codex app-server` for the "application server"
    
    Note `codex mcp` still exists because it already has its own subcommands
    for MCP management (`list`, `add`, etc.)
    
    The MCP logic continues to live in `codex-rs/mcp-server` whereas the
    refactored app server logic is in the new `codex-rs/app-server` folder.
    Note that most of the existing integration tests in
    `codex-rs/mcp-server/tests/suite` were actually for the app server, so
    all the tests have been moved with the exception of
    `codex-rs/mcp-server/tests/suite/mod.rs`.
    
    Because this is already a large diff, I tried not to change more than I
    had to, so `codex-rs/app-server/tests/common/mcp_process.rs` still uses
    the name `McpProcess` for now, but I will do some mechanical renamings
    to things like `AppServer` in subsequent PRs.
    
    While `mcp-server` and `app-server` share some overlapping functionality
    (like reading streams of JSONL and dispatching based on message types)
    and some differences (completely different message types), I ended up
    doing a bit of copypasta between the two crates, as both have somewhat
    similar `message_processor.rs` and `outgoing_message.rs` files for now,
    though I expect them to diverge more in the near future.
    
    One material change is that of the initialize handshake for `codex
    app-server`, as we no longer use the MCP types for that handshake.
    Instead, we update `codex-rs/protocol/src/mcp_protocol.rs` to add an
    `Initialize` variant to `ClientRequest`, which takes the `ClientInfo`
    object we need to update the `USER_AGENT_SUFFIX` in
    `codex-rs/app-server/src/message_processor.rs`.
    
    One other material change is in
    `codex-rs/app-server/src/codex_message_processor.rs` where I eliminated
    a use of the `send_event_as_notification()` method I am generally trying
    to deprecate (because it blindly maps an `EventMsg` into a
    `JSONNotification`) in favor of `send_server_notification()`, which
    takes a `ServerNotification`, as that is intended to be a custom enum of
    all notification types supported by the app server. So to make this
    update, I had to introduce a new variant of `ServerNotification`,
    `SessionConfigured`, which is a non-backwards compatible change with the
    old `codex mcp`, and clients will have to be updated after the next
    release that contains this PR. Note that
    `codex-rs/app-server/tests/suite/list_resume.rs` also had to be update
    to reflect this change.
    
    I introduced `codex-rs/utils/json-to-toml/src/lib.rs` as a small utility
    crate to avoid some of the copying between `mcp-server` and
    `app-server`.
  • Move PR-style review to top (#4486)
    <img width="469" height="330" alt="Screenshot 2025-09-29 at 10 31 22 PM"
    src="https://github.com/user-attachments/assets/b5e20a08-85b4-4095-8a7f-0f58d1195b7e"
    />
  • Set originator for codex exec (#4485)
    Distinct from the main CLI.
  • Add MCP tool call item to codex exec (#4481)
    No arguments/results for now.
    ```
    {
      "type": "item.started",
      "item": {
        "id": "item_1",
        "item_type": "mcp_tool_call",
        "server": "github",
        "tool": "search_issues",
        "status": "in_progress"
      }
    }
    {
      "type": "item.completed",
      "item": {
        "id": "item_1",
        "item_type": "mcp_tool_call",
        "server": "github",
        "tool": "search_issues",
        "status": "completed"
      }
    }
    ```
  • Rakesh/support device auth (#3531)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    # test
    
    ```
    codex-rs % export CODEX_DEVICE_AUTH_BASE_URL=http://localhost:3007
    codex-rs % cargo run --bin codex login --experimental_use-device-code
       Compiling codex-login v0.0.0 (/Users/rakesh/code/codex/codex-rs/login)
       Compiling codex-mcp-server v0.0.0 (/Users/rakesh/code/codex/codex-rs/mcp-server)
       Compiling codex-tui v0.0.0 (/Users/rakesh/code/codex/codex-rs/tui)
       Compiling codex-cli v0.0.0 (/Users/rakesh/code/codex/codex-rs/cli)
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.90s
         Running `target/debug/codex login --experimental_use-device-code`
    To authenticate, enter this code when prompted: 6Q27-KBVRF with interval 5
    ^C
    
    ```
    
    The error in the last line is since the poll endpoint is not yet
    implemented
  • Custom prompts begin with /prompts: (#4476)
    <img width="608" height="354" alt="Screenshot 2025-09-29 at 4 41 08 PM"
    src="https://github.com/user-attachments/assets/162508eb-c1ac-4bc0-95f2-5e23cb4ae428"
    />
  • Fixes (#4458)
    Fixing the "? for shortcuts"
    
    - Only show the hint when composer is empty
    - Don't reset footer on new task updates
    - Reorder the elements
    - Align the "?" and "/" with overlay on and off
    
    Based on #4364
  • Custom prompt args (numeric) (#4470)
    [Cherry picked from /pull/3565]
    
    Adds $1, $2, $3, $ARGUMENTS param parsing for custom prompts.
  • no background for /command or @file popup (#4469)
    before:
    
    <img width="855" height="270" alt="Screenshot 2025-09-29 at 3 42 53 PM"
    src="https://github.com/user-attachments/assets/eb247e1f-0947-4830-93c4-d4ecb2992b32"
    />
    
    
    after:
    
    <img width="855" height="270" alt="Screenshot 2025-09-29 at 3 43 04 PM"
    src="https://github.com/user-attachments/assets/46717844-6066-47a4-a34a-1a75508ea2c3"
    />
  • render • as dim (#4467)
    <img width="988" height="686" alt="Screenshot 2025-09-29 at 3 28 30 PM"
    src="https://github.com/user-attachments/assets/634a6e6f-cdc0-49af-97c1-096e871414bb"
    />
  • [Core]: add tail in the rollout data (#4461)
    This will help us show the conversation tail and last updated timestamp.
  • Parse out frontmatter for custom prompts (#4456)
    [Cherry picked from https://github.com/openai/codex/pull/3565]
    
    Removes the frontmatter description/args from custom prompt files and
    only includes body.
  • [mcp-server] Expose fuzzy file search in MCP (#2677)
    ## Summary
    Expose a simple fuzzy file search implementation for mcp clients to work
    with
    
    ## Testing
    - [x] Tested locally
  • OpenTelemetry events (#2103)
    ### Title
    
    ## otel
    
    Codex can emit [OpenTelemetry](https://opentelemetry.io/) **log events**
    that
    describe each run: outbound API requests, streamed responses, user
    input,
    tool-approval decisions, and the result of every tool invocation. Export
    is
    **disabled by default** so local runs remain self-contained. Opt in by
    adding an
    `[otel]` table and choosing an exporter.
    
    ```toml
    [otel]
    environment = "staging"   # defaults to "dev"
    exporter = "none"          # defaults to "none"; set to otlp-http or otlp-grpc to send events
    log_user_prompt = false    # defaults to false; redact prompt text unless explicitly enabled
    ```
    
    Codex tags every exported event with `service.name = "codex-cli"`, the
    CLI
    version, and an `env` attribute so downstream collectors can distinguish
    dev/staging/prod traffic. Only telemetry produced inside the
    `codex_otel`
    crate—the events listed below—is forwarded to the exporter.
    
    ### Event catalog
    
    Every event shares a common set of metadata fields: `event.timestamp`,
    `conversation.id`, `app.version`, `auth_mode` (when available),
    `user.account_id` (when available), `terminal.type`, `model`, and
    `slug`.
    
    With OTEL enabled Codex emits the following event types (in addition to
    the
    metadata above):
    
    - `codex.api_request`
      - `cf_ray` (optional)
      - `attempt`
      - `duration_ms`
      - `http.response.status_code` (optional)
      - `error.message` (failures)
    - `codex.sse_event`
      - `event.kind`
      - `duration_ms`
      - `error.message` (failures)
      - `input_token_count` (completion only)
      - `output_token_count` (completion only)
      - `cached_token_count` (completion only, optional)
      - `reasoning_token_count` (completion only, optional)
      - `tool_token_count` (completion only)
    - `codex.user_prompt`
      - `prompt_length`
      - `prompt` (redacted unless `log_user_prompt = true`)
    - `codex.tool_decision`
      - `tool_name`
      - `call_id`
    - `decision` (`approved`, `approved_for_session`, `denied`, or `abort`)
      - `source` (`config` or `user`)
    - `codex.tool_result`
      - `tool_name`
      - `call_id`
      - `arguments`
      - `duration_ms` (execution time for the tool)
      - `success` (`"true"` or `"false"`)
      - `output`
    
    ### Choosing an exporter
    
    Set `otel.exporter` to control where events go:
    
    - `none` – leaves instrumentation active but skips exporting. This is
    the
      default.
    - `otlp-http` – posts OTLP log records to an OTLP/HTTP collector.
    Specify the
      endpoint, protocol, and headers your collector expects:
    
      ```toml
      [otel]
      exporter = { otlp-http = {
        endpoint = "https://otel.example.com/v1/logs",
        protocol = "binary",
        headers = { "x-otlp-api-key" = "${OTLP_TOKEN}" }
      }}
      ```
    
    - `otlp-grpc` – streams OTLP log records over gRPC. Provide the endpoint
    and any
      metadata headers:
    
      ```toml
      [otel]
      exporter = { otlp-grpc = {
        endpoint = "https://otel.example.com:4317",
        headers = { "x-otlp-meta" = "abc123" }
      }}
      ```
    
    If the exporter is `none` nothing is written anywhere; otherwise you
    must run or point to your
    own collector. All exporters run on a background batch worker that is
    flushed on
    shutdown.
    
    If you build Codex from source the OTEL crate is still behind an `otel`
    feature
    flag; the official prebuilt binaries ship with the feature enabled. When
    the
    feature is disabled the telemetry hooks become no-ops so the CLI
    continues to
    function without the extra dependencies.
    
    ---------
    
    Co-authored-by: Anton Panasenko <apanasenko@openai.com>
  • fix clear-to-end being emitted at the end of a row (#4447)
    This was causing glitchy behavior when a line in the input was the exact
    width of the terminal.
  • feat: introduce npm module for codex-responses-api-proxy (#4417)
    This PR expands `.github/workflows/rust-release.yml` so that it also
    builds and publishes the `npm` module for
    `@openai/codex-responses-api-proxy` in addition to `@openai/codex`. Note
    both `npm` modules are similar, in that they each contain a single `.js`
    file that is a thin launcher around the appropriate native executable.
    (Since we have a minimal dependency on Node.js, I also lowered the
    minimum version from 20 to 16 and verified that works on my machine.)
    
    As part of this change, we tighten up some of the docs around
    `codex-responses-api-proxy` and ensure the details regarding protecting
    the `OPENAI_API_KEY` in memory match the implementation.
    
    To test the `npm` build process, I ran:
    
    ```
    ./codex-cli/scripts/build_npm_package.py --package codex-responses-api-proxy --version 0.43.0-alpha.3
    ```
    
    which stages the `npm` module for `@openai/codex-responses-api-proxy` in
    a temp directory, using the binary artifacts from
    https://github.com/openai/codex/releases/tag/rust-v0.43.0-alpha.3.
  • Add /review to main commands (#4416)
    <img width="517" height="249" alt="Screenshot 2025-09-28 at 4 33 26 PM"
    src="https://github.com/user-attachments/assets/6d34734e-fe3c-4b88-8239-a6436bcb9fa5"
    />
  • chore: remove responses-api-proxy from the multitool (#4404)
    This removes the `codex responses-api-proxy` subcommand in favor of
    running it as a standalone CLI.
    
    As part of this change, we:
    
    - remove the dependency on `tokio`/`async/await` as well as `codex_arg0`
    - introduce the use of `pre_main_hardening()` so `CODEX_SECURE_MODE=1`
    is not required
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/4404).
    * #4406
    * __->__ #4404
    * #4403
  • Improve update nudge (#4405)
    Makes the update nudge larger and adds a link to see latest release:
    
    <img width="542" height="337" alt="Screenshot 2025-09-28 at 11 19 05 AM"
    src="https://github.com/user-attachments/assets/1facce96-72f0-4a97-910a-df8b5b8b07af"
    />
  • fix: remove default timeout of 30s in the proxy (#4336)
    This is likely the reason that I saw some conversations "freeze up" when
    using the proxy.
    
    Note the client in `core` does not specify a timeout when making
    requests to the Responses API, so the proxy should not, either.
  • tui: separator above final agent message (#4324)
    Adds a separator line before the final agent message
    
    <img width="1011" height="884" alt="Screenshot 2025-09-26 at 4 55 01 PM"
    src="https://github.com/user-attachments/assets/7c91adbf-6035-4578-8b88-a6921f11bcbc"
    />
  • [MCP] Add experimental support for streamable HTTP MCP servers (#4317)
    This PR adds support for streamable HTTP MCP servers when the
    `experimental_use_rmcp_client` is enabled.
    
    To set one up, simply add a new mcp server config with the url:
    ```
    [mcp_servers.figma]
    url = "http://127.0.0.1:3845/mcp"
    ```
    
    It also supports an optional `bearer_token` which will be provided in an
    authorization header. The full oauth flow is not supported yet.
    
    The config parsing will throw if it detects that the user mixed and
    matched config fields (like command + bearer token or url + env).
    
    The best way to review it is to review `core/src` and then
    `rmcp-client/src/rmcp_client.rs` first. The rest is tests and
    propagating the `Transport` struct around the codebase.
    
    Example with the Figma MCP:
    <img width="5084" height="1614" alt="CleanShot 2025-09-26 at 13 35 40"
    src="https://github.com/user-attachments/assets/eaf2771e-df3e-4300-816b-184d7dec5a28"
    />
  • update composer + user message styling (#4240)
    Changes:
    
    - the composer and user messages now have a colored background that
    stretches the entire width of the terminal.
    - the prompt character was changed from a cyan `▌` to a bold `›`.
    - the "working" shimmer now follows the "dark gray" color of the
    terminal, better matching the terminal's color scheme
    
    | Terminal + Background        | Screenshot |
    |------------------------------|------------|
    | iTerm with dark bg | <img width="810" height="641" alt="Screenshot
    2025-09-25 at 11 44 52 AM"
    src="https://github.com/user-attachments/assets/1317e579-64a9-4785-93e6-98b0258f5d92"
    /> |
    | iTerm with light bg | <img width="845" height="540" alt="Screenshot
    2025-09-25 at 11 46 29 AM"
    src="https://github.com/user-attachments/assets/e671d490-c747-4460-af0b-3f8d7f7a6b8e"
    /> |
    | iTerm with color bg | <img width="825" height="564" alt="Screenshot
    2025-09-25 at 11 47 12 AM"
    src="https://github.com/user-attachments/assets/141cda1b-1164-41d5-87da-3be11e6a3063"
    /> |
    | Terminal.app with dark bg | <img width="577" height="367"
    alt="Screenshot 2025-09-25 at 11 45 22 AM"
    src="https://github.com/user-attachments/assets/93fc4781-99f7-4ee7-9c8e-3db3cd854fe5"
    /> |
    | Terminal.app with light bg | <img width="577" height="367"
    alt="Screenshot 2025-09-25 at 11 46 04 AM"
    src="https://github.com/user-attachments/assets/19bf6a3c-91e0-447b-9667-b8033f512219"
    /> |
    | Terminal.app with color bg | <img width="577" height="367"
    alt="Screenshot 2025-09-25 at 11 45 50 AM"
    src="https://github.com/user-attachments/assets/dd7c4b5b-342e-4028-8140-f4e65752bd0b"
    /> |
  • Add turn started/completed events and correct exit code on error (#4309)
    Adds new event for session completed that includes usage. Also ensures
    we return 1 on failures.
    ```
    {
      "type": "session.created",
      "session_id": "019987a7-93e7-7b20-9e05-e90060e411ea"
    }
    {
      "type": "turn.started"
    }
    ...
    {
      "type": "turn.completed",
      "usage": {
        "input_tokens": 78913,
        "cached_input_tokens": 65280,
        "output_tokens": 1099
      }
    }
    ```