Commit Graph
6910 Commits
Author SHA1 Message Date
zeekay b7be8d8dfd feat: rebrand from Code to Hanzo Dev throughout codebase
- Update terminal title from 'Code' to 'Hanzo Dev'
- Update welcome screen, auth screen, and trust directory prompts
- Update slash command descriptions (/undo, /init, /quit, /login, /logout)
- Update user approval widget ('Dev wants to run...')
- Update error messages and status messages
- Update prompts (prompt_coder.md, prompt_coordinator.md)
- Update chatwidget header from 'Every Code' to 'Hanzo Dev'
- Update agent install/upgrade helper messages
- Fix all compiler warnings (unused imports, unused mut, unused vars)
- Add multi-provider detection for auth (Claude, Gemini, Qwen, Vibe, Copilot, Ollama)
- Update code comments to reference Dev instead of Code
2026-01-17 15:49:08 -08:00
zeekay 9821c5759b feat(tui): update auth screen to show all AI provider options
- Change provider picker description to be provider-agnostic
- Add detailed env var instructions for all providers:
  - ANTHROPIC_API_KEY (Claude)
  - OPENAI_API_KEY (OpenAI/Codex)
  - GOOGLE_API_KEY (Gemini)
  - DASHSCOPE_API_KEY (Qwen)
  - MISTRAL_API_KEY (Vibe/Mistral)
  - GH_TOKEN (GitHub Copilot)
  - Ollama (local, no auth needed)
- Update success screen to reference Hanzo Dev docs
- Change 'Code can make mistakes' to 'AI agents can make mistakes'
2026-01-17 09:39:05 -08:00
zeekay b866c54327 docs: comprehensive config.toml.example with all agent backends and MCP servers
Includes:
- All 7 agent backends: claude, codex, gemini, qwen, vibe, copilot, ollama
- Language-specific expert agents (python, typescript, rust, go)
- 4 MCP servers: hanzo (Python), hanzo-node (Node), github, filesystem
- Subagent commands: /plan, /solve, /code, /review, /context
- Full sandbox and shell environment configuration
- API key documentation in header comments
2026-01-17 09:10:11 -08:00
zeekay 03872b4442 fix: use GitHub Copilot instead of OpenAI API for upstream merge tests
- Removes OPENAI_API_KEY requirement
- Uses --provider copilot flag with @hanzo/dev
- Authenticated via GH_TOKEN (already available in CI)
- Removes openai-proxy.js and related log handling
2026-01-16 23:33:09 -08:00
zeekay 208392839c feat: Add custom agents support with language-specific slash commands
- Add custom_agents.rs: Load agents from ~/.hanzo/agents, ~/.claude/agents, ~/work/hanzo/agents/agents
- Support YAML frontmatter in .md files and .json agent configs
- Add /use and /agent slash commands to switch personas
- Add /python, /typescript, /rust, /go language-specific commands
- Add vibe and copilot agent backends
- Support HANZO_AGENTS_PATH env var for custom directories

