## Description
Add Codex as a supported local child-agent harness in the Warp client.
This updates local harness normalization and launch command
construction, and wires the CLI parsing and test coverage needed for
local child launches.
This is the client-side counterpart to
https://github.com/warpdotdev/warp-server/pull/10880.
## Linked Issue
https://linear.app/warpdotdev/issue/QUALITY-578/codex-support-for-orchestration
- [ ] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [ ] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).
## Testing
- `cargo +1.92.0 fmt --all`
- `MACOSX_DEPLOYMENT_TARGET=10.14 cargo +1.92.0 clippy --workspace
--exclude warp_completer --all-targets --tests -- -D warnings`
- `MACOSX_DEPLOYMENT_TARGET=10.14 cargo +1.92.0 clippy -p warp_completer
--all-targets --tests -- -D warnings`
- `MACOSX_DEPLOYMENT_TARGET=10.14 cargo +1.92.0 test -p warp_cli`
- `MACOSX_DEPLOYMENT_TARGET=10.14 cargo +1.92.0 test -p warp
local_child_task_config_records_supported_third_party_harnesses`
- `MACOSX_DEPLOYMENT_TARGET=10.14 cargo +1.92.0 test -p warp
execute_returns_error_when_local_harness_child_requires_orchestration_v2`
- `MACOSX_DEPLOYMENT_TARGET=10.14 cargo +1.92.0 test -p warp
execute_rejects_invalid_local_harness_names_before_pane_creation`
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Artifacts
- Conversation:
https://app.warp.dev/conversation/e4346560-106f-4bfc-a931-b705a9906799
- Plan: https://app.warp.dev/drive/notebook/BiU3vIJVoZ4jALRYFtNzdz
CHANGELOG-OZ: Add Codex as a supported harness for local child agents.
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Adds copy actions to the attached tab context menu so users can copy
tab/session metadata directly from the same UI surface where that
metadata is shown.
The menu now includes copy actions for available, non-empty metadata
when it makes sense for the current tab layout:
- Horizontal tabs show `Copy tab title` only, matching the metadata
visible in the horizontal tab strip.
- Vertical tabs grouped by tabs show copy actions for the tab title plus
available focused-session metadata such as branch, working directory,
and pull request link.
- Vertical tabs grouped by panes show copy actions sourced from the
active pane, including `Copy pane title` instead of `Copy tab title`.
All new copy actions use sentence casing, and unavailable metadata is
omitted from the menu rather than shown disabled.
## Linked Issue
- [ ] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [x] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).
## Screenshots / Videos
- Loom demo: https://www.loom.com/share/b57f7bfebea44a15b2703140db88c758
## Testing
Added integration coverage for the main layout variants:
- `test_tab_context_menu_copies_metadata` covers horizontal tabs. It
verifies that only the tab title copy action is present, and that
selecting it copies the tab title.
- `test_vertical_tab_context_menu_copies_metadata` covers vertical tabs
grouped by tabs. It verifies that the context menu can copy the branch,
tab title, and working directory for the tab/focused session.
- `test_vertical_pane_context_menu_copies_metadata` covers vertical tabs
grouped by panes. It creates a split pane with different metadata and
verifies that the menu copies the active pane branch, pane title, and
working directory.
Validation run:
- `./script/run` (bundled and launched WarpLocal.app)
- `./script/run` (bundled and launched WarpLocal.app)
- `PATH=/tmp/warp-corepack-bin:$PATH
/Users/zach/Projects/warp_3/target/debug/integration
test_tab_context_menu_copies_metadata`
- `PATH=/tmp/warp-corepack-bin:$PATH
/Users/zach/Projects/warp_3/target/debug/integration
test_vertical_tab_context_menu_copies_metadata`
- `PATH=/tmp/warp-corepack-bin:$PATH
/Users/zach/Projects/warp_3/target/debug/integration
test_vertical_pane_context_menu_copies_metadata`
- `cargo fmt --manifest-path /Users/zach/Projects/warp_3/Cargo.toml
--all --check`
- `PATH=/tmp/warp-corepack-bin:$PATH cargo nextest run --manifest-path
/Users/zach/Projects/warp_3/Cargo.toml --no-fail-fast --workspace
test_tab_context_menu_copies_metadata
test_vertical_tab_context_menu_copies_metadata
test_vertical_pane_context_menu_copies_metadata`
- `PATH=/tmp/warp-corepack-bin:$PATH cargo clippy --manifest-path
/Users/zach/Projects/warp_3/Cargo.toml --workspace --all-targets
--all-features --tests -- -D warnings`
Note: initial nextest/clippy attempts without temporary Corepack shims
failed in `command-signatures-v2` because the global Yarn version is
1.22.22 while that crate requires Corepack/Yarn 4.0.1. Rerunning with
temporary Corepack shims passed.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
CHANGELOG-IMPROVEMENT: Added tab context menu actions to copy visible
tab and pane metadata when available.
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Adds the client-side follow-up for the Git Operations AI enterprise/tier
policy:
- Adds `isGitOperationsAiEnabled` to the client GraphQL schema and
`WarpAiPolicy` fragments/models.
- Converts the new policy into the app-level workspace billing model.
- Gates Git Operations AI requests and the “Commit & Pull Request
Generation” setting on the billing policy instead of the previous
hardcoded enterprise client gate.
- Removes the stale TODO that asked for this client-side gate.
This is intended to pair with the server-side schema/policy change in
warpdotdev/warp-server#10798. Keeping this PR as draft until the server
field is available to clients.
## Linked Issue
N/A — client follow-up for the server GraphQL schema/policy PR.
## Screenshots / Videos
N/A — this is policy/schema wiring. The existing setting is hidden when
the new billing policy disables Git Operations AI.
## Testing
- `cargo fmt --manifest-path
/Users/edward/Repos/edward-update-git-ops-ai-schema/Cargo.toml --all --
--check`
- `cargo clippy --manifest-path
/Users/edward/Repos/edward-update-git-ops-ai-schema/Cargo.toml -p
warp_graphql_schema -p warp_graphql -p warp --all-targets --all-features
--tests -- -D warnings`
- `git --no-pager diff --check`
No new integration test added; this is a small billing-policy plumbing
change that reuses existing settings/request gates.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
Agent conversation:
https://staging.warp.dev/conversation/281d784d-6c87-414f-89db-1b29f771f571
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
Co-authored-by: MaggieShan <sshan.maggie@gmail.com>
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
After posting a demo of local -> cloud handoff, I get some feedback
(from peter, varoon, and ZL) that it would be better to just open the
cloud mode session in the same pane as the local conversation. This
makes sense to me, and we're still forking the conversation and opening
up a new cloud mode pane so it's not like this is a destructive action
(someone can just close the cloud mode view and re-open the local
conversation view).
Implements REMOTE-1557
## Screenshots / Videos
<!-- Attach screenshots or a short video demonstrating the change, where
appropriate. Remove this section if it is not relevant to your PR. -->
demo: https://www.loom.com/share/d2f67ee4e15245959210ef41d1dfe7c6
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Description
On macOS, some Japanese IMEs (built-in macOS Japanese, Google Japanese
Input, etc.) commit a phrase mid-typing via a single
`interpretKeyEvents:` pass that fires `insertText:` (the just-committed
phrase) and then `setMarkedText:` (the next in-progress character). The
trailing `[self unmarkText]` in `keyDownImpl` was unconditionally
clobbering that freshly-set marked text in our state.
After that, the IME's internal state still held the queued character but
`WarpHostView`'s `markedText` was empty and `warp_marked_text_cleared`
had been dispatched. On the next keystroke (typically Enter
to commit), `wasComposing` was therefore `false`, so
`warp_handle_view_event` ran without the composing flag and the
keybinding system handled Enter as a command submission. The IME's
`insertText:` of the queued character arrived at the post-dispatch
insert path with `handled=YES` and was silently dropped.
The fix tracks whether the IME modified marked text via `setMarkedText:`
or `unmarkText` during the current `interpretKeyEvents:` pass, and skips
the trailing `unmarkText` if the IME has already touched
marked text in that pass — the IME has either cleared it (so our call
would have been a redundant `ClearMarkedText`) or replaced it with new
in-progress text we must preserve.
This change is contained to the macOS Objective-C IME plumbing in
`host_view.m`. The Linux/Windows IME path (winit `Ime::Preedit` /
`Ime::Commit` in `crates/warpui/src/windowing/winit/event_loop/mod.rs`)
is structurally different and not affected by this PR.
## Linked Issue
Fixes#7261
> Note: the issue body explicitly reports `Operating system (OS): macOS`
(`15.6(24G84)`), so the `os:linux` label appears to have been applied in
error during automated triage. This PR addresses the
macOS path only; please drop the `os:linux` label or relabel as `os:mac`
during review.
- [x] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [x] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).
## Screenshots / Videos
### Before Fix
https://github.com/user-attachments/assets/f3acf468-2860-4326-b8ab-f8ff4990d5a0
### After Fix
https://github.com/user-attachments/assets/a45d9c18-8619-4422-9406-e3cb66cc380e
## Testing
Manual verification on macOS 15.x with the macOS built-in Japanese IME
(Hiragana / Romaji mode):
1. Reproduced the bug on `master` with the steps from #7261 — typing
`漢字の入力(変換)が、` and pressing Enter dropped the trailing `、` and submitted
the buffer immediately.
2. Verified the fix on this branch with `cargo run --bin warp-oss` (with
`FeatureFlag::ImeMarkedText` enabled locally so inline preedit could be
observed). After the fix the queued `、` is preserved across
the split-commit, the next Enter commits it via the IME, and a
subsequent Enter submits the buffer as expected.
3. Sanity-checked dead-key composition (`⌥e` then `a` → `á`) on a US
keyboard layout to confirm the dead-key suppression branch in
`keyDownImpl` is unaffected.
4. Ran the presubmit checks locally:
- `cargo fmt --check` — pass
- `cargo clippy --workspace --exclude warp_completer --all-targets
--tests -- -D warnings` — pass
- `cargo clippy -p warp_completer --all-targets --tests -- -D warnings`
— pass
- `./script/run-clang-format.py -r --extensions 'c,h,cpp,m'
./crates/warpui/src/ ./app/src/` — pass
- `cargo nextest run --no-fail-fast --workspace --exclude
command-signatures-v2` — passes for the IME-relevant suites; the only
failures observed locally
(`settings::init::tests::test_migration_does_not_rerun_when_marker_present`
and the SSH-IAP integration suite) reproduce identically on `master` and
are unrelated to this change.
- `cargo test --doc` — pass
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
<!--
CHANGELOG-BUG-FIX: Fix Japanese IME losing the last character of a
phrase that ends right before a punctuation mark on macOS.
-->
## Description
We were running three steps in parallel with `futures::join!`
1. Check binary
2. Check old binary for autoupdate
3. Detect platform
This will end up using 3 control master connections. Since each
connection is a limited resource, this could cause these open failed
issues.
For now I am moving these to be sequential. I considered combining them
into one command and have some client side parsing to reconstruct the
results but I am not confident about that change with different shells
and potential error states. We could observe if latency with sequential
execution becomes a problem and decide if we want to further optimize
## Problem
Sentry issue `WARP-CLIENT-DEV-NYY`: `panic: Invalid edit range
4042..3982` in `Buffer::edit`.
When the AI agent produces a multi-hunk V4A diff where one hunk's
matched range subsumes another's (e.g. a large deletion whose context
window overlaps a nearby single-line edit), `fuzzy_match_v4a_diffs`
produces `DiffDelta`s with overlapping `replacement_line_range` values.
When `CodeEditorModel::apply_diffs` later converts these to char offsets
and feeds them to `insert_at_offsets`, the editor's `Buffer::edit`
panics on the invalid range.
Confirmed via MAA conversation `d71bf84b` (request `b621adb3`): a
17-hunk V4A diff against `mod.rs` produced overlapping deltas (lines
46..71 subsuming 64..65).
## Fix
**Diff layer** (`crates/ai/src/diff_validation/mod.rs`):
- Added `deduplicate_overlapping_deltas()` — after matching all hunks,
sort deltas by start line and drop any delta whose range overlaps with a
preceding one.
**Editor safeguard** (`crates/editor/src/content/core.rs`):
- In `apply_core_edit_actions()`, skip any action whose anchor-resolved
range has `start > end` instead of panicking. Returns
`EditResult::default()` if all actions are skipped.
## Tests
- `test_v4a_maa_crash_d71bf84b_no_overlapping_deltas` — uses the exact
V4A hunks from the crash to verify the subsumed delta is dropped (1
delta survives, not 2).
- `test_insert_at_offsets_overlapping_ranges_skipped` — passes inverted
char-offset range (`4042..3982`) to `insert_at_offsets` and verifies the
buffer is unchanged (edit gracefully skipped).
Fixes WARP-CLIENT-DEV-NYY
The file picker capped combined filename + path length at 55 characters,
leaving significant horizontal space unused in wider popovers. Drops
that cap for the command palette file picker and switches the path text
to render a leading `…` (instead of a fade) when overflow does happen.
Also fixes a latent paint bug in `Start + Ellipsis` text clipping: the
ellipsis-reservation shifted glyphs leftward without compensating their
origin, so the leftmost visible glyph overlapped the ellipsis at the
same x. Adds regression-protection unit tests for the start-clipping
paint path.
Fixeswarpdotdev/warp#8709
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
What is a design buddy?
## Linked Issue
<!--
Link the GitHub issue this PR addresses. Before opening this PR, please
confirm:
-->
- [ ] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [X] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).
## Screenshots / Videos
<img width="1774" height="1326" alt="Screenshot_redacted_2"
src="https://github.com/user-attachments/assets/596bb770-d64f-443c-9da9-30e4fe0bf727"
/>
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
-->
Look at the PR.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
Used claude code.
<!--
## Changelog Entries for Stable
The entries below will be used when constructing a soft-copy of the
stable release changelog. Leave blank or remove the lines if no entry in
the stable changelog is needed. Entries should be on the same line,
without the `{{` `}}` brackets. You can use multiple lines, even of the
same type. The valid suffixes are:
* NEW-FEATURE: for new, relatively sizable features. Features listed
here will likely have docs / social media posts / marketing launches
associated with them, so use sparingly.
* IMPROVEMENT: for new functionality of existing features.
* BUG-FIX: for fixes related to known bugs or regressions.
* IMAGE: the image specified by the URL (hosted on GCP) will be added to
Dev & Preview releases. For Stable releases, see the pinned doc in the
#release Slack channel.
* OZ: Oz-related updates. Use `CHANGELOG-OZ`. At most 4 Oz updates are
shown in-app per release.
CHANGELOG-NEW-FEATURE: {{text goes here...}}
CHANGELOG-IMPROVEMENT: {{text goes here...}}
CHANGELOG-BUG-FIX: {{text goes here...}}
CHANGELOG-BUG-FIX: {{more text goes here...}}
CHANGELOG-IMAGE: {{GCP-hosted URL goes here...}}
CHANGELOG-OZ: {{text goes here...}}
-->
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
This PR introduces a new `HarnessAvailabilityModel`, following
server-side changes to expose the list of available harnesses for use
with Oz in the `availableHarnesses` section of the `User` GraphQL query.
We model this new model (ha) after the existing models (ha) model, which
stores the list of available LLMs (`LLMPreferences`) that we get from
the server.
We also update the cloud mode UI, management view filter, and CLI so
that we check this model to determine the list of harnesses to display
(rather than hardcoding them), as well as to show enabled/disabled state
when triggering something from cloud mode.
## Screenshots / Videos
<!-- Attach screenshots or a short video demonstrating the change, where
appropriate. Remove this section if it is not relevant to your PR. -->
Example of disabled state for harnesses in cloud mode:
<img width="878" height="419" alt="image"
src="https://github.com/user-attachments/assets/a2b62e18-2a65-42aa-8b5b-c45b58d22855"
/>
No harnesses available state:
https://www.loom.com/share/65d9ed8f52be4a5ba4b1e320fdddff0b
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
-->
Tested locally, ensuring that:
- Disabled harnesses show up correctly
- Non-feature-flag-enabled harnesses don't show up
- Different UI surfaces all reflect the list from the server
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Description
First half of Phase 2 of REMOTE-1370. Adds the GraphQL plumbing for
\`taskGitCredentials\` so the driver can call it in the next PR.
**Changes:**
- Add \`taskGitCredentials\` types to \`schema.graphql\` and add to the
\`clientQueries\` allowlist in \`client-schema.ts\`
- New \`task_git_credentials.rs\` cynic query file, following the
\`task_secrets\` pattern
- Add \`GitCredential\` struct and \`get_task_git_credentials\` to
\`AIClient\` trait + \`ServerApi\` implementation
No behaviour change — nothing calls \`get_task_git_credentials\` yet;
that's in the follow-on PR.
**schema.graphql approach:** \`yarn generate -p staging\` was run to
verify the new types, but the output was not committed wholesale because
the current staging server also has other unrelated schema changes
(removed \`freeAvailableModels\`, new \`VOYAGE_4_512\` EmbeddingConfig
variant, etc.) that are out of scope and would break existing Rust
bindings. Instead, only the \`taskGitCredentials\` types were
cherry-picked — the field names, nullability, and doc comments were
verified to be identical to what the server generates.
Warp-server staging is deployed with the new query.
Followed by: #10153.
## Linked Issue
Linear: REMOTE-1370
## Testing
- \`cargo build -p warp\` clean
- \`cargo fmt\` and \`cargo clippy\` clean
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
Conversation:
https://staging.warp.dev/conversation/e16dc3e2-8e2f-4499-8c9b-59b200e17c50
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
Co-authored-by: oz-for-oss[bot] <277970191+oz-for-oss[bot]@users.noreply.github.com>
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
This PR implements the UI for the local -> cloud handoff flow in the
client. This is done levaraging the workspace-discovery and snapshotting
functionality added in the PRs below this one. On chip-click, we
snapshot the conversation's touched files and repos, and create a new
cloud mode pane to kick off a run. When the user submits a query, we
kick that run off.
Don't over-index on the UI too much — in a follow-up PR I'll add the
conversation into the cloud mode pane and also re-use the full cloud
mode setup v2 UI.
The associated server PR for this client PR is here:
https://github.com/warpdotdev/warp-server/pull/10777
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
demo: https://www.loom.com/share/a6caa2c974e34b49b2b038a8019c062c
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Description
Adds the client-side orchestration config UI on plan cards, auto-launch
for matching `run_agents` tool calls, and per-conversation config
scoping. This builds on top of the Stage 1 confirmation card and shared
controls.
**Demo:** https://www.loom.com/share/18e96159e91641e3b6a78924ea1b9f76
### What
**Plan card config block** — An inline config block on plan cards with:
- Approval toggle (pill switch) controlling whether orchestration is
enabled
- "View details" expand/collapse for Cloud/Local picker, harness, host,
environment, and model dropdowns
- Vertical full-width layout matching the Figma mock
- Dirty-sync transport: config changes piggybacked onto the next
outbound request as `OrchestrationConfigUpdate`
**Auto-launch** — When the user approves a config and the agent sends a
matching `run_agents` tool call, the confirmation card is skipped and
agents spawn immediately. Deferred to stream completion via
`ActionBlockedOnUserConfirmation` to handle streaming timing.
**Per-conversation scoping** — Orchestration config moved from the
`AIDocumentModel` singleton to per-conversation `AIConversation` storage
(following the `todo_lists` pattern), preventing config from one
conversation leaking into another.
**Reactive config hydration** — `OrchestrationConfigSnapshot` messages
are processed inline in `apply_client_action()` as they arrive, rather
than scanning all messages on every streaming update. Scanning is only
used for conversation restore.
### Architecture
- `crates/ai/src/agent/orchestration_config.rs` — Rust-native types,
`matches_active_config()` with 15 unit tests
- `app/src/ai/blocklist/inline_action/orchestration_controls.rs` —
Shared controls (trait-based generic pickers) used by both the
confirmation card editor and the plan card config block
- `app/src/ai/document/orchestration_config_block.rs` — Plan card config
block view
- Config block and document view subscribe directly to
`BlocklistAIHistoryEvent::OrchestrationConfigUpdated` (no passthrough
relay)
## Testing
- 40 unit tests for `run_agents_card_view` (21 new covering
auto-launch/auto-deny decision logic)
- 15 unit tests for `orchestration_config` (matching, proto round-trips)
- 37 orchestration integration tests passing
- Manual validation against the [validation
checklist](https://staging.warp.dev/conversation/028e6a5d-0a9f-4e4d-84a6-b03f80a77331)
covering plan card UI, dirty sync, per-conversation scoping,
auto-launch, confirmation card, and edge cases
## Server API dependencies
- Relies on `OrchestrationConfigSnapshot` and
`OrchestrationConfigUpdate` proto messages (already deployed)
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
[Conversation](https://staging.warp.dev/conversation/028e6a5d-0a9f-4e4d-84a6-b03f80a77331)
| [Plan](https://staging.warp.dev/drive/notebook/xxRB6SLGbQc23j2NGObZsq)
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
We are seeing ~850 Sentry errors in 2 days
([WARP-CLIENT-BETA-STABLE-7JNH](https://warpdotdev.sentry.io/issues/7456268110/))
from doomed reconnect attempts after SSH disconnects caused by system
sleep / network loss.
When the Mac sleeps, the SSH TCP connection dies but the ControlMaster
process stays alive locally (no keepalives configured). The
`remote-server-proxy` reader task detects EOF and triggers reconnect,
but reconnecting through the same ControlMaster is futile since its TCP
connection is dead. Both attempts fail with "Response channel closed
before receiving a reply" and the errors get reported to Sentry.
**Root cause**: the reconnect flow had no way to distinguish a
recoverable disconnect (remote server process crashed, SSH connection
still alive) from an unrecoverable one (SSH connection itself is dead).
**Fix**: Add `is_reconnectable(exit_status)` to the `RemoteTransport`
trait so each transport can decide whether a reconnect is viable.
`SshTransport` returns `false` when the exit code is 255 (SSH
connection-level error) or the process was signal-killed, indicating the
ControlMaster connection is dead. `mark_session_disconnected` consults
the transport before entering the reconnect loop.
This is a required trait method (no default impl) so future transports
must explicitly consider reconnectability.
### Changes
- **`RemoteTransport` trait** (`transport.rs`): Added required
`is_reconnectable` method
- **`SshTransport`** (`ssh_transport.rs`): Implements `is_reconnectable`
— returns `false` for exit code 255 / signal kill
- **`RemoteServerManager`** (`manager.rs`): `mark_session_disconnected`
calls `transport.is_reconnectable()` before attempting reconnect;
extracted `finalize_disconnect` helper to deduplicate the
disconnect-and-emit pattern
## Linked Issue
- Sentry:
[WARP-CLIENT-BETA-STABLE-7JNH](https://warpdotdev.sentry.io/issues/7456268110/)
## Testing
- `cargo clippy` passes on both `remote_server` and `warp` crates
- All 48 `remote_server` tests pass
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
[Conversation](https://staging.warp.dev/conversation/ead2a14e-5ddd-4fe6-9a04-5ce7f48ec84f)
<!--
CHANGELOG-BUG-FIX: Fixed unnecessary reconnect attempts for remote SSH
sessions after system sleep, reducing error noise
-->
The `settings` crate previously couldn't depend on `warp_features`, so
we plumbed `FeatureFlag::SettingsFile.is_enabled()` into a
process-global `SETTINGS_FILE_ENABLED: AtomicBool` at startup and the
crate read that mirror instead. The dependency restriction is gone, so
this PR removes the indirection and calls the feature flag directly from
the settings crate.
## Description
Client-side implementation of the `RunAgents` orchestration tool, paired
with server PR https://github.com/warpdotdev/warp-server/pull/10809.
### What
- **RunAgentsCardView**: confirmation card UI with inline editor for
model, harness, environment, host, and execution mode (Local/Cloud)
- **RunAgentsExecutor**: executor that dispatches accepted requests,
spawning child agent conversations via `StartAgentExecutor`
- **Cancel handling**: card subscribes to `FinishedAction` events so
Ctrl+C (both card-level and terminal-level) shows the cancelled state
- **Harness support**: Oz, Claude, Gemini, Codex with brand icons;
local-dev host gated on `Channel::Local`
- **Spawning card**: in-flight "Spawning N agents..." status while
children are being launched
- **Proto adoption**: `RunAgents` request/result types, `Harness` oneof
shape, `StartAgentV2` advertised alongside `Orchestrate`
### Demo
https://www.loom.com/share/dacad55f436b42d29191bf54461ab3cf
## Testing
- Manual validation of accept, reject (Ctrl+C), edit/discard, picker
interactions, local and cloud execution modes
- Existing tests updated for new harness list and import ordering
## Server API dependencies
- [x] Does this change rely on a new server API?
- Server PR: https://github.com/warpdotdev/warp-server/pull/10809
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
This removes `FeatureFlag::BlocklistMarkdownImages` from
`PREVIEW_FLAGS`.
We accidentally promoted inline Markdown image rendering in the AI block
list to Stable in the latest release because `blocklist_markdown_images`
is already enabled in the default Cargo feature list. This PR aligns the
runtime flag lists with that Stable enablement path so the feature is no
longer treated as Preview-exclusive.
Mermaid rendering is also already enabled for Stable via the default
`markdown_mermaid` Cargo feature. Together, these defaults allow Stable
builds to render inline Markdown images and Mermaid diagrams in agent
block output.
## Linked Issue
N/A
## Screenshots / Videos
N/A — flag-list cleanup only.
## Testing
- `cargo fmt`
- `cargo clippy --workspace --all-targets --all-features --tests -- -D
warnings`
Note: the first clippy attempt failed before Rust checks because
`command-signatures-v2` required Yarn 4 via Corepack while the shell had
Yarn 1.22. I ran `corepack enable` and reran clippy successfully.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-IMPROVEMENT: Warp now renders inline local images and Mermaid
diagrams in agent block output.
Co-Authored-By: Oz <oz-agent@warp.dev>
Agent artifacts:
- Conversation:
https://staging.warp.dev/conversation/7967da60-8ae2-4747-9db4-3bb49f727a32
Co-authored-by: Oz <oz-agent@warp.dev>
Fixes#9036.
## Description
On Windows, non-Latin keyboard layouts (Cyrillic, Greek, Arabic, etc.)
translate the physical key to a non-ASCII character even when Ctrl/Cmd
is held. That makes bindings like `ctrl-c` / `ctrl-v` (and the
terminal's copy/paste shortcuts) fail to match — users have to switch
their system layout to English just to copy or paste in Warp.
This change detects that situation in `convert_keyboard_input_event` and
substitutes the US-QWERTY character that the physical key would produce,
so chord shortcuts work regardless of the active OS layout. Same
approach used by VS Code, JetBrains, and Chromium.
The fallback is gated on `cfg(windows)` and on Ctrl/Super being held
with a non-ASCII character — typed text on non-Latin layouts is
unaffected.
## Testing
Unit tests in `key_events_tests.rs` cover the new
`us_qwerty_fallback_for_chord` helper:
- Letter mappings (`KeyA` → `a`, etc.)
- Digit and punctuation mappings
- Returns `None` for keys outside the chord-shortcut set (function keys,
modifiers, navigation), so the original `logical_key` is preserved
- Returns `None` for `PhysicalKey::Unidentified`
Manually verified on Windows:
- [x] Copy / Select All / Paste with English (US) layout
- [x] Copy / Select All / Paste with Russian layout
- [x] Copy / Select All / Paste with German layout
- [x] AltGr (Right Alt) bindings with German layout
## Server API dependencies
No server API changes.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
CHANGELOG-BUG-FIX: Fixed Ctrl/Cmd shortcuts (e.g. copy, paste) failing
on Windows when a non-Latin keyboard layout was active.
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
Fixes orchestration v2 parent/child agent wake-up and messaging behavior
for remote child agents.
This PR updates the client-side orchestration flow so that incoming
parent-agent messages wake remote child agents through the server run
follow-up path instead of trying to treat them like local dormant Claude
harnesses. Previously, a remote child could receive the parent’s
message, but it would not be restarted correctly in a harness and could
fail or hang when trying to send a message back to the parent.
Main changes:
• Adds a remote-child wake path in the blocklist AI controller:
◦ detects remote child conversations with pending parent-agent message
events
◦ submits a run follow-up to agent/runs/{run_id}/followups
◦ removes delivered pending message events after successful follow-up
submission
◦ retries/logs failures instead of silently hanging
• Keeps local dormant Claude wake behavior separate from remote child
wake behavior.
• Restores remote hidden child panes as cloud/ambient agent panes
instead of local terminal-backed child panes.
• Ensures restored remote child panes enter the existing ambient session
in AgentRunning state.
• Persists and restores remote-child conversation metadata so the client
can distinguish local children from remote children across reloads.
• Improves orchestration v2 message sending:
◦ uses task-scoped server APIs when available
◦ adds bounded timeouts and error logging for send failures
◦ surfaces failures instead of leaving action execution indefinitely
pending
• Adds regression coverage for:
◦ remote child conversation restoration
◦ remote child pane/session state
◦ task-scoped ambient agent messaging
◦ orchestration v2 message/error behavior
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
## Server API dependencies
<!-- You may remove this section if your PR does not have any server
dependencies. -->
- [ ] Is this change necessary to make the client compatible with a
desired [server API breaking
change](https://www.notion.so/warpdev/How-to-safely-introduce-server-API-breaking-changes-0aa805ff5d5d41fd8834f3c95caba0b4?pvs=4#d55ecf8aea3449949d3c33b0e67f6800)?
- [ ] Does this change rely on a [new server
API](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#04da1e6a493542d68b3e998c7d339640)?
- [ ] If so, is the use of this API restricted to client channels that
rely on the staging server (e.g. WarpDev)?
- [ ] Is this change enabling the use of a server API on client channels
that rely on the production server (e.g. WarpStable)?
- [ ] If so, has the new server API been stable on production for at
least one server release cycle? See
[here](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#73b202f939834b97ab1fbdf7fc82cd53)
for more details.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
<!--
The entries below will be used when constructing a soft-copy of the
stable release changelog. Leave blank or remove the lines if no entry in
the stable changelog is needed. Entries should be on the same line,
without the `{{` `}}` brackets. You can use multiple lines, even of the
same type. The valid suffixes are:
* NEW-FEATURE: for new, relatively sizable features. Features listed
here will likely have docs / social media posts / marketing launches
associated with them, so use sparingly.
* IMPROVEMENT: for new functionality of existing features.
* BUG-FIX: for fixes related to known bugs or regressions.
* IMAGE: the image specified by the URL (hosted on GCP) will be added to
Dev & Preview releases. For Stable releases, see the pinned doc in the
#release Slack channel.
* OZ: Oz-related updates. Use `CHANGELOG-OZ`. At most 4 Oz updates are
shown in-app per release.
-->
CHANGELOG-NEW-FEATURE: {{text goes here...}}
CHANGELOG-IMPROVEMENT: {{text goes here...}}
CHANGELOG-BUG-FIX: {{text goes here...}}
CHANGELOG-BUG-FIX: {{more text goes here...}}
CHANGELOG-IMAGE: {{GCP-hosted URL goes here...}}
CHANGELOG-OZ: {{text goes here...}}
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Adds Chrome-style cross-window tab dragging behind the
`DragTabsToWindows` feature flag. A user can drag a tab out of a window
to create a new one, drag it into another window's tab bar to attach it,
and keep dragging through multiple attach/detach cycles without
releasing the mouse.
Product behavior is fully described in
`specs/pei/cross-window-tab-drag/PRODUCT.md`; the architectural
rationale is in `specs/pei/cross-window-tab-drag/TECH.md`.
https://www.loom.com/share/94d21b4b573c4f6893684142d66b844a
## How it works
A cross-window drag has two shapes depending on where it starts:
- **Single-tab window** — the source window itself follows the cursor
and acts as the drag preview. No second window is created.
- **Multi-tab window** — when the user drags a tab out of the tab bar, a
dedicated preview window is spun up to hold the dragged tab, and the
source window stays in place showing its remaining tabs.
As the user drags, we continuously hit-test the cursor against the tab
bars of other windows in z-order. When the cursor enters an eligible tab
bar we show a lightweight ghost (insertion slot + floating chip) in the
target; the live view tree only moves at drop time, except in the
back-to-caller case where the tab is transferred so the source window
can host real reordering. If the cursor leaves a target tab bar, any
handoff is reversed and the drag continues. On drop, the preview is
either promoted to a permanent window (no target), folded into the
target (handoff committed), or cleaned up (no-op).
## State machines
Full ASCII versions live in the module doc at
`app/src/workspace/cross_window_tab_drag.rs`. Mermaid renderings:
### Single-tab source window
```mermaid
stateDiagram-v2
[*] --> Floating: begin_single_tab_drag
Floating --> Transitioning: cursor enters target tab bar
Transitioning --> InsertedInTarget
InsertedInTarget --> Floating: cursor leaves target tab bar (reverse_handoff)
InsertedInTarget --> FinalizeHandoff: on_drop while inserted
Floating --> FinalizeFloatingWindow: on_drop while floating
FinalizeHandoff --> [*]
FinalizeFloatingWindow --> [*]
```
The source window itself is the preview, so no extra window is created.
`FinalizeFloatingWindow` just leaves the source window where the user
dropped it.
### Multi-tab source window
```mermaid
stateDiagram-v2
[*] --> Floating: begin_multi_tab_drag (creates preview window)
Floating --> GhostInTarget: cursor enters target tab bar (deferred)
GhostInTarget --> Floating: cursor leaves target tab bar
Floating --> Transitioning: cursor re-enters source (back-to-caller)
Transitioning --> InsertedInTarget
InsertedInTarget --> Floating: cursor leaves source tab bar (reverse_handoff)
InsertedInTarget --> FinalizeHandoff: on_drop while inserted
GhostInTarget --> FinalizeHandoff: on_drop over target
Floating --> FinalizePreviewAsNewWindow: on_drop while floating
FinalizeHandoff --> [*]
FinalizePreviewAsNewWindow --> [*]
```
`GhostInTarget` is a hover-only state — no view-tree transfer happens
until drop. The `InsertedInTarget` branch is reserved for the
back-to-caller path, where the preview must be kept alive so the user
can drag the tab back out again.
## Infrastructure changes
Most of the diff lands in shared infrastructure rather than in
feature-specific code. Each piece exists to satisfy a specific product
invariant:
- **Move a live tab between windows without restarting it.** A user
dragging a tab between windows expects their terminal, scrollback, agent
state, and animations to be preserved — kill-and-respawn would break the
illusion of one continuous gesture. WarpUI gains the ability to relocate
a live view tree (and its non-rendered structural children) into a
different window, which is what makes the dragged tab feel like the same
tab no matter which window is hosting it.
- **Make z-order observable so drop targeting matches what the user
sees.** When windows overlap, dropping a tab "into" an occluded window
through the window in front of it would feel buggy. The window manager
now exposes front-to-back ordering so attach targeting only considers
windows that are actually reachable from the current cursor position.
- **Show preview windows without disrupting the user's typing context.**
A preview window appearing under the cursor would steal focus from
whatever the user was typing into and would briefly flash blank before
its content is ready. A new windowing primitive lets us materialize a
window at exact bounds without taking focus, paired with a
focus-suppression hook that covers the gap before the preview's content
paints for the first time.
- **Closing a window because its tab moved should be silent.** Today,
closing a window with running processes prompts "Close window?" and
tears down panes — both correct for normal closes, both wrong when the
window is closing only because its content moved elsewhere. New
workspace flags and a dedicated termination mode let transfer-driven
closes skip the prompt and the teardown, so the user never sees a dialog
that suggests data loss during a harmless transfer. Snapshots also skip
the temporary preview workspaces so they don't leak into persistence.
- **One owner of cross-window drag state.** Multiple windows mutating
each other in response to the same drag event is exactly the shape of
bug that produces duplicated tabs and stale subscriptions. Concentrating
the drag state machine in a singleton, with workspaces only reacting to
its returned decisions, removes the re-entrancy entirely and makes "what
state is the drag in?" a single question with a single answer.
- **One drag implementation across tab presentations.** Horizontal tabs
and the vertical tabs panel are different visual surfaces, but the user
expects identical drag behavior from both. Both UIs now emit the same
drag actions and feed the same orchestration code, which keeps them from
drifting apart and prevents accidental "works for horizontal, broken for
vertical" regressions.
- **Specs and integration tests.** Product behavior and architectural
decisions are checked into `specs/pei/cross-window-tab-drag/` so future
changes have something to preserve. Integration coverage exercises
detach, attach, reattach, reverse-handoff, target-side reorder, and
drop-outside flows behind the feature flag rather than gating on a
specific OS.
Behind a feature flag, so no change for users until it's rolled out.
## Testing
- New integration tests cover detach, attach, reattach, reverse-handoff,
reorder-in-target, and drop-outside scenarios.
- Manually verified single-tab and multi-tab drags against all scenarios
in `specs/pei/cross-window-tab-drag/PRODUCT.md` § Success Criteria on
macOS.
## Server API dependencies
No server dependencies.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-NEW-FEATURE: You can now drag tabs out of a window into their
own window, or between windows, similar to Chrome.
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
Given the fact that we're planning on accommodating multiple variants of
cloud agents, we need to change the agent icons in the conversation
list, notifications, pane header, and vertical tabs to support different
harnesses. Peter drew up some mocks for this, and we'll use the new icon
+ status variants across all of these surfaces.
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
demo: https://www.loom.com/share/066e5842bf0541fa808925100cc6529e
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Description
Two related fixes to the remote-server setup flow:
### 1. Gate remote-server install on a glibc preinstall check (APP-4281)
The prebuilt remote-server binary is linked against glibc 2.31. On older
Linux hosts (e.g. RHEL/Rocky/CentOS 8 with glibc 2.28) the binary
downloads fine but fails at runtime, leaving users stuck. This PR adds a
lightweight, fail-open preinstall probe that runs over the existing SSH
`ControlMaster` socket *before* any user-visible install affordance.
### 2. Don't fail the install when staging-dir cleanup races
`install_remote_server.sh` ran `trap 'rm -rf "$tmpdir"' EXIT` under `set
-e`. When `rm -rf` hit a "Directory not empty" / `EBUSY` race after the
binary had already been moved into place, the trap's non-zero exit
replaced the script's success exit, surfacing as `install script failed
(exit 1)` in the manager. The cleanup is now best-effort (`rm -rf
"$tmpdir" 2>/dev/null || true`) so post-success races no longer break
the install. Real install failures (curl, tar, missing binary,
unsupported arch/OS) still propagate normally because they happen before
the trap fires.
Fixes APP-4281
## Testing
Tested locally with an RHEL 7 docker container (which uses glibc 2.28)
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
[Conversation](https://staging.warp.dev/conversation/86cbc3ea-d9de-4b23-832a-fa8b23c0f295)
· [Tech
spec](https://staging.warp.dev/drive/notebook/oGmQYNHrHzuGx3FegfsEuQ)
<!--
CHANGELOG-IMPROVEMENT: Warp now silently falls back to a regular SSH
session on remote hosts where the prebuilt remote-server binary is
incompatible (e.g. glibc < 2.31), instead of attempting an install that
would fail at runtime.
CHANGELOG-BUG-FIX: Remote-server installs no longer fail when the
staging-directory cleanup hits a "Directory not empty" race after the
binary has already been moved into place.
-->
Co-Authored-By: Oz <oz-agent@warp.dev>
## Description
Fixes#9213. On macOS, `.command` is the standard extension for
double-clickable shell scripts (a `#!/usr/bin/env bash` file you can
`chmod +x` and run from Finder). Opening one in Warp's editor today
shows "Language support is unavailable for this file type" because
`language_by_filename` in `crates/languages/src/lib.rs` doesn't include
`command` next to the existing `sh | zsh | bash` shell extensions.
```diff
- "sh" | "zsh" | "bash" => language_by_name("shell"),
+ "sh" | "zsh" | "bash" | "command" => language_by_name("shell"),
```
## Testing
- Added `command_extension_resolves_to_shell` in
`crates/languages/src/lib_tests.rs` that calls
`language_by_filename(Path::new("script.command"))` and asserts the
returned language's `display_name` is `"Shell"` — fails on master,
passes after the fix.
- `cargo fmt -p languages -- --check` passes locally.
- Couldn't run `cargo nextest run -p languages` locally because the
Metal toolchain isn't installed (same situation as #9277), so relying on
CI for the full clippy / nextest pass.
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: `.command` shell scripts now open with shell syntax
highlighting in Warp's editor.
Co-authored-by: anshul-garg27 <anshul-garg27@users.noreply.github.com>
Most `target_os = "linux"` cfg sites in this tree gate code that already
works fine on FreeBSD. wayland-client, cctk, fontconfig, x11rb,
native-dialog, notify-rust, and the WindowingSystem enum all compile and
run there using the existing Linux branches. Widening those cfg guards
from `target_os = "linux"` to `any(target_os = "linux", target_os =
"freebsd")` is enough to get a working build.
The change is mechanical: 79 files across `app/` and `crates/`, all of
them just adjusting the cfg.
One Linux-only carveout: `InputFlags::IUTF8` in
`app/src/terminal/local_tty/unix.rs`. nix does not expose that termios
input flag on FreeBSD, and the PTY works without it.
Linux, macOS, and Windows are unaffected by construction: every widened
cfg already evaluated true on Linux and continues to; neither macOS nor
Windows ever matched these guards.
Tested by building `warp-oss` on FreeBSD 16-CURRENT amd64 with rust 1.92
and launching it under wayland (niri).
<img width="2560" height="1440" alt="image"
src="https://github.com/user-attachments/assets/085f3b8c-621c-4fbb-adc8-69daebc03d3a"
/>
## Description
We currently have a bug with session restoration where maximized windows
won't restore into the maximized state. This is due to the "vertical
adjustment" code which tries to make sure the title bar is on screen (it
moves the window downward if that isn't the case). Without getting too
much into the details, on Windows when windows are maximized, winit
reports the physical size of the window _as if_ it had the native window
decorations, even when it doesn't. It treats the native title bar as
being off the screen and represents that with a negative origin (above
the screen). This triggers `fn maybe_adjust_window_vertically` to return
a value which triggers the caller to try to move the window which makes
Windows un-maximize the window. This simple guard fixes the problem
## Testing
1. Run Warp on Windows
2. Make sure session restoration is enabled
3. Maximize the window
4. quit warp
5. Start warp again
6. The window should be maximized but it isn't
On this branch, that bug no longer occurs.
## Description
Refs #9522.
After #9513 bundled `LICENSE-ALACRITTY` and added attribution headers to
the original tranche of derivative files, [@chrisduerr (Alacritty
maintainer) followed
up](https://github.com/warpdotdev/warp/issues/9522#issuecomment-4350152049)
and named two specific files that were still missing attribution:
> - This is an almost verbatim copy of VTE's ansi.rs module:
> `crates/warp_terminal/src/model/ansi/control_sequence_parameters.rs`
> - This function (and several others) are also verbatim copies:
> `app/src/terminal/grid_renderer/cell_type.rs:L160`
This PR adds the same two-line "adapted from … under the Apache license"
comment header that #9513 introduced, pointing to the same bundled
`crates/warp_terminal/src/model/LICENSE-ALACRITTY`:
| File | Attribution |
| ---- | ----------- |
| `crates/warp_terminal/src/model/ansi/control_sequence_parameters.rs` |
"adapted from the vte crate (an Alacritty project)" — file-wide |
| `app/src/terminal/grid_renderer/cell_type.rs` | "color-mapping helpers
(`compute_fg_rgb`, `compute_bg_rgb`, `get_override_color`) below are
adapted from the alacritty_terminal crate" — scoped because `Secret` /
`IsFocused` / `CellType` at the top of the file are Warp-specific |
Both files now point to the existing
`crates/warp_terminal/src/model/LICENSE-ALACRITTY` (Apache-2.0 — the
same license `vte` and `alacritty_terminal` both ship under). No
license-file changes are needed.
This is documentation/attribution only — no functional changes.
## Scope
This PR addresses the **two files explicitly cited** in #9522 by the
Alacritty maintainer. The cited comment also says "this function and
several others" — the "several others" likely includes the
immediately-adjacent `compute_bg_rgb` and `get_override_color` helpers
in the same `cell_type.rs` (they are similar verbatim ports), which is
why this PR's attribution covers all three of them. A broader audit of
files that *might* be derivative beyond what's explicitly cited is best
done by Warp's team or the Alacritty maintainers directly, since it
requires intimate knowledge of upstream history; happy to extend this PR
to cover any additional files that get flagged.
## Testing
Documentation/comments only. `cargo fmt -- --check` clean. No code paths
affected.
## Server API dependencies
- [ ] No server impact.
## Agent Mode
- [ ] Warp Agent Mode
## Changelog Entries for Stable
(None — internal/legal attribution metadata.)
Fixes#9517
## Description
Meta+enter (among others) was sending the ESC plus the literal string
`enter` instead of anything reasonable! This has been bothering me for
ages and is because `meta_keystroke_to_escape_sequence` falls back to
sending the key name as literal ASCII bytes when the key isn't in
map_special_key_to_bytes.
Add the missing entries to map_special_key_to_bytes:
- enter/numpadenter → CR (\r)
- tab → HT (\t)
- escape → ESC (\x1b)
## Testing
Didn't add tests as I think they'd just be repeating the implementation.
## Server API dependencies
<!-- You may remove this section if your PR does not have any server
dependencies. -->
- [ ] Is this change necessary to make the client compatible with a
desired [server API breaking
change](https://www.notion.so/warpdev/How-to-safely-introduce-server-API-breaking-changes-0aa805ff5d5d41fd8834f3c95caba0b4?pvs=4#d55ecf8aea3449949d3c33b0e67f6800)?
- [ ] Does this change rely on a [new server
API](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#04da1e6a493542d68b3e998c7d339640)?
- [ ] If so, is the use of this API restricted to client channels that
rely on the staging server (e.g. WarpDev)?
- [ ] Is this change enabling the use of a server API on client channels
that rely on the production server (e.g. WarpStable)?
- [ ] If so, has the new server API been stable on production for at
least one server release cycle? See
[here](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#73b202f939834b97ab1fbdf7fc82cd53)
for more details.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: Fixed Option+Enter, Option+Tab, and Option+Escape
sending literal key names instead of correct escape sequences
## Description
Fixes APP-4002
<img width="444" height="303" alt="Screenshot 2026-04-28 at 5 42 20 PM"
src="https://github.com/user-attachments/assets/1c45e5fa-1a20-4aa9-8666-c6d59b781fa5"
/>
This is a defensively coded UI in case something else leads to missing
file contexts.
<img width="469" height="113" alt="Screenshot 2026-04-28 at 5 40 44 PM"
src="https://github.com/user-attachments/assets/f2bd2c03-c529-49a2-8c6c-4d1efdc37544"
/>
When an LLM requests a `read_files` tool call with line ranges entirely
beyond EOF (e.g., lines 1891–2090 of a 1237-line file), the client
returns `ReadFilesResult::Success { files: [] }` — the file silently
vanishes from the result. This renders as an empty box with a green
checkmark in the blocklist UI.
**Root cause:** `TextFileAccumulator::flush_range` only emitted a
segment on final flush for whole-file reads (`final_flush &&
self.whole_file`). For ranged reads where no lines fall within the
requested range, the buffer stays empty and no segment is emitted. The
file ends up in neither `file_contexts` nor `missing_files`.
**Fix:**
1. **Primary:** Change `flush_range` to always emit a segment on final
flush (`!self.buf.is_empty() || final_flush`), so every requested range
produces a `TextFileSegment` even when entirely past EOF.
2. **Defensive:** Add rendering fallback that shows a red X error box
with "Failed to read files" when `ReadFilesResult::Success` has empty
`file_contexts`, preventing empty boxes for any future edge case.
3. **Tests:** Updated existing test and added two new tests covering
out-of-bounds ranges on non-empty files.
## Testing
- Updated `empty_file_with_ranges_produces_no_segment` →
`empty_file_with_ranges_produces_empty_segment` (expects 1 segment with
empty content)
- Added `range_past_eof_produces_empty_segment` — 5-line file, range
10..15
- Added `multiple_ranges_some_past_eof` — 5-line file, ranges [1..3,
10..15]
- All 23 text_file_reader tests pass
- `cargo fmt` and `cargo clippy` clean
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: Fixed read_files tool showing an empty box when the
LLM requests line ranges beyond the end of a file.
---
[Conversation](https://staging.warp.dev/conversation/ef9f9688-ca1e-4eb3-b29a-35c5c13e80da)
| [Plan](https://staging.warp.dev/drive/notebook/lAlU2uG6KN5y96mdmk8wYL)
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
`language_by_filename` in `crates/languages/src/lib.rs` recognizes
`.html` but not the legacy three-character `.htm` extension. `.htm` is
widely produced by static-site generators and historical web tooling
(DOS 8.3 filename limits), and is already treated as an HTML/text file
elsewhere in the codebase: see `is_development_text_extension` in
`crates/warp_util/src/file_type.rs:225`, which lists `"html" | "htm"`
together.
Opening a `.htm` file in Warp's editor today shows "Language support is
unavailable for this file type" instead of HTML syntax highlighting.
This PR resolves the inconsistency.
```diff
- "html" => language_by_name("html"),
+ "html" | "htm" => language_by_name("html"),
```
## Testing
- Added `html_extensions_resolve_to_html` in
`crates/languages/src/lib_tests.rs` covering both `.html` and `.htm`.
The test calls `language_by_filename(Path::new("index.htm"))` and
asserts `display_name() == "HTML"`; fails on master, passes after the
change.
- `cargo fmt -p languages -- --check` passes locally.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-IMPROVEMENT: HTML files using the .htm extension now open with
HTML syntax highlighting in Warp's editor.
Co-authored-by: Suraj Gupta <39461854+szgupta@users.noreply.github.com>
## Description
The onboarding flow managed by `OnboardingCalloutModel` was getting
triggered when Warp runs in headless SDK/CLI mode. There is no real user
to interact with the callout in those runs, so the tutorial would
silently take over the input and discard the prompt the SDK had
submitted.
This PR adds an `AppExecutionMode::can_show_onboarding` gate (which
mirrors the other `is_app()`-based capability checks) and uses it to
skip every onboarding entry point in SDK mode:
- `Workspace::start_agent_onboarding_tutorial`
- `Workspace::dispatch_tutorial_when_bootstrapped`
- `Workspace::should_show_agent_onboarding`
- `Workspace::should_trigger_get_started_onboarding`
- `Workspace::check_and_trigger_onboarding`
In `App` mode behavior is unchanged.
## Testing
`cargo check -p warp_core` and `cargo check -p warp` both pass.
## Server API dependencies
No server changes.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: Don't trigger the agent onboarding tutorial when Warp
is running in headless SDK/CLI mode.
_Conversation:
https://staging.warp.dev/conversation/e7e67056-a174-4995-9fb0-54c104d09d12_
_Run:
https://oz.staging.warp.dev/runs/019dde8f-ff05-716f-8c3a-e7644e40f40d_
_This PR was generated with [Oz](https://warp.dev/oz)._
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
[APP-3805](https://linear.app/warpdotdev/issue/APP-3805/client-server-version-skew)
— handle client/server version skew for the SSH remote-server binary.
Previously the remote binary lived at a single unversioned path. When a
client updated but the remote still had an older binary, the two could
silently go out of sync.
This PR does three things:
1. **Version the installed path.** The binary is now written to
`{dir}/{binary_name}-{version}`, so any client-server drift becomes a
path miss and triggers a reinstall. The unversioned path is kept for
`cargo run` / `deploy_remote_server` dev loops.
2. **Check versions on handshake.** `initialize()` now compares
`server_version` against the client's release tag. On mismatch, the
manager deletes the stale binary, tears the session down, and emits
`SessionConnectionFailed` so the failed-banner path fires.
3. **Auto-update without a prompt.** When `check_binary()` misses but
the remote already has an install directory, we skip the "Install Warp
SSH tools?" modal and install directly with `is_update: true`. The
shimmer reads "Updating Warp SSH Extension..." instead of
"Installing...". Dev clients without a release tag fall through to the
normal prompt so they don't accidentally CDN-install over a
locally-deployed binary.
## Testing
- `cargo test -p remote_server`, `cargo clippy -D warnings`, `cargo fmt`
— all clean.
- Manual against `alokedesai@136.107.29.130`:
- Fresh install: modal → "Installing Warp SSH Extension..." → Ready.
- Reconnect with a newer client tag: handshake mismatch detected, stale
binary removed, reconnect reinstalls.
- Reconnect with an older client tag while a newer versioned binary is
on the remote: auto-update, no modal, "Updating..." shimmer.
- Forced install failure on the update path: failed banner renders.
## Server API dependencies
None — warp-server already supports `?version=` on `/download/cli`
(#10284).
---------
Co-authored-by: Oz <oz-agent@warp.dev>
### Description
Two README files in \`crates/\` had typos and one had an ambiguous file
reference:
**\`crates/warpui_core/README.md\`**
- \"to do describe\" → \"To describe\"
- \"appearence\" → \"appearance\"
- \"precicely\" → \"precisely\"
- \"handlign\" → \"handling\"
**\`crates/lsp/README.md\`**
- \"implmentation\" → \"implementation\"
- The README said \"See main.rs for an example implementation\" but
there is no \`main.rs\` in \`crates/lsp/src/\`. The example actually
lives at \`crates/lsp/examples/rust-lsp/main.rs\`, so I made the path
explicit.
Doc-only changes.
### Testing
Markdown only.
### Server API
No server changes.
### Agent Mode
Not applicable.
### Changelog Entries
None.
Co-authored-by: anshul-garg27 <anshul-garg27@users.noreply.github.com>
## Description
Adds Block's [Goose](https://github.com/block/goose) to the `CLIAgent`
enum so that running `goose` in a Warp terminal triggers the CLI-agent
toolbar, status, brand color, and icon — the same wrapper experience the
other recognized agents (Claude Code, Codex, Gemini, Amp, Droid,
OpenCode, Copilot, Pi, Auggie, Cursor) already get.
Without this change, `goose` runs as a plain terminal command and none
of the wrapper UI activates, even though the rest of the CLI-agent
infrastructure works fine for it once detection is in place.
Goose is wired in as a third-party agent without a first-party plugin
(mirroring Pi / Copilot / Cursor):
- No `CliAgentPluginManager` — falls through to the `None` arm in
`plugin_manager_for_with_shell`
- No `CLIAgentSessionHandler` — falls through to the `None` arm in
`create_handler`, and is implicitly excluded from `is_agent_supported`
via `matches!`
- Default `Inline` rich-input submit strategy
The `enum_iterator::Sequence`-driven detection in `CLIAgent::detect`
picks `goose` up automatically from `command_prefix()`, so no detection
plumbing is needed beyond the variant.
### Files touched
| File | Change |
|---|---|
| `app/src/terminal/cli_agent.rs` | New `GOOSE_COLOR` const (`#101010`),
`Goose` enum variant, match arms in `command_prefix`, `display_name`,
`icon`, `supported_skill_providers`, `brand_color`, `From<CLIAgent> for
CLIAgentType` |
| `app/src/server/telemetry/events.rs` | `CLIAgentType::Goose` |
| `crates/warp_core/src/ui/icons.rs` | `Icon::GooseLogo` + path mapping
`bundled/svg/goose.svg` |
| `app/assets/bundled/svg/goose.svg` | Official Block/Goose logo
(Apache-2.0), re-saved with the bundled-SVG `#FF0000` placeholder fill
so the runtime icon renderer applies the brand color |
| `app/src/terminal/cli_agent_sessions/plugin_manager/mod.rs` | Add
`CLIAgent::Goose` to the no-plugin-manager arm |
| `app/src/terminal/cli_agent_sessions/listener/mod.rs` | Add
`CLIAgent::Goose` to the no-handler arm |
| `app/src/terminal/view/use_agent_footer/mod.rs` | Add
`CLIAgent::Goose` to the `Inline` rich-input submit strategy arm |
| `app/src/terminal/cli_agent_tests.rs` | Add `("goose",
CLIAgent::Goose)` to `test_detect_known_agents` |
## Testing
Added `("goose", CLIAgent::Goose)` to the existing
`test_detect_known_agents` table — this is the standard regression
coverage pattern used for every other agent in this file. The test
exercises `CLIAgent::detect("goose", None, None, ctx)` and asserts it
returns `Some(CLIAgent::Goose)`.
The compiler enforces correctness for everything else: every
non-catch-all `match` on `CLIAgent` must list every variant
exhaustively, so any missed match arm would be a build failure rather
than silent wrong behavior at runtime.
**Local presubmit note:** `cargo fmt --check` passes locally. The full
`./script/presubmit` requires the Metal Toolchain (not just Xcode) to
compile shaders during the `warpui` build, and on this machine the asset
downloads but doesn't activate without further intervention. Relying on
CI to run the full `cargo clippy --workspace --all-targets --tests -- -D
warnings` and `cargo nextest run --workspace`.
## Server API dependencies
This PR does not depend on any server API changes.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-IMPROVEMENT: Recognize Block's `goose` CLI agent — running
`goose` now activates the CLI-agent toolbar, status, brand color, and
icon like other recognized third-party agents.
Fixes#9038
## Description
This passes the app version through to `clap`, so that the `--version`
flag is supported.
## Testing
Ran locally with `--version` and `-V`, using a fake Git release tag.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: Added `--version` flag support in the Oz CLI
### Description
The Warp Drive import flow lets users pick workflow (YAML) and notebook
(Markdown) files. The picker uses `FileType::Yaml` and
`FileType::Markdown` from `warpui_core::platform::file_picker`, which
previously listed only `yaml` and `md`. That doesn't match what the
importer is willing to ingest:
-
[`app/src/drive/import/nodes.rs`](https://github.com/warpdotdev/warp/blob/main/app/src/drive/import/nodes.rs)
(`TryFrom<&Path> for FileType`) accepts both `.yaml` and `.yml` for
workflows.
-
[`warp_util::file_type::is_markdown_file`](https://github.com/warpdotdev/warp/blob/main/crates/warp_util/src/file_type.rs)
recognises both `.md` and `.markdown` (`MARKDOWN_EXTENSIONS`).
- The import modal's helper text in `modal_body.rs` already advertises
`"md, yaml, yml"` to users.
The result: a user can drag-and-drop a `.yml` workflow or `.markdown`
notebook and it imports cleanly, but the file picker filter hides those
same files when they click "Choose files…". This change brings the
picker in line with what the rest of the import path already accepts.
I left `FileType::Image` alone — that one has a separate user-facing
contract (the theme creator body explicitly says \"(.png, .jpg)\"), so
broadening it would need its own design decision.
### Testing
- Added two unit tests covering both extensions for `FileType::Yaml` and
`FileType::Markdown`.
- `cargo fmt -p warpui_core -- --check`
- Couldn't run the full `cargo nextest` locally (Metal toolchain not
available on this machine), the change is well-scoped to a const-array
literal so risk is low.
### Server API
No server changes.
### Agent Mode
Not applicable.
### Changelog Entries
- Warp Drive import file picker now lists `.yml` and `.markdown` files
in addition to `.yaml` and `.md`.
---------
Co-authored-by: anshul-garg27 <anshul-garg27@users.noreply.github.com>
Co-authored-by: anshul-garg27 <13553550+anshul-garg27@users.noreply.github.com>
## Description
Explicitly identifies, in source files, which ones were inherited from
Alacritty when Warp was initially built, and separately bundles in the
Alacritty license.
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
WISOTT!
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
The vibes are right. I'm sure there's some minor styling but no blockers
remain to start using it!
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
This PR sets up the initial plumbing for supporting the Codex CLI with
multi-harness. It follows the existing pattern for Claude Code and
Gemini, implementing the `ThirdPartyHarness` trait for codex.
Notable decisions:
- We run the CLI with `--dangerously-bypass-approvals-and-sandbox`
([docs](https://developers.openai.com/codex/agent-approvals-security#run-without-approval-prompts))
- We provide the system prompt by writing to `AGENTS.override.md`
([docs](https://developers.openai.com/codex/guides/agents-md))—codex
reads this first and recommends it for temporary instructions. It
doesn't really matter yet which we use since these are running in a
cloud agent context where we control the FS.
- Codex, like Gemini, unfortunately doesn't support file input or
redirecting stdin. We reuse the `$(cat prompt_file)` approach here for
now.
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
Tested E2E in downstream PR,
https://github.com/warpdotdev/warp/pull/9376
Also confirmed that it picks up the system prompt instructions:
<img width="1353" height="912" alt="image"
src="https://github.com/user-attachments/assets/6665db5a-fbf3-427f-b95d-2e5c627f3865"
/>
## Server API dependencies
<!-- You may remove this section if your PR does not have any server
dependencies. -->
Relies on the support for Codex added to the server in
https://github.com/warpdotdev/warp-server/pull/10740
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Enable SSH remote server on stable!
This also setup the server experiment rollout so we could have a
percentage of users with the setting default on and the rest with
default off
## Description
Fix file tree flickering during SSH session transitions. Previously,
when SSHing into a remote host, the file tree would stay stuck showing
the stale local file tree until the remote session finished
bootstrapping, then abruptly switch—causing a visible flicker.
Now the file tree shows a loading state as soon as the SSH command is
detected at preexec, giving a smooth transition: **local tree → loading
→ remote tree** (on success) or **local tree → loading → local tree**
(on failure).
### Changes
- **`CodingPanelEnablementState`**: Add `PendingRemoteSession` variant
to represent the transitional state between local and remote sessions.
- **`TerminalView`**: Add `has_pending_ssh_command()` method that
derives the pending SSH state from
`warpify_state.get_pending_ssh_host()` combined with
`is_long_running()`. Emit `TerminalViewStateChanged` when SSH is
detected at preexec so the workspace can react.
- **`Workspace`**: In `update_active_session()`, override enablement to
`PendingRemoteSession` when `has_pending_ssh && enablement == Enabled`.
Also call `update_active_session()` on `TerminalViewStateChanged` events
so the file tree refreshes immediately when SSH starts.
- **File tree / global search views**: Handle `PendingRemoteSession` by
rendering a loading state.
Co-Authored-By: Oz <oz-agent@warp.dev>
## Testing
Manual testing: ran `ssh` commands and verified the file tree
transitions smoothly from local → loading → remote (or back to local on
failure) with no flickering.
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: Fixed file tree flickering when transitioning to an
SSH remote session