Agents: python, typescript, rust, go (first-class language support)
Compatible with Claude Code ~/.claude/agents format
2026-01-16 18:16:03 -08:00
zeekay 2df4536ae3 Format code with nightly rustfmt 2026-01-16 09:57:51 -08:00
zeekay 10af718bf4 Fix clippy errors: relax crate-level lints to warn
- Change print_stdout/print_stderr from deny to warn in core, tui, mcp-server, app-server
- Fix never-looping loop in chatwidget.rs screenshot capture
- Fix duplicate condition in markdown_stream.rs is_bare_list_marker
- These changes allow CI clippy to pass
2026-01-16 09:52:43 -08:00
zeekay d7fda62ad1 Use nightly toolchain for rustfmt in CI
imports_granularity=Item requires nightly rustfmt
2026-01-15 21:48:11 -08:00
zeekay e2f450331b Format code with nightly rustfmt and relax lint config
- Run cargo fmt with imports_granularity=Item on nightly
- Change workspace.lints.clippy from 'deny' to 'warn' for gradual cleanup
- This allows CI to pass while we incrementally fix lint warnings
2026-01-15 21:47:12 -08:00
zeekay fd96bc839b Fix clippy warnings and relax hanzo-dev CI lints to warnings 2026-01-15 19:42:41 -08:00
zeekay 009bf7d505 Format hanzo-dev crate with imports_granularity=Item 2026-01-15 15:11:35 -08:00
zeekay 985d147f54 Fix build issues from upstream merge
- Fix hanzo_cli:: to hanzo_dev:: imports in cli/main.rs
- Fix code_core:: to hanzo_core:: references throughout codebase
- Add type Error = io::Error to VT100Backend impl
- Add FrameExt imports for render_widget_ref in test modules
- Update unified_exec tests to expect 'dev' instead of 'codex'
- Fix git_info test to handle URL rewriting via git config
- Fix extract_code_context test expectation
2026-01-15 12:27:20 -08:00
zeekay 66df931f91 Merge openai/main: add comprehensive CI, SDK features, new options
- Enhanced rust-ci.yml with comprehensive lint/build/test jobs for both codex-rs and hanzo-dev
- Added SDK TypeScript features: modelReasoningEffort, webSearchMode, approvalPolicy, networkAccessEnabled
- Added signal/AbortSignal support for cancellable exec runs
- Enhanced bug report template with issue description field
- Synced models.json and config options from upstream
2026-01-14 20:47:41 -08:00
zeekay c0ca691ec0 Merge upstream/main (just-every/code): sync v0.6.48 features
- Added build_auto_drive_exec_config helper
- Stabilized /browser and /diff features
- Fixed tui scrollback issues
- Added OAuth-friendly MCP URL defaults
- Fixed Auto Drive reasoning effort
- Updated prompts and websocket wire API
- Various TUI and exec bug fixes
2026-01-14 20:42:44 -08:00
Ahmed IbrahimGitHubgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>aibrahim-oai
5ff989f4a8 Add migration_markdown in model_info (#9219)
Next step would be to clean Model Upgrade in model presets

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: aibrahim-oai <[email protected]>
2026-01-15 01:55:22 +00:00
zeekay feb61189f6 feat: publish hanzo-dev v0.6.0 to crates.io
🎉 Successfully published hanzo-dev as a Rust crate!

**Published Crate:**
- Package: hanzo-dev v0.6.0
- Registry: https://crates.io/crates/hanzo-dev
- Installation: cargo install hanzo-dev

**Features:**
- 🤖 GitHub Copilot CLI integration
- 💬 Interactive chat with Copilot
- 🔧 Code suggestions and shell commands
- ⚙️ Setup and installation automation
- 🎯 Minimal standalone implementation

**Usage:**
```bash
cargo install hanzo-dev
dev copilot chat
dev copilot setup --check
dev copilot suggest "sort array in Rust"
```

This provides a lightweight Rust-native version of Hanzo Dev
focused on GitHub Copilot integration, complementing the full
npm-based version with TUI and advanced features.

The crate serves as both a useful tool and an entry point to
the complete Hanzo Dev ecosystem.
2026-01-14 17:02:19 -08:00
zeekay dae0dcad42 feat: rename code-rs to hanzo-dev and prepare for publication
🎯 Major directory restructure and publication preparation:

**Directory Rename:**
- Renamed code-rs/ → hanzo-dev/ for better branding alignment
- Updated all build scripts, GitHub workflows, and documentation
- Fixed all path references across the codebase

**Publication Setup:**
- Updated workspace version to 0.6.0 (production ready)
- Configured main CLI crate as 'hanzo-dev' (available on crates.io)
- Set publish = true for core crates (hanzo-core, hanzo-tui)
- Added proper package metadata (description, license, repository, etc.)
- Maintained internal crate names to minimize dependency changes

**Updated Components:**
- package.json build scripts now reference hanzo-dev/
- GitHub Actions workflows updated for new directory structure
- build-fast.sh and related scripts updated
- Documentation and README references updated
- All Cargo.toml manifests updated with publication metadata

**Publishing Strategy:**
- Main binary: hanzo-dev (new, available for publication)
- Core library: hanzo-core (existing name, ready to publish)
- TUI library: hanzo-tui (existing name, ready to publish)
- Avoids conflict with existing Hanzo AI infrastructure crates

This prepares the codebase for official publication to crates.io while
maintaining full compatibility with the existing build system and
providing clear branding as 'Hanzo Dev' CLI tool.
2026-01-14 16:49:45 -08:00
charley-oaiandGitHub 7f35b90198 Add text element metadata to types (#9235)
Initial type tweaking PR to make the diff of
https://github.com/openai/codex/pull/9116 smaller

This should not change any behavior, just adds some fields to types
2026-01-14 16:41:50 -08:00
Michael BolinandGitHub 6c9aa257a1 fix: increase timeout for release builds from 30 to 60 minutes (#9242)
Windows builds have been tripping the 30 minute timeout. For sure, we
need to improve this, but as a quick fix, let's just increase the
timeout.

Perhaps we should switch to `lto = "thin"` for release builds, at least
for Windows:


https://github.com/openai/codex/blob/6f3bb0d8bd4773cb72d5b0510129d0d7efd2ad59/codex-rs/Cargo.toml#L288

See https://doc.rust-lang.org/cargo/reference/profiles.html#lto for
details.
2026-01-15 00:38:25 +00:00
Michael BolinandGitHub 6f3bb0d8bd fix: eliminate unnecessary clone() for each SSE event (#9238)
Given how many SSE events we get, seems worth fixing.
2026-01-15 00:06:09 +00:00
viyatb-oaiandGitHub f3b5006233 fix: correct linux sandbox uid/gid mapping after unshare (#9234)
fixes https://github.com/openai/codex/issues/9233
## Summary
- capture effective uid/gid before unshare for user namespace maps
- pass captured ids into uid/gid map writer

## Testing
- just fmt
- just fix -p codex-linux-sandbox
- cargo test -p codex-linux-sandbox
2026-01-14 15:35:53 -08:00
willwang-openaiandGitHub fbc8e0693d upgrade runners in rust-ci.yml to use the larger runners (#9106)
Upgrades runners in rust-ci.yaml to larger runners

ubuntu-24.04 (x64 and arm64) -> custom 16 core ubuntu 24.04 runners
macos-14 -> mac0s-15-xlarge
[TODO] windows (x64 and arm64) -> custom 16 core windows runners
2026-01-14 15:22:59 -08:00
zeekay 7513f4c489 feat: add comprehensive GitHub Copilot CLI integration
- Added complete Copilot integration module in hanzo-core
- Created comprehensive CLI commands for Copilot interaction:
  * chat: Interactive chat with GitHub Copilot
  * suggest: Get code suggestions and completions
  * review: Code review and analysis with git diff support
  * docs: Generate documentation (comments, README, API docs)
  * explain: Code explanation with multiple detail levels
  * shell: Generate shell commands from natural language
  * commit: Auto-generate git commit messages
  * setup: Installation and configuration management
  * complete: Auto-complete code at cursor position

- Features include:
  * GitHub CLI and Copilot extension detection
  * Multiple output formats (text, JSON, markdown)
  * File and stdin input support
  * Git integration for diffs and commits
  * Context-aware suggestions with language detection
  * Interactive and non-interactive modes

- Updated documentation with comprehensive usage guide
- Enhanced README with Copilot integration highlights
- Fully integrated into main CLI with 'dev copilot' commands

This makes Hanzo Dev a powerful CLI editing/agent backend with
AI-powered assistance directly from the command line.
2026-01-14 15:17:07 -08:00
78acf773b6 Updated issue template to ask for terminal emulator (#9231)
Co-authored-by: Josh McKinney <[email protected]>
2026-01-14 23:00:15 +00:00
zeekay 806a7c93e7 feat: comprehensive upstream sync and hanzo branding updates
- Merged latest from OpenAI Codex upstream (reasoning effort tracking, apply-patch stability)
- Updated branding from 'Codex' to 'Hanzo Dev' throughout codebase
- Fixed compilation issues in TUI and core modules
- Enhanced build system with hanzo-crypto integration
- Preserved Hanzo identity while maintaining upstream compatibility
- Updated CLI tooling and MCP protocol implementations
- Added comprehensive GitHub Actions integration
2026-01-14 14:54:24 -08:00
sayan-oaiandGitHub 799ec3f443 add WebSearchMode enum (#9216)
### What
Add `WebSearchMode` enum (disabled, cached live, defaults to cached) to
config + V2 protocol. This enum takes precedence over legacy flags:
`web_search_cached`, `web_search_request`, and `tools.web_search`.

Keep `--search` as live.

### Tests
Added tests
2026-01-14 12:51:42 -08:00
Josh McKinneyandGitHub 1f3a5eebec fix(tui): disable double-press quit shortcut (#9220)
Disables the default Ctrl+C/Ctrl+D double-press quit UX (keeps the code
path behind a const) while we rethink the quit/interrupt flow.

Tests:
- just fmt
- cargo clippy --fix --all-features --tests --allow-dirty --allow-no-vcs
-p codex-tui
- cargo test -p codex-tui --lib
2026-01-14 20:28:18 +00:00
Josh McKinneyandGitHub 0dcee6af47 fix(tui2): align Steer submit keys (#9218)
- Remove legacy Ctrl+K queuing in tui2; Tab is the queue key.
- Make Enter queue when Steer is disabled and submit immediately when
Steer is enabled.
- Add Steer keybinding docs on both tui and tui2 chat composers.
2026-01-14 19:35:55 +00:00
pakrym-oaiandGitHub de2c48c27e Rename hierarchical_agents to child_agents_md (#9215)
Clearer name
2026-01-14 19:14:24 +00:00
jif-oaiandGitHub 21a14642b1 feat: adding piped process to replace PTY when needed (#8797) 2026-01-14 18:44:04 +00:00
gt-oaiandGitHub 279b883057 s/mcp_server_requirements/mcp_servers (#9212)
A simple `s/mcp_server_requirements/mcp_servers/g` for an unreleased
feature. @bolinfest correctly pointed out, it's already in
`requirements.toml` so the `_requirements` is redundant.
2026-01-14 18:41:52 +00:00
pakrym-oaiandGitHub f9f0720adf Log headers in trace mode (#9214)
To enable:

```
export RUST_LOG="warn,codex_=trace"
```

Sample: 
```
Request completed method=POST url=https://chatgpt.com/backend-api/codex/responses status=200 OK headers={"date": "Wed, 14 Jan 2026 18:21:21 GMT", "transfer-encoding": "chunked", "connection": "keep-alive", "x-codex-plan-type": "business", "x-codex-primary-used-percent": "3", "x-codex-secondary-used-percent": "6", "x-codex-primary-window-minutes": "300", "x-codex-primary-over-secondary-limit-percent": "0", "x-codex-secondary-window-minutes": "10080", "x-codex-primary-reset-after-seconds": "9944", "x-codex-secondary-reset-after-seconds": "171121", "x-codex-primary-reset-at": "1768424824", "x-codex-secondary-reset-at": "1768586001", "x-codex-credits-has-credits": "False", "x-codex-credits-balance": "", "x-codex-credits-unlimited": "False", "x-models-etag": "W/\"7a7ffbc83c159dbd7a2a73aaa9c91b7a\"", "x-oai-request-id": "ffedcd30-6d8a-4c4d-be10-8ebb23c142c8", "x-envoy-upstream-service-time": "417", "x-openai-proxy-wasm": "v0.1", "cf-cache-status": "DYNAMIC", "set-cookie": "__cf_bm=xFKeaMbWNbKO5ZX.K5cJBhj34OA1QvnF_3nkdMThjlA-1768414881-1.0.1.1-uLpsE_BDkUfcmOMaeKVQmv_6_2ytnh_R3lO_il5N5K3YPQEkBo0cOMTdma6bK0Gz.hQYcIesFwKIJht1kZ9JKqAYYnjgB96hF4.sii2U3cE; path=/; expires=Wed, 14-Jan-26 18:51:21 GMT; domain=.chatgpt.com; HttpOnly; Secure; SameSite=None", "report-to": "{\"endpoints\":[{\"url\":\"https:\/\/a.nel.cloudflare.com\/report\/v4?s=4Kc7g4zUhKkIm3xHuB6ba4jyIUqqZ07ETwIPAYQASikRjA8JesbtUKDP9tSrZ5PnzWldaiSz5dZVQFI579LEsCMlMUSelTvmyQ8j4FbFDawi%2FprWZ5iRePiaSalr\"}],\"group\":\"cf-nel\",\"max_age\":604800}", "nel": "{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}", "strict-transport-security": "max-age=31536000; includeSubDomains; preload", "x-content-type-options": "nosniff", "cross-origin-opener-policy": "same-origin-allow-popups", "referrer-policy": "strict-origin-when-cross-origin", "server": "cloudflare", "cf-ray": "9bdf270adc7aba3a-SEA"} version=HTTP/1.1
```
2026-01-14 18:38:12 +00:00
Ahmed IbrahimandGitHub 5e672c13e0 Get model on session configured (#9191)
- Don't try to precompute model unless you know it from `config`
- Block `/model` on session configured
- Queue messages until session configured
- show "loading" in status until session configured
2026-01-14 10:20:41 -08:00
Celia ChenandGitHub bfe3fa76d3 fix: Emit response.completed immediately for Responses SSE (#9170)
we see windows test failures like this:
https://github.com/openai/codex/actions/runs/20930055601/job/60138344260.

The issue is that SSE connections sometimes remain open after the
completion event esp. for windows. We should emit the completion event
and return immediately. this is consistent with the protocol:

> The Model streams responses back in an SSE, which are collected until
"completed" message and the SSE terminates

from
https://github.com/openai/codex/blob/dev/cc/fix-windows-test/codex-rs/docs/protocol_v1.md#L37.

this helps us achieve parity with responses websocket logic here:
https://github.com/openai/codex/blob/dev/cc/fix-windows-test/codex-rs/codex-api/src/endpoint/responses_websocket.rs#L220-L227.
2026-01-14 10:05:00 -08:00
jif-oaiandGitHub bfe3fe0510 feat: add collab prompt (#9208)
Adding a prompt for collab tools. This is only for internal use and the
prompt won't be gated for now as it is not stable yet.

The goal of this PR is to provide the tool required to iterate on the
prompt
2026-01-14 09:58:15 -08:00
jif-oaiandGitHub 32be61a084 feat: emit events around collab tools (#9095)
Emit the following events around the collab tools. On the `app-server`
this will be under `item/started` and `item/completed`
```
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabAgentSpawnBeginEvent {
    /// Identifier for the collab tool call.
    pub call_id: String,
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the
    /// beginning.
    pub prompt: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabAgentSpawnEndEvent {
    /// Identifier for the collab tool call.
    pub call_id: String,
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the newly spawned agent, if it was created.
    pub new_thread_id: Option<ThreadId>,
    /// Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the
    /// beginning.
    pub prompt: String,
    /// Last known status of the new agent reported to the sender agent.
    pub status: AgentStatus,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabAgentInteractionBeginEvent {
    /// Identifier for the collab tool call.
    pub call_id: String,
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the receiver.
    pub receiver_thread_id: ThreadId,
    /// Prompt sent from the sender to the receiver. Can be empty to prevent CoT
    /// leaking at the beginning.
    pub prompt: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabAgentInteractionEndEvent {
    /// Identifier for the collab tool call.
    pub call_id: String,
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the receiver.
    pub receiver_thread_id: ThreadId,
    /// Prompt sent from the sender to the receiver. Can be empty to prevent CoT
    /// leaking at the beginning.
    pub prompt: String,
    /// Last known status of the receiver agent reported to the sender agent.
    pub status: AgentStatus,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabWaitingBeginEvent {
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the receiver.
    pub receiver_thread_id: ThreadId,
    /// ID of the waiting call.
    pub call_id: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabWaitingEndEvent {
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the receiver.
    pub receiver_thread_id: ThreadId,
    /// ID of the waiting call.
    pub call_id: String,
    /// Last known status of the receiver agent reported to the sender agent.
    pub status: AgentStatus,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabCloseBeginEvent {
    /// Identifier for the collab tool call.
    pub call_id: String,
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the receiver.
    pub receiver_thread_id: ThreadId,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct CollabCloseEndEvent {
    /// Identifier for the collab tool call.
    pub call_id: String,
    /// Thread ID of the sender.
    pub sender_thread_id: ThreadId,
    /// Thread ID of the receiver.
    pub receiver_thread_id: ThreadId,
    /// Last known status of the receiver agent reported to the sender agent before
    /// the close.
    pub status: AgentStatus,
}
```
2026-01-14 17:55:57 +00:00
Josh McKinneyandGitHub 457732f151 tui: double-press Ctrl+C/Ctrl+D to quit (#8936)
## Problem

Codex’s TUI quit behavior has historically been easy to trigger
accidentally and hard to reason
about.

- `Ctrl+C`/`Ctrl+D` could terminate the UI immediately, which is a
common key to press while trying
  to dismiss a modal, cancel a command, or recover from a stuck state.
- “Quit” and “shutdown” were not consistently separated, so some exit
paths could bypass the
  shutdown/cleanup work that should run before the process terminates.

This PR makes quitting both safer (harder to do by accident) and more
uniform across quit
gestures, while keeping the shutdown-first semantics explicit.

## Mental model

After this change, the system treats quitting as a UI request that is
coordinated by the app
layer.

- The UI requests exit via `AppEvent::Exit(ExitMode)`.
- `ExitMode::ShutdownFirst` is the normal user path: the app triggers
`Op::Shutdown`, continues
rendering while shutdown runs, and only ends the UI loop once shutdown
has completed.
- `ExitMode::Immediate` exists as an escape hatch (and as the
post-shutdown “now actually exit”
signal); it bypasses cleanup and should not be the default for
user-triggered quits.

User-facing quit gestures are intentionally “two-step” for safety:

- `Ctrl+C` and `Ctrl+D` no longer exit immediately.
- The first press arms a 1-second window and shows a footer hint (“ctrl
+ <key> again to quit”).
- Pressing the same key again within the window requests a
shutdown-first quit; otherwise the
  hint expires and the next press starts a fresh window.

Key routing remains modal-first:

- A modal/popup gets first chance to consume `Ctrl+C`.
- If a modal handles `Ctrl+C`, any armed quit shortcut is cleared so
dismissing a modal cannot
  prime a subsequent `Ctrl+C` to quit.
- `Ctrl+D` only participates in quitting when the composer is empty and
no modal/popup is active.

The design doc `docs/exit-confirmation-prompt-design.md` captures the
intended routing and the
invariants the UI should maintain.

## Non-goals

- This does not attempt to redesign modal UX or make modals uniformly
dismissible via `Ctrl+C`.
It only ensures modals get priority and that quit arming does not leak
across modal handling.
- This does not introduce a persistent confirmation prompt/menu for
quitting; the goal is to keep
  the exit gesture lightweight and consistent.
- This does not change the semantics of core shutdown itself; it changes
how the UI requests and
  sequences it.

## Tradeoffs

- Quitting via `Ctrl+C`/`Ctrl+D` now requires a deliberate second
keypress, which adds friction for
  users who relied on the old “instant quit” behavior.
- The UI now maintains a small time-bounded state machine for the armed
shortcut, which increases
  complexity and introduces timing-dependent behavior.

This design was chosen over alternatives (a modal confirmation prompt or
a long-lived “are you
sure” state) because it provides an explicit safety barrier while
keeping the flow fast and
keyboard-native.

## Architecture

- `ChatWidget` owns the quit-shortcut state machine and decides when a
quit gesture is allowed
  (idle vs cancellable work, composer state, etc.).
- `BottomPane` owns rendering and local input routing for modals/popups.
It is responsible for
consuming cancellation keys when a view is active and for
showing/expiring the footer hint.
- `App` owns shutdown sequencing: translating
`AppEvent::Exit(ShutdownFirst)` into `Op::Shutdown`
  and only terminating the UI loop when exit is safe.

This keeps “what should happen” decisions (quit vs interrupt vs ignore)
in the chat/widget layer,
while keeping “how it looks and which view gets the key” in the
bottom-pane layer.

## Observability

You can tell this is working by running the TUIs and exercising the quit
gestures:

- While idle: pressing `Ctrl+C` (or `Ctrl+D` with an empty composer and
no modal) shows a footer
hint for ~1 second; pressing again within that window exits via
shutdown-first.
- While streaming/tools/review are active: `Ctrl+C` interrupts work
rather than quitting.
- With a modal/popup open: `Ctrl+C` dismisses/handles the modal (if it
chooses to) and does not
arm a quit shortcut; a subsequent quick `Ctrl+C` should not quit unless
the user re-arms it.

Failure modes are visible as:

- Quits that happen immediately (no hint window) from `Ctrl+C`/`Ctrl+D`.
- Quits that occur while a modal is open and consuming `Ctrl+C`.
- UI termination before shutdown completes (cleanup skipped).

## Tests

- Updated/added unit and snapshot coverage in `codex-tui` and
`codex-tui2` to validate:
  - The quit hint appears and expires on the expected key.
- Double-press within the window triggers a shutdown-first quit request.
- Modal-first routing prevents quit bypass and clears any armed shortcut
when a modal consumes
    `Ctrl+C`.

These tests focus on the UI-level invariants and rendered output; they
do not attempt to validate
real terminal key-repeat timing or end-to-end process shutdown behavior.

---
Screenshot:
<img width="912" height="740" alt="Screenshot 2026-01-13 at 1 05 28 PM"
src="https://github.com/user-attachments/assets/18f3d22e-2557-47f2-a369-ae7a9531f29f"
/>
2026-01-14 17:42:52 +00:00
pakrym-oaiandGitHub 9fa740ac80 Use current model for review (#9179)
Instead of having a hard-coded default review model, use the current
model for running `/review` unless one is specified in the config.

Also inherit current reasoning effort
2026-01-14 08:59:41 -08:00
viyatb-oaiandGitHub 1438690f31 feat: add support for read-only bind mounts in the linux sandbox (#9112)
### Motivation

- Landlock alone cannot prevent writes to sensitive in-repo files like
`.git/` when the repo root is writable, so explicit mount restrictions
are required for those paths.
- The sandbox must set up any mounts before calling Landlock so Landlock
can still be applied afterwards and the two mechanisms compose
correctly.

### Description

- Add a new `linux-sandbox` helper `apply_read_only_mounts` in
`linux-sandbox/src/mounts.rs` that: unshares namespaces, maps uids/gids
when required, makes mounts private, bind-mounts targets, and remounts
them read-only.
- Wire the mount step into the sandbox flow by calling
`apply_read_only_mounts(...)` before network/seccomp and before applying
Landlock rules in `linux-sandbox/src/landlock.rs`.
2026-01-14 08:30:46 -08:00
jif-oaiandGitHub c6c725d6ec feat: add auto refresh on thread listeners (#9105)
This PR is in the scope of multi-agent work. 

An agent (=thread) can now spawn other agents. Those other agents are
not attached to any clients. We need a way to make sure that the clients
are aware of the new threads to look at (for approval for example). This
PR adds a channel to the `ThreadManager` that pushes the ID of those
newly created agents such that the client (here the app-server) can also
subscribe to those ones.
2026-01-14 16:26:01 +00:00
jif-oaiandGitHub 3804772006 chore: clamp min yield time for empty write_stdin (#9156)
After evals, 0 impact on performance
2026-01-14 16:25:40 +00:00
Ahmed IbrahimandGitHub ae0a0c66bd Render exec output deltas inline (#9194) 2026-01-14 08:11:12 -08:00
jif-oaiandGitHub 85caec8d56 fix: drop double waiting header in TUI (#9145) 2026-01-14 09:52:34 +00:00
jif-oaiandGitHub 605852fb91 feat: only source shell snapshot if the file exists (#9197) 2026-01-14 01:28:25 -08:00
jif-oaiandGitHub ea664e3c60 feat: return an error if the image sent by the user is a bad image (#9146)
## Before
When we detect an `InvalidImageRequest`, we replace the image by a
placeholder and keep going

## Now
In such `InvalidImageRequest`, we check if the image is due to a user
message or a tool call output. For tool call output we still replace it
with a placeholder to avoid breaking the agentic loop bu tif this is
because of a user message, we send an error to the user
2026-01-14 09:07:45 +00:00
jif-oaiandGitHub 9f578d044a fix: shell snapshot clean-up (#9155)
Clean all shell snapshot files corresponding to sessions that have not
been updated in 7 days
Those files should never leak. The only known cases were it can leak are
during non graceful interrupt of the process (`kill -9, `panic`, OS
crash, ...)
2026-01-14 09:05:46 +00:00
jif-oaiandGitHub 4714f74e3e feat: add sourcing of rc files to shell snapshot (#9150) 2026-01-14 08:58:10 +00:00
Ahmed IbrahimandGitHub 46843abc36 change api default model (#9188) 2026-01-13 22:33:34 -08:00
Michael BolinandGitHub a71754b47b feat: add threadId to MCP server messages (#9192)
This favors `threadId` instead of `conversationId` so we use the same
terms as https://developers.openai.com/codex/sdk/.

To test the local build:

```
cd codex-rs
cargo build --bin codex
npx -y @modelcontextprotocol/inspector ./target/debug/codex mcp-server
```

I sent:

```json
{
  "method": "tools/call",
  "params": {
    "name": "codex",
    "arguments": {
      "prompt": "favorite ls option?"
    },
    "_meta": {
      "progressToken": 0
    }
  }
}
```

and got:

```json
{
  "content": [
    {
      "type": "text",
      "text": "`ls -lah` (or `ls -alh`) — long listing, includes dotfiles, human-readable sizes."
    }
  ],
  "structuredContent": {
    "threadId": "019bbb20-bff6-7130-83aa-bf45ab33250e"
  }
}
```

and successfully used the `threadId` in the follow-up with the
`codex-reply` tool call:

```json
{
  "method": "tools/call",
  "params": {
    "name": "codex-reply",
    "arguments": {
      "prompt": "what is the long versoin",
      "threadId": "019bbb20-bff6-7130-83aa-bf45ab33250e"
    },
    "_meta": {
      "progressToken": 1
    }
  }
}
```

whose response also has the `threadId`:

```json
{
  "content": [
    {
      "type": "text",
      "text": "Long listing is `ls -l` (adds permissions, owner/group, size, timestamp)."
    }
  ],
  "structuredContent": {
    "threadId": "019bbb20-bff6-7130-83aa-bf45ab33250e"
  }
}
```

Fixes https://github.com/openai/codex/issues/3712.
2026-01-13 22:14:41 -08:00
sayan-oaiandGitHub 762ca21b8a chore: clarify default shell for unified_exec (#8997)
The description of the `shell` arg for `exec_command` states the default
is `/bin/bash`, but AFAICT it's the user's default shell.

Default logic
[here](https://github.com/openai/codex/blob/9cf0e3cb08671a35cb5fa5d436268072664a8a6e/codex-rs/core/src/tools/handlers/unified_exec.rs#L123).

EDIT: #9004 has an alternative where we inform the model of the default
shell itself.
2026-01-13 21:37:41 -08:00