Agent-readable wiki

Warp Agentic Development Environment — Technical Wiki

Warp is an agentic development environment born out of the terminal, implemented as a large multi-crate Rust workspace with a GPU-rendered UI, an embedded coding agent, and bring-your-own-CLI-agent support. This developer reference maps its workspace layout, core subsystems, and operational surfaces.

Pages

  1. Technical OrientationWhat Warp is, how the Cargo workspace and the app binary fit together, the per-channel entry points under app/src/bin, and how the rest of this developer reference is organized.
  2. Workspace & Crate MapHow the ~65-crate Rust workspace is organized: the role of the app binary versus the crates/* libraries, default-members, the local workspace dependency graph, and which crates own which responsibility.
  3. Terminal Engine & GPU UI RenderingThe terminal model and shell-session layer in warp_terminal, and the warpui windowing/rendering stack (wgpu, glyph cache, font atlas) that paints blocks, the editor, and panels.
  4. Agentic AI & Agent RuntimeWarp's coding-agent surface: the ai crate (agent orchestration, actions, skills, indexing), the app-side agent conversation and management models, MCP tool transport, and the computer_use automation layer. Stays provider-neutral — built-in or bring-your-own CLI agents.
  5. Settings, Feature Flags, Build Channels & Extension PointsThe operational boundaries of the codebase: the settings system and schema, runtime feature gating via warp_features, release-channel binaries and Docker packaging, and the extension surfaces (MCP servers, BYO CLI agents) to inspect next.

Complete Markdown

# Warp Agentic Development Environment — Technical Wiki

> Warp is an agentic development environment born out of the terminal, implemented as a large multi-crate Rust workspace with a GPU-rendered UI, an embedded coding agent, and bring-your-own-CLI-agent support. This developer reference maps its workspace layout, core subsystems, and operational surfaces.

## Context Links

- [Agent index](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/llms.txt)
- [Human interactive wiki](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5)
- [GitHub repository](https://github.com/warpdotdev/warp)

## Repository Metadata

- Repository: warpdotdev/warp

- Generated: 2026-05-25T03:35:59.859Z
- Updated: 2026-05-25T03:38:04.030Z
- Runtime: Claude Code
- Format: Technical
- Pages: 5

## Page Index

- 01. [Technical Orientation](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/01-technical-orientation.md) - What Warp is, how the Cargo workspace and the app binary fit together, the per-channel entry points under app/src/bin, and how the rest of this developer reference is organized.
- 02. [Workspace & Crate Map](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/02-workspace-crate-map.md) - How the ~65-crate Rust workspace is organized: the role of the app binary versus the crates/* libraries, default-members, the local workspace dependency graph, and which crates own which responsibility.
- 03. [Terminal Engine & GPU UI Rendering](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/03-terminal-engine-gpu-ui-rendering.md) - The terminal model and shell-session layer in warp_terminal, and the warpui windowing/rendering stack (wgpu, glyph cache, font atlas) that paints blocks, the editor, and panels.
- 04. [Agentic AI & Agent Runtime](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/04-agentic-ai-agent-runtime.md) - Warp's coding-agent surface: the ai crate (agent orchestration, actions, skills, indexing), the app-side agent conversation and management models, MCP tool transport, and the computer_use automation layer. Stays provider-neutral — built-in or bring-your-own CLI agents.
- 05. [Settings, Feature Flags, Build Channels & Extension Points](https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/05-settings-feature-flags-build-channels-extension-points.md) - The operational boundaries of the codebase: the settings system and schema, runtime feature gating via warp_features, release-channel binaries and Docker packaging, and the extension surfaces (MCP servers, BYO CLI agents) to inspect next.

## Source File Index

- `app/Cargo.toml`
- `app/src/ai/agent_conversations_model.rs`
- `app/src/app_state.rs`
- `app/src/bin/channel_config.rs`
- `app/src/bin/oss.rs`
- `app/src/bin/stable.rs`
- `app/src/features.rs`
- `Cargo.toml`
- `CONTRIBUTING.md`
- `crates/ai/src/agent/mod.rs`
- `crates/ai/src/agent/orchestration_config.rs`
- `crates/ai/src/lib.rs`
- `crates/computer_use/src/lib.rs`
- `crates/editor/src/lib.rs`
- `crates/mcp/src/lib.rs`
- `crates/settings/src/manager.rs`
- `crates/settings/src/schema.rs`
- `crates/warp_core/src/lib.rs`
- `crates/warp_features/src/lib.rs`
- `crates/warp_terminal/src/lib.rs`
- `crates/warp_terminal/src/shared_session.rs`
- `crates/warp_util/src/lib.rs`
- `crates/warpui/src/lib.rs`
- `crates/warpui/src/rendering/glyph_cache.rs`
- `crates/warpui/src/rendering/mod.rs`
- `README.md`
- `WARP.md`

---

## 01. Technical Orientation

> What Warp is, how the Cargo workspace and the app binary fit together, the per-channel entry points under app/src/bin, and how the rest of this developer reference is organized.

- Page Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/01-technical-orientation.md
- Generated: 2026-05-25T03:33:07.427Z

### Source Files

- `README.md`
- `WARP.md`
- `Cargo.toml`
- `app/Cargo.toml`
- `app/src/bin/stable.rs`
- `app/src/bin/oss.rs`
- `app/src/app_state.rs`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [README.md](README.md)
- [WARP.md](WARP.md)
- [Cargo.toml](Cargo.toml)
- [app/Cargo.toml](app/Cargo.toml)
- [app/src/bin/stable.rs](app/src/bin/stable.rs)
- [app/src/bin/oss.rs](app/src/bin/oss.rs)
- [app/src/bin/local.rs](app/src/bin/local.rs)
- [app/src/bin/dev.rs](app/src/bin/dev.rs)
- [app/src/bin/preview.rs](app/src/bin/preview.rs)
- [app/src/bin/integration.rs](app/src/bin/integration.rs)
- [app/src/bin/channel_config.rs](app/src/bin/channel_config.rs)
- [app/src/lib.rs](app/src/lib.rs)
- [app/src/app_state.rs](app/src/app_state.rs)
- [crates/warp_core/src/channel/mod.rs](crates/warp_core/src/channel/mod.rs)
- [crates/warp_core/src/channel/config.rs](crates/warp_core/src/channel/config.rs)
- [crates/warp_core/src/channel/state.rs](crates/warp_core/src/channel/state.rs)
- [crates/warp_features/src/lib.rs](crates/warp_features/src/lib.rs)
</details>

# Technical Orientation

This page orients a developer to the **warpdotdev/warp** repository: what Warp is, how its Cargo workspace is laid out, how the `app` crate produces several near-identical channel binaries from one shared library, and how the per-channel entry points under `app/src/bin` differ only in the configuration and feature flags they install before calling the common `warp::run()`. It is the entry door to the rest of this developer reference; later pages drill into the subsystems this page names (terminal, AI/agents, UI framework, persistence, cloud sync).

Warp is **an agentic development environment, born out of the terminal** — a Rust terminal emulator with a custom UI framework, a built-in coding agent, and support for bringing your own CLI agent (Claude Code, Codex, Gemini CLI, and others). The client codebase is open source in this repository; the UI framework crates (`warpui_core`, `warpui`) are MIT-licensed and the rest is AGPL v3.

Sources: [README.md:32-58](), [WARP.md:55-91]()

## The Cargo Workspace

The repository is a single Cargo workspace whose members are every directory under `crates/*` plus the `app` crate. WARP.md describes this as a workspace with **60+ member crates**, with the main binary in `app/` and the UI framework in `crates/warpui/`.

```toml
# Cargo.toml
[workspace]
members = [
  "crates/*",
  "app",
]
resolver = "2"
```

A separate `default-members` list narrows what `cargo build`/`cargo test` touch by default. It deliberately excludes `serve-wasm` (a helper for serving wasm binaries) and `integration` (used only for testing), while keeping `app` and a focused set of fast-iterating crates such as `editor`, `warpui`, `warp_terminal`, and `warp_completer`.

The workspace also centralizes dependency versions. Internal crates are declared once under `[workspace.dependencies]` with `path = "crates/..."`, so member crates reference them as `foo.workspace = true` rather than repeating paths or versions — for example `warp = { path = "app" }`, `warp_core = { path = "crates/warp_core" }`, and `warpui = { path = "crates/warpui" }`. Shared third-party versions (tokio, reqwest, wgpu, diesel, etc.) live in the same table. Workspace-wide package metadata sets the AGPL-3.0-only license and marks all crates `publish = false`.

```text
warp workspace (Cargo.toml)
├── app/                      → the application crate (lib + 7 bins)
└── crates/*                  → 60+ supporting crates
     ├── warp_core            channel/state, feature flags, platform abstractions
     ├── warpui, warpui_core  custom UI framework (MIT)
     ├── warp_terminal        terminal emulation core
     ├── editor               text editing
     ├── persistence          Diesel + SQLite storage
     ├── graphql              GraphQL client/schema
     └── ai, mcp, ipc, lsp …  agents, tooling, IPC, language servers
```

Sources: [Cargo.toml:1-28](), [Cargo.toml:30-96](), [WARP.md:78-99]()

## The `app` Crate: One Library, Many Binaries

The `app` crate (package `warp`, library name `warp`) is the heart of the client. Almost all application logic lives in its library (`src/lib.rs`); the binaries are thin wrappers. `autobins = false` disables Cargo's automatic binary discovery so that every binary target is declared explicitly, and `default-run = "warp-oss"` makes the open-source binary the one `cargo run` launches without arguments.

```toml
# app/Cargo.toml
[package]
default-run = "warp-oss"
autobins = false
name = "warp"

[lib]
name = "warp"
path = "src/lib.rs"
```

The crate declares **seven binary targets**. Six are channel/role front-ends, and one (`generate_settings_schema`) is a build-time tool. The comment in the manifest states the intent directly: each channel binary exists "so that we can bundle with its own icon, app name, and channel-specific configuration (such as flag overrides). Otherwise these binaries are exactly identical to our main binary."

| Binary target | Path | Purpose | Notes |
|---|---|---|---|
| `warp-oss` | `src/bin/oss.rs` | Open-source build (default `cargo run`) | Production server config, no telemetry/crash reporting |
| `warp` | `src/bin/local.rs` | Internal HEAD build | Bundle id `dev.warp.Warp-Local` |
| `stable` | `src/bin/stable.rs` | First-party stable release | Loads `"stable"` channel config |
| `preview` | `src/bin/preview.rs` | First-party feature-preview release | Requires `preview_channel` feature |
| `dev` | `src/bin/dev.rs` | Internal nightly build | |
| `integration` | `src/bin/integration.rs` | Integration-test build | Parses `WorkerCommand` subcommands |
| `generate_settings_schema` | `src/bin/generate_settings_schema.rs` | Settings-schema generator tool | |

The `[package.metadata.bundle.bin.*]` tables give each channel binary its own bundle identity — e.g. `stable` bundles as `name = "Warp"`, `preview` as `WarpPreview` (`dev.warp.Warp-Preview`), and `warp-oss` as `WarpOss` (`dev.warp.WarpOss`) — confirming that the binaries differ in packaging, not in core code.

Sources: [app/Cargo.toml:1-54](), [app/Cargo.toml:972-1021]()

## Per-Channel Entry Points

Every channel binary follows the same three-line shape: build a `ChannelState`, install it as global state via `ChannelState::set(...)`, then hand off to the shared `warp::run()`. The differences are entirely in *which* configuration and *which* feature-flag sets each one layers in.

```mermaid
flowchart TB
    subgraph bins["app/src/bin (per-channel front-ends)"]
        oss["oss.rs<br/>Channel::Oss"]
        local["local.rs<br/>Channel::Local"]
        stable["stable.rs<br/>Channel::Stable"]
        preview["preview.rs<br/>Channel::Preview"]
        dev["dev.rs<br/>Channel::Dev"]
        integ["integration.rs<br/>Channel::Integration"]
    end

    cfg["channel_config::load_config!<br/>(generator binary or embedded JSON)"]
    state["warp_core::channel::ChannelState<br/>ChannelState::set(...) → global"]
    flags["warp_features flag sets<br/>DEBUG / DOGFOOD / PREVIEW / RELEASE"]
    run["warp::run()<br/>app/src/lib.rs (shared entry)"]

    oss --> state
    local --> cfg
    stable --> cfg
    preview --> cfg
    dev --> cfg
    integ --> state
    cfg --> state
    flags --> state
    state --> run
```

**Configuration source.** Internal channels (`stable`, `dev`, `preview`, `local`) obtain their `ChannelConfig` through the `load_config!` macro in `channel_config.rs`. That macro switches on the `release_bundle` feature: bundled builds embed the JSON config at compile time via `include_str!` of `<channel>_config.json` in `OUT_DIR`, while non-bundled builds shell out at runtime to a `warp-channel-config` generator binary that must be on `PATH`. By contrast, `oss.rs` and `integration.rs` construct `ChannelConfig` inline in Rust — the OSS build uses `WarpServerConfig::production()` / `OzConfig::production()` with telemetry, crash reporting, autoupdate, and MCP static config all set to `None`; the integration build points server URLs at the black-hole IANA test address `192.0.2.0:9`.

```rust
// app/src/bin/stable.rs
fn main() -> Result<()> {
    ChannelState::set(ChannelState::new(
        Channel::Stable,
        channel_config::load_config!("stable"),
    ));
    warp::run()
}
```

**Feature-flag layering.** Each channel applies `with_additional_features(...)` for its audience. Internal channels stack the broadest sets — `local.rs` and `dev.rs` add `DEBUG_FLAGS`, `DOGFOOD_FLAGS`, *and* `PREVIEW_FLAGS`; `preview.rs` adds `PREVIEW_FLAGS` plus a forced-login flag; `oss.rs` adds `DEBUG_FLAGS` only in debug builds. These flag arrays are defined in the `warp_features` crate (re-exported as `warp_core::features`). `local.rs` even reads an env var to conditionally enable a sandbox-telemetry flag.

```rust
// app/src/bin/local.rs
let mut state = ChannelState::new(Channel::Local, config)
    .with_additional_features(features::DEBUG_FLAGS)
    .with_additional_features(features::DOGFOOD_FLAGS)
    .with_additional_features(features::PREVIEW_FLAGS);
```

The `integration` binary is the one structurally distinct front-end: it uses `clap` to parse optional `WorkerCommand` subcommands (e.g. running as a terminal server, remote-server proxy, or daemon) before falling back to `warp::run()`.

Sources: [app/src/bin/stable.rs:12-19](), [app/src/bin/oss.rs:10-30](), [app/src/bin/local.rs:8-24](), [app/src/bin/dev.rs:13-22](), [app/src/bin/preview.rs:13-21](), [app/src/bin/integration.rs:15-73](), [app/src/bin/channel_config.rs:25-101](), [crates/warp_features/src/lib.rs:896-956]()

## `Channel`, `ChannelState`, and `ChannelConfig`

The model the entry points install lives in `crates/warp_core/src/channel`. The `Channel` enum enumerates the six channels and encodes behavior policy on them: `is_dogfood()` is true only for `Dev`/`Local`, and `allows_server_url_overrides()` is true only for the internal channels (`Dev`, `Local`, `Integration`) — release channels (`Stable`, `Preview`, `Oss`) ignore `--server-root-url` and friends so shipped builds can't be redirected from their baked-in URLs. Each channel also maps to a CLI command name (e.g. `Stable → "oz"`, `Oss → "warp-oss"`).

`ChannelConfig` is the per-channel data record: an `app_id`, a logfile name, a `WarpServerConfig` (server, RTC, session-sharing URLs, Firebase key), an `OzConfig` for ambient-agent dashboards, and optional telemetry/autoupdate/crash-reporting/MCP configs. `WarpServerConfig::production()` and `OzConfig::production()` bake in the real `app.warp.dev` / `oz.warp.dev` endpoints.

`ChannelState` is held in a process-global `lazy_static` `Mutex`. `ChannelState::set(...)` is what the entry points call; thereafter, code anywhere reads the active channel and resolved URLs through associated functions like `ChannelState::channel()`, `ChannelState::server_root_url()`, and `ChannelState::ws_server_url()`. This is why the `main()` functions can be three lines: they seed one global, and the rest of the app reads from it.

```rust
// crates/warp_core/src/channel/state.rs
lazy_static! {
    static ref CHANNEL_STATE: Mutex<ChannelState> = Mutex::new(ChannelState::init());
}
```

Sources: [crates/warp_core/src/channel/mod.rs:9-74](), [crates/warp_core/src/channel/config.rs:7-72](), [crates/warp_core/src/channel/state.rs:15-99]()

## The Shared Entry Point: `warp::run()`

After channel state is installed, all binaries converge on `warp::run()` in `app/src/lib.rs`. This is where the application actually starts: it performs platform-specific init, initializes feature flags, and parses CLI arguments. It then honors server-URL overrides only when `ChannelState::channel().allows_server_url_overrides()` is true — closing the loop on the release-channel safety property described above. Finally it dispatches: if a `warp_cli` subcommand was given (terminal server, plugin host, minidump server, remote-server proxy/daemon, ripgrep search, …) it runs that worker and returns; otherwise it proceeds into the normal GUI launch.

```rust
// app/src/lib.rs
pub fn run() -> Result<()> {
    platform::init();
    features::init_feature_flags();
    let args = warp_cli::Args::from_env();
    if ChannelState::channel().allows_server_url_overrides() {
        // apply --server-root-url / --ws-server-url overrides
    }
    // dispatch worker subcommands, else launch the app
}
```

A complementary piece of the `app` crate is `app_state.rs`, which defines the serializable `AppState` / `WindowSnapshot` / `TabSnapshot` types used to persist and restore window, tab, and pane layout across launches — distinct from channel state, but part of the same crate's startup responsibilities.

Sources: [app/src/lib.rs:579-662](), [app/src/app_state.rs:26-69]()

## How the Rest of This Reference Is Organized

This page is the orientation layer. The subsystems it names map onto the deeper pages of this developer reference, grounded in the structure WARP.md and the workspace already expose:

| Area | Where it lives | Deeper-reference topic |
|---|---|---|
| UI framework (Entity-Component-Handle, `App`/`ViewHandle`) | `crates/warpui`, `crates/warpui_core` | WarpUI architecture |
| Terminal emulation & shell | `app/src/terminal/`, `crates/warp_terminal` | Terminal model (note the `model.lock()` deadlock caution) |
| AI / Agent Mode | `app/src/ai/`, `crates/ai`, `crates/mcp` | Agents, MCP, BYO-CLI agents |
| Channels & feature flags | `crates/warp_core/src/channel`, `crates/warp_features` | Build channels, flag rollout |
| Persistence | `crates/persistence` (Diesel + SQLite) | Storage & migrations |
| GraphQL & cloud sync | `crates/graphql`, `app/src/drive/` | Warp Drive, server protocol |
| Build & dev workflow | `script/bootstrap`, `script/run`, `script/presubmit` | Building locally, presubmit checks |

The recommended starting point for actually building is the three-command flow in the README (`./script/bootstrap`, `./script/run`, `./script/presubmit`), with WARP.md as the full engineering guide for coding style, testing conventions (`cargo nextest`, `${filename}_tests.rs`), and the feature-flag lifecycle.

In short: a single Cargo workspace builds one shared `warp` library, which several thin per-channel binaries in `app/src/bin` wrap by installing a channel-specific `ChannelState` (config + feature flags) before delegating to `warp::run()`. Understanding that fan-in is the key to navigating everything else in the codebase.

Sources: [WARP.md:55-99](), [README.md:73-83](), [Cargo.toml:1-23]()

---

## 02. Workspace & Crate Map

> How the ~65-crate Rust workspace is organized: the role of the app binary versus the crates/* libraries, default-members, the local workspace dependency graph, and which crates own which responsibility.

- Page Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/02-workspace-crate-map.md
- Generated: 2026-05-25T03:32:57.560Z

### Source Files

- `Cargo.toml`
- `app/Cargo.toml`
- `crates/warp_core/src/lib.rs`
- `crates/warp_terminal/src/lib.rs`
- `crates/warpui/src/lib.rs`
- `crates/warp_util/src/lib.rs`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [Cargo.toml](Cargo.toml)
- [app/Cargo.toml](app/Cargo.toml)
- [crates/warp_core/src/lib.rs](crates/warp_core/src/lib.rs)
- [crates/warp_terminal/src/lib.rs](crates/warp_terminal/src/lib.rs)
- [crates/warpui/src/lib.rs](crates/warpui/src/lib.rs)
- [crates/warpui_core/src/lib.rs](crates/warpui_core/src/lib.rs)
- [crates/warp_util/src/lib.rs](crates/warp_util/src/lib.rs)
- [crates/ai/src/lib.rs](crates/ai/src/lib.rs)
- [crates/command/src/lib.rs](crates/command/src/lib.rs)
- [crates/editor/src/lib.rs](crates/editor/src/lib.rs)
- [crates/warp_terminal/Cargo.toml](crates/warp_terminal/Cargo.toml)
- [crates/warp_core/Cargo.toml](crates/warp_core/Cargo.toml)
- [crates/warpui_core/Cargo.toml](crates/warpui_core/Cargo.toml)
</details>

# Workspace & Crate Map

Warp is built as a single Cargo workspace that contains one application package (`app/`) and roughly 65 library crates under `crates/*`. The workspace root declares its members with two glob/path entries — `crates/*` and `app` — and pins the v2 feature resolver, so every directory under `crates/` is automatically a workspace member without being individually listed. This page explains how that workspace is organized: how the binary package relates to the libraries, what `default-members` selects, how local crates are wired together through path dependencies, and which crate owns which responsibility.

The most important structural fact is that responsibility is split by *layer*, not by feature. A small set of utility and UI-framework crates sit at the bottom, domain crates such as `warp_core` and `warp_terminal` build on them, capability crates (`ai`, `lsp`, `mcp`, `graphql`, `persistence`) provide subsystems, and the `app` package at the top composes everything into shippable binaries. This page verifies that layering directly from the manifests and crate roots rather than from naming alone.

Sources: [Cargo.toml:1-6](), [Cargo.toml:30-95]()

## Workspace membership and the resolver

The workspace is defined at the repository root. Members are expanded from the `crates/*` glob plus the explicit `app` entry, and the modern dependency resolver is selected:

```toml
# Cargo.toml
[workspace]
members = [
  "crates/*",
  "app",
]
resolver = "2"
```

Because the glob captures every subdirectory of `crates/`, the workspace currently holds ~65 library crates plus the `app` package. Shared package metadata (author, AGPL-3.0 license, `publish = false`) is defined once in `[workspace.package]` and inherited by member crates via `*.workspace = true`.

Sources: [Cargo.toml:1-28](), [app/Cargo.toml:8-9]()

### Layered ownership model

The verified dependency edges below show that the workspace is not flat — crates form a directed acyclic layering from generic utilities up to the application binary.

```mermaid
flowchart TD
    subgraph App["Application package — app/"]
        APP["warp (lib) + bins:\nwarp-oss, warp, dev, stable, preview, integration"]
    end
    subgraph Domain["Domain & terminal crates"]
        CORE["warp_core\napp identity, channels, features,\npaths, telemetry, settings re-export"]
        TERM["warp_terminal\nmodel, shell, shared_session"]
        COMPL["warp_completer"]
    end
    subgraph Capability["Capability / subsystem crates"]
        AI["ai — agents, skills, index"]
        LSP["lsp"]
        MCP["mcp"]
        GQL["graphql (warp_graphql)"]
        PERS["persistence (diesel)"]
        SRV["warp_server_client"]
        EDIT["editor (warp_editor)"]
    end
    subgraph UIFW["UI framework"]
        WUI["warpui\nfonts, platform, rendering, windowing"]
        WUIC["warpui_core\nactions, elements, event, keymap"]
    end
    subgraph Foundation["Foundation utilities"]
        UTIL["warp_util"]
        SUM["sum_tree"]
        SET["settings / settings_value"]
        FEAT["warp_features"]
    end

    APP --> CORE & TERM & WUI & AI & LSP & MCP & GQL & PERS & SRV & EDIT
    TERM --> CORE & COMPL & UTIL
    CORE --> WUI & SET & FEAT & UTIL
    WUI --> WUIC
    WUIC --> SUM & UTIL
```

Sources: [crates/warp_terminal/Cargo.toml:33-35](), [crates/warp_core/Cargo.toml:1-95](), [crates/warpui/src/lib.rs:1-8](), [crates/warpui_core/Cargo.toml:72-79]()

## The `app` binary versus the `crates/*` libraries

The `app` package is both a library and a multi-binary target. Its `[lib]` is named `warp` (path `src/lib.rs`), and it declares `default-run = "warp-oss"`, with `autobins = false` so that binaries are only the ones explicitly listed. Each channel is a separate `[[bin]]` that points at a thin entry file under `src/bin/`, while remaining "exactly identical to our main binary" apart from icon, app name, and channel-specific flag overrides:

| Binary | Entry path | Purpose |
| --- | --- | --- |
| `warp-oss` | `src/bin/oss.rs` | Default run target; open-source build |
| `warp` | `src/bin/local.rs` | Local developer build |
| `dev` / `stable` / `preview` | `src/bin/{dev,stable,preview}.rs` | Release channels (`preview` requires the `preview_channel` feature) |
| `integration` | `src/bin/integration.rs` | Integration-test harness binary |
| `generate_settings_schema` | `src/bin/generate_settings_schema.rs` | Tooling to emit the settings JSON schema |

The `app` package is the composition root: it depends on essentially every domain and capability crate — `warp_core`, `warp_terminal`, `warpui`, `ai`, `lsp`, `mcp` (via `rmcp`), `warp_graphql`, `persistence`, `warp_server_client`, `editor` (as `warp_editor`), `vim`, `remote_server`, and many more — and owns the enormous `[features]` table (hundreds of feature flags, the `default` set, plus platform-conditional dependency blocks for macOS, wasm, Windows, and Unix). The `crates/*` libraries, by contrast, each own one coherent concern and avoid binary/composition concerns.

Sources: [app/Cargo.toml:1-54](), [app/Cargo.toml:218-260](), [app/Cargo.toml:432-469]()

## `default-members` — what builds and tests by default

While `members` includes every crate, `default-members` narrows what `cargo build`/`cargo test` operate on when no `-p` is given:

```toml
# Cargo.toml
default-members = [
  "app",
  "crates/channel_versions",
  "crates/command",
  "crates/editor",
  "crates/graphql",
  "crates/markdown_parser",
  "crates/sum_tree",
  "crates/warpui",
  "crates/warp_completer",
  "crates/warp_terminal",
  "crates/warp_util",
]
```

The accompanying comment states the intent of the exclusions: `serve-wasm` is omitted because it is "a helper for serving wasm binaries and not something we want to regularly compile or run tests against," and `integration` is omitted because it "is only used for testing." In practice the listed set is `app` plus a curated group of library crates whose own test suites run by default; because `app` transitively depends on nearly all other crates, building the default members still compiles the broader graph.

Sources: [Cargo.toml:8-23]()

## The local dependency graph

Local crates are wired together through `[workspace.dependencies]`, where each internal crate is registered with a `path = "crates/..."` entry. Downstream crates then refer to them with `crate.workspace = true` instead of repeating paths or versions — the file's own comment notes this "lets us reference them in other crates without specifying a path."

A notable subtlety is that the **dependency key name does not always match the directory name**. The workspace deliberately re-labels several crates:

| Dependency name | Filesystem path |
| --- | --- |
| `warp_editor` | `crates/editor` |
| `warp_graphql` | `crates/graphql` |
| `warp_isolation_platform` | `crates/isolation_platform` |
| `warp_managed_secrets` | `crates/managed_secrets` |
| `virtual-fs` | `crates/virtual_fs` |
| `warp` | `app` |

A few crates also opt out of default features at the workspace level (`channel_versions`, `settings_value`, `warpui_extras`).

The actual edges confirm the layering. `warp_terminal` depends only on `warp_completer`, `warp_core`, and `warp_util`. `warp_core` depends on lower-level crates including `settings`, `warp_features`, `warp_util`, `websocket`, plus the UI crates `warpui` and `warpui_extras`. `warpui` re-exports `warpui_core`, which in turn depends on `sum_tree` and `warp_util`. `warp_util` itself pulls in no internal crates — it is the foundation.

Sources: [Cargo.toml:30-95](), [crates/warp_terminal/Cargo.toml:33-35](), [crates/warp_core/Cargo.toml:1-95](), [crates/warpui/src/lib.rs:6-7](), [crates/warpui_core/Cargo.toml:72-79]()

## Which crate owns which responsibility

The crate roots make ownership explicit through their public module trees. The table summarizes the central crates verified from their `lib.rs`:

| Crate | Role (from `lib.rs` modules / doc) |
| --- | --- |
| `warp_util` | "Generic utilities and helpers available for use across all internal warp crates" — `file`, `path`, `git`, `host_id`, `sync`, `remote_path` |
| `warpui_core` | UI framework core — `actions`, `elements`, `event`, `keymap`, `accessibility`, `clipboard`, `image_cache`, `fonts` |
| `warpui` | UI rendering/windowing layer; adds `fonts`, `platform`, `rendering`, `windowing` and re-exports all of `warpui_core` |
| `warp_core` | App-domain foundation — `app_id`, `channel`, `features`, `paths`, `telemetry`, `session_id`, `user_preferences`; re-exports `settings` and its macros |
| `warp_terminal` | Terminal domain — `model`, `shell`, `shared_session` |
| `command` | Cross-platform process spawning; drop-in replacements for `std::process::Command` / `async_process::Command` (Windows `no_window` handling) |
| `ai` | Agent/LLM subsystem — `agent`, `api_keys`, `skills`, `index`, `project_context`, `LLMId` |
| `editor` (`warp_editor`) | Text editing — `content`, `editor`, `selection`, `search`, `multiline`, `render` |
| `settings` | Settings system — `macros`, `manager` (`SettingsManager`), `schema` |
| `graphql` (`warp_graphql`) | GraphQL `api`, `client`, `scalars`, `managed_secrets` |
| `persistence` | Local storage via Diesel; `model`, `schema`, embedded `MIGRATIONS` (gated on `local_fs`) |
| `warp_server_client` | Cloud client — `auth` (`UserUid`), `cloud_object`, `drive`, `ids` |
| `lsp` | Language-server integration — `CommandBuilder`, `manager`, `servers`, `supported_servers` |
| `mcp` | Model Context Protocol transport (`sse_transport`) |

`warp_core`'s root also re-exports `settings` and its declarative macros (`define_setting`, `define_settings_group`, …) "for backward compatibility," which is why many crates reach the settings system through `warp_core` rather than depending on `settings` directly.

Sources: [crates/warp_util/src/lib.rs:1-23](), [crates/warpui_core/src/lib.rs:1-18](), [crates/warpui/src/lib.rs:1-8](), [crates/warp_core/src/lib.rs:1-31](), [crates/warp_terminal/src/lib.rs:1-3](), [crates/command/src/lib.rs:1-18](), [crates/ai/src/lib.rs:1-16](), [crates/editor/src/lib.rs:1-9](), [crates/settings/src/lib.rs:1-18](), [crates/graphql/src/lib.rs:1-7](), [crates/persistence/src/lib.rs:1-6](), [crates/warp_server_client/src/lib.rs:1-7](), [crates/lsp/src/lib.rs:1-18](), [crates/mcp/src/lib.rs:1]()

## Per-crate build tuning

The workspace recognizes that some crates are hot paths even in debug builds and overrides their optimization level via `[profile.dev.package]`. For example, `warp_terminal.opt-level = 3` is applied because the comment explains it is needed to "improve the performance of core terminal logic," while keeping the rest of the dev build fast. Similar per-crate overrides exist for font/text layout, image processing, and profiling crates. This is a workspace-level mechanism rather than something each crate configures itself, reinforcing that build policy is centralized in the root manifest.

Sources: [Cargo.toml:406-436]()

## Summary

The Warp workspace is a layered Cargo monorepo: one root manifest expands `crates/*` and `app` into ~65 members under resolver v2, registers every internal crate as a path dependency so others can reference it with `crate.workspace = true`, and centralizes license, feature, profile, and per-crate optimization policy. The `app` package is the composition root — a library plus several channel binaries that depend on nearly the entire crate graph — while `default-members` selects `app` and a curated set of library crates for default builds/tests, intentionally excluding `serve-wasm` and `integration`. Responsibilities flow bottom-up from `warp_util` and `warpui_core` through `warp_core`/`warp_terminal` and capability crates like `ai`, `lsp`, and `persistence`, with the dependency-key-to-directory remapping (`warp_editor → editor`, `warp_graphql → graphql`, and others) being the main naming subtlety to watch when navigating the tree. This organization is provider-neutral: the crate boundaries and path-based dependency wiring shown here are independent of any model provider or hosted service, so the same map applies regardless of how AI capability crates such as `ai` are configured.

Sources: [Cargo.toml:1-95](), [app/Cargo.toml:1-54]()

---

## 03. Terminal Engine & GPU UI Rendering

> The terminal model and shell-session layer in warp_terminal, and the warpui windowing/rendering stack (wgpu, glyph cache, font atlas) that paints blocks, the editor, and panels.

- Page Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/03-terminal-engine-gpu-ui-rendering.md
- Generated: 2026-05-25T03:34:04.722Z

### Source Files

- `crates/warp_terminal/src/lib.rs`
- `crates/warp_terminal/src/shared_session.rs`
- `crates/warpui/src/lib.rs`
- `crates/warpui/src/rendering/mod.rs`
- `crates/warpui/src/rendering/glyph_cache.rs`
- `crates/editor/src/lib.rs`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [crates/warp_terminal/src/lib.rs](crates/warp_terminal/src/lib.rs)
- [crates/warp_terminal/src/model/mod.rs](crates/warp_terminal/src/model/mod.rs)
- [crates/warp_terminal/src/model/grid/flat_storage/mod.rs](crates/warp_terminal/src/model/grid/flat_storage/mod.rs)
- [crates/warp_terminal/src/model/grid/cell_type.rs](crates/warp_terminal/src/model/grid/cell_type.rs)
- [crates/warp_terminal/src/model/block_id.rs](crates/warp_terminal/src/model/block_id.rs)
- [crates/warp_terminal/src/shared_session.rs](crates/warp_terminal/src/shared_session.rs)
- [crates/warp_terminal/src/shell/mod.rs](crates/warp_terminal/src/shell/mod.rs)
- [crates/warpui/src/lib.rs](crates/warpui/src/lib.rs)
- [crates/warpui/src/rendering/mod.rs](crates/warpui/src/rendering/mod.rs)
- [crates/warpui/src/rendering/glyph_cache.rs](crates/warpui/src/rendering/glyph_cache.rs)
- [crates/warpui/src/rendering/atlas/mod.rs](crates/warpui/src/rendering/atlas/mod.rs)
- [crates/warpui/src/rendering/atlas/manager.rs](crates/warpui/src/rendering/atlas/manager.rs)
- [crates/warpui/src/rendering/wgpu/mod.rs](crates/warpui/src/rendering/wgpu/mod.rs)
- [crates/warpui/src/rendering/wgpu/renderer.rs](crates/warpui/src/rendering/wgpu/renderer.rs)
- [crates/warpui/src/rendering/wgpu/renderer/frame.rs](crates/warpui/src/rendering/wgpu/renderer/frame.rs)
- [crates/warpui/src/rendering/wgpu/renderer/glyph.rs](crates/warpui/src/rendering/wgpu/renderer/glyph.rs)
- [crates/warpui/src/windowing/mod.rs](crates/warpui/src/windowing/mod.rs)
- [crates/warpui_core/src/scene.rs](crates/warpui_core/src/scene.rs)
- [crates/warpui_core/src/rendering/mod.rs](crates/warpui_core/src/rendering/mod.rs)
- [crates/editor/src/lib.rs](crates/editor/src/lib.rs)
- [crates/editor/src/render/mod.rs](crates/editor/src/render/mod.rs)
- [crates/editor/src/editor.rs](crates/editor/src/editor.rs)
</details>

# Terminal Engine & GPU UI Rendering

Warp's client is built from two cooperating layers. `warp_terminal` owns the *terminal model*: the ANSI/escape-sequence parser, the cell grid, the scrollback buffer, and the shell-session metadata that turns raw PTY bytes into structured, block-addressable content. `warpui` (with its platform-agnostic core `warpui_core`) owns the *rendering and windowing stack*: a retained `Scene` graph of rectangles, images, and glyphs that a GPU backend (wgpu, or native Metal on macOS) paints into the window, backed by a glyph cache and a texture atlas. The `editor` crate sits between them, rendering marked-up rich text (blocks, the command editor, panels) into the same `Scene` primitives.

This page traces how those pieces fit together: how terminal state is stored, how the UI describes what to draw, and how text becomes pixels through the glyph cache, font atlas, and wgpu render pipelines.

## Layer Architecture and Ownership

`warp_terminal` is intentionally thin at the root — `lib.rs` exposes only the `model`, `shell`, and `shared_session` modules ([crates/warp_terminal/src/lib.rs:1-3]()). The real weight lives in `model`, which re-exports the grid, ANSI handling, block indexing, and keyboard-mode types ([crates/warp_terminal/src/model/mod.rs:1-14]()).

`warpui` is a platform-facing wrapper that re-exports everything from `warpui_core` and adds `fonts`, `platform`, `rendering`, and `windowing` modules ([crates/warpui/src/lib.rs:1-7]()). The retained-scene types (`Scene`, `Layer`, `Glyph`, `GlyphKey`) live in `warpui_core` ([crates/warpui_core/src/scene.rs:17-97]()), while GPU device handling and the glyph cache live in `warpui` so they can be compiled per platform.

```mermaid
flowchart TB
    subgraph terminal["warp_terminal (terminal model)"]
        grid["model::grid::FlatStorage\nscrollback + cells"]
        ansi["model::ansi / escape_sequences"]
        block["model::BlockId\nblock identity"]
        shell["shell::Shell\nshell metadata"]
    end
    subgraph editor["editor (rich-text layer)"]
        rtv["EditorView / RichTextElement\nrender::element + layout"]
    end
    subgraph core["warpui_core (retained scene)"]
        scene["Scene / Layer\nrects, images, glyphs, icons"]
        cfg["rendering::Config\nGlyphConfig, GPUPowerPreference"]
    end
    subgraph ui["warpui (GPU + windowing)"]
        wgpu["rendering::wgpu::Renderer\nrect/glyph/image pipelines"]
        cache["GlyphCache + atlas::Manager\n1024² texture atlases"]
        win["windowing (winit) / platform (mac Metal)"]
    end
    ansi --> grid --> block
    grid --> rtv
    shell --> rtv
    rtv --> scene
    cfg --> scene
    scene --> wgpu
    wgpu --> cache
    wgpu --> win
```

Sources: [crates/warp_terminal/src/lib.rs:1-3](), [crates/warp_terminal/src/model/mod.rs:1-14](), [crates/warpui/src/lib.rs:1-7](), [crates/warpui/src/rendering/mod.rs:1-8](), [crates/warpui_core/src/scene.rs:17-38](), [crates/editor/src/render/mod.rs:1-13]()

## The Terminal Model

### Scrollback storage: `FlatStorage`

The terminal grid is stored in `FlatStorage`, a space-efficient flat buffer purpose-built for scrollback. Its module docs explain the trade-off: it is optimized for `Index`, `Scan`/`Iterate`, `Push`, and `Pop`, but deliberately *not* for `Insert`, because inserting into the middle of a flat array requires shifting all trailing data — acceptable for immutable scrollback rows but avoided on the active region ([crates/warp_terminal/src/model/grid/flat_storage/mod.rs:1-17]()).

Rather than storing styling per cell, `FlatStorage` keeps the text content compact and pushes color and style into interval maps. The struct holds the `Content` buffer, an `Index` mapping row numbers to content offsets, the column width, an `fg_color_map`, a `bg_and_style_map`, an optional `end_of_prompt_marker`, and a `max_rows` cap with a `num_truncated_rows` counter for bounded scrollback ([crates/warp_terminal/src/model/grid/flat_storage/mod.rs:45-72]()).

```text
FlatStorage
 ├─ content: Content            (flat char buffer)
 ├─ index: Index                (row → byte offset)
 ├─ columns: usize
 ├─ fg_color_map  ─┐ interval maps keyed by content offset
 ├─ bg_and_style_map ┘ (color/style stored as ranges, not per-cell)
 ├─ end_of_prompt_marker: Option<..>
 └─ max_rows / num_truncated_rows  (bounded scrollback)
```

Sources: [crates/warp_terminal/src/model/grid/flat_storage/mod.rs:1-90]()

### Cells, wide characters, and blocks

Each grid cell is classified by `CellType`, which distinguishes a `RegularChar` from the components of a double-width glyph: `WideChar`, `WideCharSpacer`, and `LeadingWideCharSpacer` (used when a wide char must wrap to the next row). The conversion from `&Cell` is tuned so the common narrow-character case resolves with a single flag comparison before checking the rarer wide-cell flags ([crates/warp_terminal/src/model/grid/cell_type.rs:2-37]()).

Output is grouped into *blocks* identified by `BlockId`. A block produced from PTY output takes the form `{WARP_SESSION_ID}-{NUM_ID}` with a monotonically increasing per-session counter, because that ID originates in the shell `precmd` hook where generating a UUID would be too expensive; blocks created inside the app use a UUID instead ([crates/warp_terminal/src/model/block_id.rs:4-11]()).

Sources: [crates/warp_terminal/src/model/grid/cell_type.rs:2-37](), [crates/warp_terminal/src/model/block_id.rs:1-11]()

### Shell session layer

The `shell` module models the shell and its configuration. `Shell` carries the `shell_type`, optional `version`, shell `options`, autodetected `plugins` (e.g. Powerlevel10k, flagged for special handling), and the absolute path to the running shell binary ([crates/warp_terminal/src/shell/mod.rs:78-91]()). It also handles platform path quirks — Windows `PATHEXT` extension elision and zsh extended-history prefix stripping done with hand-rolled string parsing to stay fast on a hot path ([crates/warp_terminal/src/shell/mod.rs:29-76]()).

`shared_session.rs` is the bridge to session sharing: it provides `From` conversions between the model's `Point` (row/col) and the `session_sharing_protocol::common::Point`, so terminal coordinates can cross the session-sharing boundary without coupling the model to the protocol ([crates/warp_terminal/src/shared_session.rs:1-19]()).

Sources: [crates/warp_terminal/src/shell/mod.rs:29-91](), [crates/warp_terminal/src/shared_session.rs:1-19]()

## The Retained Scene Graph

The UI does not issue draw calls directly; it builds a `Scene`. A `Scene` holds a `scale_factor`, a `rendering::Config`, and a stack of `Layer`s plus overlay layers ([crates/warpui_core/src/scene.rs:17-27]()). Each `Layer` is a flat bucket of primitives — `rects`, `images`, `glyphs`, `icons` — plus optional `clip_bounds` and an R-tree `hit_map` for hit testing ([crates/warpui_core/src/scene.rs:29-38](), [crates/warpui_core/src/scene.rs:56-68]()).

A `Glyph` references a `GlyphKey` (glyph id, font id, and font size), a screen `position`, an optional `fade`, and a `color` ([crates/warpui_core/src/scene.rs:70-97]()). The `GlyphKey` is the cache key that ties the scene to the rasterizer. Application-wide rendering knobs live in `rendering::Config`: a `GlyphConfig` (thin-stroke policy via `ThinStrokes`), a `GPUPowerPreference`, and an optional `backend_preference` ([crates/warpui_core/src/rendering/mod.rs:45-75]()).

Sources: [crates/warpui_core/src/scene.rs:17-97](), [crates/warpui_core/src/rendering/mod.rs:45-75]()

## The Rich-Text Editor Layer

The `editor` crate renders Warp's marked-up content — command blocks, the multiline input editor, list/table/code elements, and panels. Its root declares the rendering machinery (`content`, `decoration`, `render`, `multiline`, `search`, `selection`) ([crates/editor/src/lib.rs:1-9]()), and `render/mod.rs` describes itself as the "Rich Text Editor rendering layer — model and UI element for rendering marked-up rich text," defining layout constants such as icon-button size and block-footer height ([crates/editor/src/render/mod.rs:1-13]()).

The `EditorView` trait is the contract between a `RichTextElement` and its containing view: it resolves runnable-command and embedded-item models by block offset and supplies `text_decorations` (syntax highlighting, underlines) for viewport ranges, with lifetimes carefully tied to cached `RangeMap` data accessed through `AppContext` ([crates/editor/src/editor.rs:18-56]()). The editor's output is ultimately the same `Scene` glyphs and rects consumed by the GPU renderer below.

Sources: [crates/editor/src/lib.rs:1-9](), [crates/editor/src/render/mod.rs:1-13](), [crates/editor/src/editor.rs:18-56]()

## GPU Rendering: wgpu Backend

### Instance and adapter management

The wgpu module owns a single global `wgpu::Instance` behind a `LazyLock<Mutex<Option<Arc<..>>>>`, initialized once via `init_wgpu_instance` and replaceable via `reset_wgpu_instance` ([crates/warpui/src/rendering/wgpu/mod.rs:16-30]()). Initialization runs on a dedicated thread (except on wasm) but blocks the caller until the lock is acquired, so `get_wgpu_instance()` can never race with setup ([crates/warpui/src/rendering/wgpu/mod.rs:112-142]()). The module also handles platform-specific concerns: Windows DirectComposition toggling and DX12 shader-compiler selection, and on Linux it suppresses `WAYLAND_DISPLAY` when the app forces X11 to avoid an instance/window-handle mismatch crash ([crates/warpui/src/rendering/wgpu/mod.rs:33-110]()).

Dual-GPU machines are detected through `is_low_power_gpu_available`, which checks whether any adapter is an `IntegratedGpu`; the result is memoized in a `OnceLock` because the probe is expensive ([crates/warpui/src/rendering/mod.rs:10-29](), [crates/warpui/src/rendering/wgpu/mod.rs:191-198]()).

Sources: [crates/warpui/src/rendering/wgpu/mod.rs:16-198](), [crates/warpui/src/rendering/mod.rs:10-29]()

### Renderer, pipelines, and frame drawing

`Renderer` holds three render pipelines — `rect`, `glyph`, and `image` — all configured with alpha blending against the surface format ([crates/warpui/src/rendering/wgpu/renderer.rs:24-62]()). Its `render` method builds a `Frame`, acquires the surface texture, encodes draw calls, submits them, optionally captures or runs a pre-present callback, and presents only if no GPU error occurred (a separate `Error::DeviceLost` is surfaced by unwrapping nested wgpu errors) ([crates/warpui/src/rendering/wgpu/renderer.rs:64-173]()).

`Frame::new` walks every `Layer` and lets each pipeline collect per-layer state, then finalizes per-frame GPU buffers ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:27-79]()). `Frame::draw` opens a single render pass that clears to transparent, then for each layer sets a scissor rect from the layer's `clip_bounds` (skipping layers that don't intersect the window) and draws **rects, then images, then glyphs** in that order ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:84-158]()). On drop, the frame tells the image pipeline to clean up its cache ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:179-185]()).

```mermaid
sequenceDiagram
    participant R as Renderer.render
    participant F as Frame
    participant GP as glyph::Pipeline
    participant GC as GlyphCache
    participant Atlas as atlas::Manager
    participant GPU as wgpu Device/Queue

    R->>F: Frame::new(scene, pipelines)
    loop each Layer
        F->>GP: initialize_for_layer(layer)
        loop each Glyph
            GP->>GC: get(glyph_key, scale, subpixel)
            alt cache miss
                GC->>GC: raster_bounds_fn + rasterize_glyph_fn
                GC->>Atlas: insert(size) -> TextureId + region
                GC->>GPU: insert_glyph_into_texture(queue)
            end
            GC-->>GP: GlyphTextureOffset (uv + bounds)
        end
        GP->>GP: group GlyphInstanceData by TextureId
    end
    R->>F: draw(encoder, surface_texture)
    F->>GPU: render pass -> rects, images, glyphs
    R->>GPU: queue.submit + surface.present
```

Sources: [crates/warpui/src/rendering/wgpu/renderer.rs:24-173](), [crates/warpui/src/rendering/wgpu/renderer/frame.rs:27-185](), [crates/warpui/src/rendering/wgpu/renderer/glyph.rs:150-239]()

## Glyph Cache and Font Atlas

`GlyphCache<Texture>` caches rasterized glyphs into a series of `1024×1024` texture atlases (`ATLAS_SIZE = 1024`). It is generic over the texture type so the same logic serves different GPU backends, and it stores a `HashMap<GlyphCacheKey, GlyphTextureOffset>` alongside an `atlas::Manager` ([crates/warpui/src/rendering/glyph_cache.rs:13-42]()). The cache key combines the `GlyphKey`, the `scale_factor` (as `OrderedFloat`), and the `SubpixelAlignment`, so the same character rasterized at a different DPI or sub-pixel offset is a distinct entry ([crates/warpui/src/rendering/glyph_cache.rs:44-59]()).

`GlyphCache::get` is callback-driven, decoupling caching policy from GPU specifics. On a miss it computes raster bounds, skips zero-size glyphs, rasterizes (in `Rgba32`), allocates a region via the atlas manager, lazily creates a new texture when a fresh atlas index appears, uploads the pixels through `insert_into_texture`, and records a `GlyphTextureOffset` (texture id, allocated region, raster bounds, emoji flag) ([crates/warpui/src/rendering/glyph_cache.rs:93-149]()). If `GlyphConfig` changes, the whole cache is thrown away and rebuilt ([crates/warpui/src/rendering/glyph_cache.rs:80-86]()).

The `atlas::Manager` performs shelf-style allocation across multiple textures. Each `insert` returns a `TextureOffset`; when the current allocator reports `Full`, the manager bumps to the next `TextureId`, starts a fresh allocator, and retries — so glyphs overflow into additional atlas pages rather than failing ([crates/warpui/src/rendering/atlas/manager.rs:43-67]()). An `AllocatedRegion` carries both the UV (texture) rect and the pixel rect for a glyph ([crates/warpui/src/rendering/atlas/mod.rs:8-15]()).

The glyph pipeline consumes the cache during `initialize_for_layer`: for each scene glyph it computes a `SubpixelAlignment` from the scaled position, calls `glyph_cache.get` with closures that build a `TextureWithBindGroup` and upload pixels, then assembles a `GlyphInstanceData` (using the atlas region size, not the smaller render bounds, to avoid sampling artifacts) grouped per `TextureId` for batched draws ([crates/warpui/src/rendering/wgpu/renderer/glyph.rs:151-239]()).

| Concept | Type / value | Responsibility |
|---|---|---|
| Atlas page size | `ATLAS_SIZE = 1024` | Fixed square texture dimension ([glyph_cache.rs:13]()) |
| Cache key | `GlyphCacheKey` | `GlyphKey` + `scale_factor` + `SubpixelAlignment` ([glyph_cache.rs:44-49]()) |
| Cached value | `GlyphTextureOffset` | texture id, region, raster bounds, `is_emoji` ([glyph_cache.rs:62-68]()) |
| Overflow strategy | `atlas::Manager::insert` | New `TextureId` + allocator when full ([manager.rs:54-67]()) |
| Config invalidation | `update_config` | Rebuild cache when `GlyphConfig` changes ([glyph_cache.rs:80-86]()) |

Sources: [crates/warpui/src/rendering/glyph_cache.rs:13-149](), [crates/warpui/src/rendering/atlas/manager.rs:43-67](), [crates/warpui/src/rendering/atlas/mod.rs:8-15](), [crates/warpui/src/rendering/wgpu/renderer/glyph.rs:151-239]()

## Windowing and Platform Backends

Rendering is split per platform. The `rendering` module gates the wgpu backend behind `#[cfg(wgpu)]` and selects atlas/glyph types through `pub(crate)` re-exports ([crates/warpui/src/rendering/mod.rs:1-8]()). macOS additionally has a native Metal renderer plus its own wgpu path under `platform/mac/rendering`, while Linux/FreeBSD use a winit-based `WindowingSystem` ([crates/warpui/src/windowing/mod.rs:1-6]()). The windowing layer also defines minimum window dimensions (`MIN_WINDOW_WIDTH`, `MIN_WINDOW_HEIGHT`), relaxed under test/integration builds ([crates/warpui/src/windowing/mod.rs:8-21]()).

Sources: [crates/warpui/src/rendering/mod.rs:1-8](), [crates/warpui/src/windowing/mod.rs:1-21]()

## Summary

Warp separates *what the terminal means* from *how it is painted*. `warp_terminal` turns PTY bytes into a compact, block-addressed model: `FlatStorage` keeps scrollback cheap by pushing color and style into interval maps, `CellType` tracks wide-character layout, and `BlockId` gives every command output a stable identity ([crates/warp_terminal/src/model/grid/flat_storage/mod.rs:45-72](), [crates/warp_terminal/src/model/block_id.rs:4-11]()). The `editor` crate renders that model — plus the input editor and panels — into a retained `Scene` of layers, rects, and glyphs ([crates/editor/src/render/mod.rs:1-13](), [crates/warpui_core/src/scene.rs:29-38]()). `warpui` then paints the scene through a wgpu `Renderer` whose glyph pipeline is fed by a `GlyphCache` over `1024²` texture atlases, batching per-texture instance data into a single render pass ([crates/warpui/src/rendering/wgpu/renderer/frame.rs:84-158](), [crates/warpui/src/rendering/glyph_cache.rs:13-149]()).

This page synthesizes the repository implementation directly; the selected knowledge profile's solved-problem notes (`docs/solutions/`) and strategy anchor (`STRATEGY.md`) are not present in this checkout, so no such sources were used. Provider-neutral note: the rendering stack depends only on `wgpu`/native GPU APIs and the local font rasterizer, with no model-provider or hosted-service coupling, so any Grok-Wiki integration consuming this page stays portable across file, repository, or catalog skill sources.

Sources: [crates/warp_terminal/src/model/grid/flat_storage/mod.rs:45-72](), [crates/warpui/src/rendering/glyph_cache.rs:13-149](), [crates/warpui/src/rendering/wgpu/renderer/frame.rs:84-158]()

---

## 04. Agentic AI & Agent Runtime

> Warp's coding-agent surface: the ai crate (agent orchestration, actions, skills, indexing), the app-side agent conversation and management models, MCP tool transport, and the computer_use automation layer. Stays provider-neutral — built-in or bring-your-own CLI agents.

- Page Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/04-agentic-ai-agent-runtime.md
- Generated: 2026-05-25T03:33:34.615Z

### Source Files

- `crates/ai/src/lib.rs`
- `crates/ai/src/agent/mod.rs`
- `crates/ai/src/agent/orchestration_config.rs`
- `crates/mcp/src/lib.rs`
- `crates/computer_use/src/lib.rs`
- `app/src/ai/agent_conversations_model.rs`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [crates/ai/src/lib.rs](crates/ai/src/lib.rs)
- [crates/ai/src/agent/mod.rs](crates/ai/src/agent/mod.rs)
- [crates/ai/src/agent/action/mod.rs](crates/ai/src/agent/action/mod.rs)
- [crates/ai/src/agent/orchestration_config.rs](crates/ai/src/agent/orchestration_config.rs)
- [crates/ai/src/skills/mod.rs](crates/ai/src/skills/mod.rs)
- [crates/ai/src/skills/skill_provider.rs](crates/ai/src/skills/skill_provider.rs)
- [crates/ai/src/index/mod.rs](crates/ai/src/index/mod.rs)
- [crates/mcp/src/lib.rs](crates/mcp/src/lib.rs)
- [crates/mcp/src/sse_transport/mod.rs](crates/mcp/src/sse_transport/mod.rs)
- [crates/computer_use/src/lib.rs](crates/computer_use/src/lib.rs)
- [app/src/ai/agent_conversations_model.rs](app/src/ai/agent_conversations_model.rs)
- [app/src/ai/agent_conversations_model/entry.rs](app/src/ai/agent_conversations_model/entry.rs)
</details>

# Agentic AI & Agent Runtime

Warp's coding-agent surface is split across several Rust crates and an app-side model layer. The `ai` crate owns the provider-neutral vocabulary of what an agent can *do* — its action types, action results, orchestration configuration, skills, and codebase index. The `app` layer owns the *management* of agent conversations and tasks (local interactive, ambient, and cloud-synced). Two supporting crates handle external surfaces: `mcp` provides a legacy SSE transport for connecting to Model Context Protocol servers, and `computer_use` provides a cross-platform screen/keyboard/mouse automation layer used by the agent's computer-use actions.

A defining property of this design is **harness neutrality**: the agent runtime is not bound to a single model provider or CLI. Orchestration and child-agent launches carry a `harness_type` string that selects between Warp's own harness (`oz`) and bring-your-own CLI agents (`claude`, `opencode`, `gemini`, `codex`), and skills are discovered from many vendor-specific directories. This page maps those modules, their data contracts, and how a tool call flows from the agent model through to local execution or an external service.

## Architecture at a Glance

The runtime separates the *action vocabulary* (in `crates/ai`) from *execution surfaces* (MCP servers, the local computer, child harnesses) and from *conversation management* (in `app`).

```mermaid
flowchart TB
    subgraph app["app/src/ai (management layer)"]
        ACM["AgentConversationsModel\n(polls + caches tasks)"]
        ENTRY["AgentConversationEntry\nprovenance + harness + capabilities"]
    end
    subgraph ai["crates/ai (action vocabulary)"]
        ACT["AIAgentActionType\n(tool-call catalog)"]
        ORCH["OrchestrationConfig\nmodel_id + harness_type + mode"]
        SKILL["skills::SkillProvider\nmulti-vendor discovery"]
        INDEX["index\n(file_outline / embeddings)"]
    end
    subgraph surfaces["Execution surfaces"]
        MCP["crates/mcp\nSSE transport to MCP servers"]
        CU["crates/computer_use\nActor: mouse/keyboard/screenshot"]
        HARNESS["Child harnesses\noz / claude / opencode / gemini / codex"]
    end
    ACM --> ENTRY
    ACM -.reads.-> ORCH
    ACT -->|CallMCPTool / ReadMCPResource| MCP
    ACT -->|UseComputer / RequestComputerUse| CU
    ACT -->|RunAgents / StartAgent| HARNESS
    ORCH -->|matches_active_config| ACT
    ACT -.SearchCodebase.-> INDEX
    ACT -.ReadSkill.-> SKILL
```

Sources: [crates/ai/src/lib.rs:1-16](crates/ai/src/lib.rs), [crates/ai/src/agent/mod.rs:1-10](crates/ai/src/agent/mod.rs), [crates/ai/src/agent/action/mod.rs:30-175](crates/ai/src/agent/action/mod.rs), [app/src/ai/agent_conversations_model.rs:508-535](app/src/ai/agent_conversations_model.rs)

## The `ai` Crate

`crates/ai/src/lib.rs` is the crate root and declares the public module surface: `agent`, `skills`, `index`, `document`, `project_context`, `workspace`, plus credential helpers (`api_keys`, `aws_credentials`) and `llm_id` (Sources: [crates/ai/src/lib.rs:1-16](crates/ai/src/lib.rs)). The `agent` module re-exports the action and result types, citations, and file-location grouping, and owns `orchestration_config` (Sources: [crates/ai/src/agent/mod.rs:1-10](crates/ai/src/agent/mod.rs)).

### Action Catalog (`AIAgentActionType`)

`AIAgentActionType` is the central enum describing every tool call an agent can request. It is provider-agnostic — it describes *intent* (read files, run a command, call an MCP tool, edit documents, drive the computer, orchestrate child agents), not how any specific model encodes those calls. Each variant has matching helpers: `cancelled_result` maps a variant to its cancelled `AIAgentActionResultType`, and `user_friendly_name`/`Display` provide human- and log-facing labels.

| Action variant | Surface / responsibility |
|---|---|
| `RequestCommandOutput`, `WriteToLongRunningShellCommand`, `ReadShellCommandOutput` | Terminal/PTY execution with read-only/risky/pager hints |
| `ReadFiles`, `RequestFileEdits`, `Grep`, `FileGlob` / `FileGlobV2` | Local filesystem access and edits |
| `SearchCodebase` | Semantic/code search backed by the `index` module |
| `CallMCPTool`, `ReadMCPResource` | MCP server tools/resources (optional `server_id`) |
| `UseComputer`, `RequestComputerUse` | `computer_use` automation (actions + screenshot params) |
| `ReadSkill` | Loads a `SkillReference` from a skill provider |
| `ReadDocuments`, `EditDocuments`, `CreateDocuments` | Agent-managed documents |
| `StartAgent`, `SendMessageToAgent`, `RunAgents` | Child-agent orchestration |
| `AskUserQuestion`, `SuggestPrompt`, `TransferShellCommandControlToUser` | Human-in-the-loop interactions |

Sources: [crates/ai/src/agent/action/mod.rs:30-175](crates/ai/src/agent/action/mod.rs), [crates/ai/src/agent/action/mod.rs:304-435](crates/ai/src/agent/action/mod.rs)

The `WriteToLongRunningShellCommand` path encodes how input is delivered to an interactive PTY via `AIAgentPtyWriteMode` (`Raw`, `Line`, `Block`); `Line` mode prepends `^A` (beginning-of-line) and submits with platform-aware `CR`/`LF`, and `Block` mode wraps the bytes in bracketed-paste markers when enabled (Sources: [crates/ai/src/agent/action/mod.rs:769-820](crates/ai/src/agent/action/mod.rs)).

### Orchestration & Harness Neutrality

When an agent orchestrates child agents (`RunAgents`) or launches a single child (`StartAgent`), the run carries run-wide configuration: `model_id`, `harness_type`, and an `execution_mode` (`Local` vs `Remote { environment_id, worker_host }`). The harness string is the neutrality seam — `harness_proto_to_string`/`harness_type_to_proto` map between the proto `Harness` oneof and client-side identifiers for `oz`, `claude` (ClaudeCode), `opencode`, `gemini`, and `codex` (Sources: [crates/ai/src/agent/orchestration_config.rs:184-214](crates/ai/src/agent/orchestration_config.rs)).

`OrchestrationConfig` mirrors a proto message but uses Rust-native types so view/model code stays free of proto imports, and `OrchestrationConfigStatus` (`None`/`Approved`/`Disapproved`) records the user's approval state (Sources: [crates/ai/src/agent/orchestration_config.rs:5-50](crates/ai/src/agent/orchestration_config.rs)). The function `matches_active_config` decides whether a `run_agents` call can auto-launch without re-prompting: empty fields on the call are treated as "inherit from config" and therefore match, while `execution_mode` variants must agree (Local vs Remote) (Sources: [crates/ai/src/agent/orchestration_config.rs:64-96](crates/ai/src/agent/orchestration_config.rs)).

`StartAgentExecutionMode` makes BYOC explicit in its `Local` variant: a `None` `harness_type` selects "the legacy embedded local child-agent flow," while `Some(harness_type)` "selects a third-party CLI harness to launch locally." Its `Remote` variant additionally carries an `auth_secret_name` — a managed secret name forwarded as the credential for non-Oz harnesses, with `None` meaning the remote environment falls back to its own ambient credentials (Sources: [crates/ai/src/agent/action/mod.rs:221-278](crates/ai/src/agent/action/mod.rs)).

```text
RunAgents (batched)                StartAgent (single child)
  base_prompt + skills               Local { harness_type: Option<String>,
  model_id / harness_type                    model_id: Option<String> }
  execution_mode:                    Remote { environment_id, harness_type,
    Local | Remote{env,host,CU}              model_id, auth_secret_name, ... }
  agent_run_configs[ {name,prompt} ]
        |
        v
  matches_active_config(req, cfg) --> auto-launch? (skip confirmation card)
```

Sources: [crates/ai/src/agent/action/mod.rs:177-219](crates/ai/src/agent/action/mod.rs), [crates/ai/src/agent/orchestration_config.rs:64-96](crates/ai/src/agent/orchestration_config.rs)

### Skills (Multi-Vendor Discovery)

The `skills` module discovers reusable instruction packs from many vendor directories rather than one proprietary location. `SkillProvider` enumerates supported origins (`Warp`, `Agents`, `Claude`, `Codex`, `Cursor`, `Gemini`, `Copilot`, `Droid`, `Github`, `OpenCode`), and `SKILL_PROVIDER_DEFINITIONS` maps each to a relative path such as `.agents/skills`, `.warp/skills`, or `.claude/skills`. The list order defines precedence (first = highest priority), surfaced via `provider_rank` (Sources: [crates/ai/src/skills/skill_provider.rs:30-147](crates/ai/src/skills/skill_provider.rs)). `SkillScope` distinguishes `Home` (e.g. `~/.agents/skills`), `Project`, and `Bundled` skills shipped with Warp (Sources: [crates/ai/src/skills/skill_provider.rs:58-66](crates/ai/src/skills/skill_provider.rs)). Public entry points include `parse_skill`/`parse_bundled_skill`, `read_skills`, and `SkillReference` (Sources: [crates/ai/src/skills/mod.rs:1-15](crates/ai/src/skills/mod.rs)).

This portable, file/directory-based discovery is what keeps skills BYOC-friendly: a skill is a folder under a recognized provider path, not a vendor-hosted catalog dependency.

### Codebase Index

The `index` module backs the `SearchCodebase` action. It splits into a native path (gated behind the `local_fs` feature) and a `wasm` path, with a bounded Rayon thread pool (`MAX_PARALLEL_THREADS = 2`) for indexing work, and exposes `build_outline`, `Outline`, and `Symbol` for file outlines plus repo-metadata types (Sources: [crates/ai/src/index/mod.rs:1-53](crates/ai/src/index/mod.rs)). A `full_source_code_embedding` submodule and `DEFAULT_SYNC_REQUESTS_PER_MIN = 600` indicate embedding-based search with a rate-limited sync (Sources: [crates/ai/src/index/mod.rs:3-6](crates/ai/src/index/mod.rs)).

## App-Side Conversation & Agent Management

`AgentConversationsModel` is "a unified interface for reading both local and ambient agent conversations (i.e. conversations & tasks)," responsible for polling for new tasks and maintaining local state; it backs both the agent management view and the conversation list view (Sources: [app/src/ai/agent_conversations_model.rs:508-535](app/src/ai/agent_conversations_model.rs)). It caches `tasks` and `conversations`, tracks per-window active data consumers to decide when to poll, and is gated behind `FeatureFlag::AgentManagementView` — when disabled it returns an inert empty model (Sources: [app/src/ai/agent_conversations_model.rs:569-584](app/src/ai/agent_conversations_model.rs)).

The model is resilient to network failure via a three-state `TaskFetchState` (`InFlight`, `PermanentlyFailed`, `TransientlyFailed`) with distinct cooldowns — 2s for transient (5xx/408/429/network) and 60s for permanent (401/403/404), deliberately not refusing forever in case permissions change mid-session (Sources: [app/src/ai/agent_conversations_model.rs:63-93](app/src/ai/agent_conversations_model.rs)). It also coalesces real-time refresh bursts with `RtcTaskRefreshThrottleState`, keeping the *earliest* timestamp in a burst because `updated_after` is a lower bound (Sources: [app/src/ai/agent_conversations_model.rs:95-121](app/src/ai/agent_conversations_model.rs)).

Each entry's origin is captured by `AgentConversationProvenance` (`LocalInteractive`, `AmbientRun`, `CloudSyncedConversation`), with `AgentConversationBackingData` flags for which data sources contributed and `AgentConversationCapabilities` describing which actions (open, share, delete, fork, cancel) are exposed under current navigation policy (Sources: [app/src/ai/agent_conversations_model/entry.rs:141-165](app/src/ai/agent_conversations_model/entry.rs)). Entries carry an optional `Harness` from `warp_cli::agent`, defaulting to `Harness::Oz` when unknown, so the management view stays harness-aware across both ambient tasks and synced conversations (Sources: [app/src/ai/agent_conversations_model/entry.rs:103-103](app/src/ai/agent_conversations_model/entry.rs), [app/src/ai/agent_conversations_model/entry.rs:355-361](app/src/ai/agent_conversations_model/entry.rs)).

## MCP Tool Transport

The `mcp` crate is intentionally small at its root: `lib.rs` exposes only `sse_transport` (Sources: [crates/mcp/src/lib.rs:1](crates/mcp/src/lib.rs)). That module is a "legacy SSE client transport for MCP, preserved from the rmcp fork after upstream removed SSE transport support in v0.11.0," allowing Warp to keep connecting to MCP servers that only speak the older Server-Sent-Events protocol (Sources: [crates/mcp/src/sse_transport/mod.rs:1-3](crates/mcp/src/sse_transport/mod.rs)). It re-exports the client building blocks — `SseClient`, `SseClientConfig`, `SseClientTransport`, `SseTransportError`, plus retry policies `ExponentialBackoff`, `FixedInterval`, and `NeverRetry` (Sources: [crates/mcp/src/sse_transport/mod.rs:9-11](crates/mcp/src/sse_transport/mod.rs)). The agent reaches MCP servers through the `CallMCPTool` and `ReadMCPResource` actions, each optionally scoped by a `server_id: Option<Uuid>` (Sources: [crates/ai/src/agent/action/mod.rs:95-109](crates/ai/src/agent/action/mod.rs)).

## Computer-Use Automation Layer

`crates/computer_use` provides the OS-level automation behind the `UseComputer` and `RequestComputerUse` actions. Platform-specific implementations are selected at compile time (`mac/`, `linux/`, `windows/`) with a `noop` fallback, and the public surface is a single `Actor` trait whose `perform_actions` executes a slice of `Action` values and returns an `ActionResult` (Sources: [crates/computer_use/src/lib.rs:1-58](crates/computer_use/src/lib.rs)).

```mermaid
classDiagram
    class Actor {
        <<trait>>
        +platform() Option~Platform~
        +perform_actions(actions, options) Result~ActionResult, String~
    }
    class Action {
        <<enum>>
        Wait MouseDown MouseUp MouseMove
        MouseWheel TypeText KeyDown KeyUp
    }
    class Options {
        screenshot_params: Option~ScreenshotParams~
    }
    class ActionResult {
        screenshot: Option~Screenshot~
        cursor_position: Option~Vector2I~
    }
    Actor --> Action : consumes
    Actor --> Options : with
    Actor --> ActionResult : returns
    ActionResult --> Screenshot
```

`Action` covers waits, mouse down/up/move/wheel, text typing, and key down/up, with `Key` supporting either a platform-specific `Keycode` or a `Char` (with a documented Windows BMP limitation) (Sources: [crates/computer_use/src/lib.rs:60-105](crates/computer_use/src/lib.rs)). Screenshots are optional and constrained by `ScreenshotParams` (`max_long_edge_px`, `max_total_px`, optional `region`); `ScreenshotRegion::validate` rejects negative or zero/negative-area regions before capture (Sources: [crates/computer_use/src/lib.rs:127-184](crates/computer_use/src/lib.rs)). The bridge from the action vocabulary lives in `UseComputerRequest`, which holds an `action_summary`, a `Vec<computer_use::Action>`, and optional `computer_use::ScreenshotParams` (Sources: [crates/ai/src/agent/action/mod.rs:742-756](crates/ai/src/agent/action/mod.rs)).

## Provider Neutrality Summary

The agent runtime stays provider-neutral at three concrete layers verified above: the **harness seam** maps a free-form `harness_type` string to built-in (`oz`) or external CLI agents (`claude`, `opencode`, `gemini`, `codex`) and forwards a named auth secret rather than hard-wiring a provider's credentials; **skills** are discovered from a ranked list of vendor directories on disk; and **MCP transport** connects to any conforming SSE server by URL with configurable retry. The `ai` crate deliberately describes agent *intent* (`AIAgentActionType`) rather than any single model's wire format, so adding or swapping a harness, model, or skill source does not change the action vocabulary or the app-side `AgentConversationsModel` that manages the resulting conversations and tasks (Sources: [crates/ai/src/agent/action/mod.rs:30-175](crates/ai/src/agent/action/mod.rs), [crates/ai/src/agent/orchestration_config.rs:184-214](crates/ai/src/agent/orchestration_config.rs)).

> Note on this run: investigation used native repository search/read tools only. The Compound Engineering knowledge profile was applied as portable wiki-shaping guidance (Page Shape / QA Review heuristics from a *bundled* skill snapshot); no `docs/solutions/**` solved-problem notes or `STRATEGY.md` were present in this checkout, so neither source class contributed content. All implementation claims above are grounded in the cited repository files.

---

## 05. Settings, Feature Flags, Build Channels & Extension Points

> The operational boundaries of the codebase: the settings system and schema, runtime feature gating via warp_features, release-channel binaries and Docker packaging, and the extension surfaces (MCP servers, BYO CLI agents) to inspect next.

- Page Markdown: https://grok-wiki.com/public/wiki/warpdotdev-warp-a55b6d0c09b5/pages/05-settings-feature-flags-build-channels-extension-points.md
- Generated: 2026-05-25T03:35:59.858Z

### Source Files

- `crates/settings/src/manager.rs`
- `crates/settings/src/schema.rs`
- `crates/warp_features/src/lib.rs`
- `app/src/features.rs`
- `app/src/bin/channel_config.rs`
- `CONTRIBUTING.md`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [crates/settings/src/manager.rs](crates/settings/src/manager.rs)
- [crates/settings/src/schema.rs](crates/settings/src/schema.rs)
- [crates/settings/src/lib.rs](crates/settings/src/lib.rs)
- [crates/warp_features/src/lib.rs](crates/warp_features/src/lib.rs)
- [app/src/features.rs](app/src/features.rs)
- [app/src/bin/channel_config.rs](app/src/bin/channel_config.rs)
- [app/src/bin/stable.rs](app/src/bin/stable.rs)
- [app/src/bin/generate_settings_schema.rs](app/src/bin/generate_settings_schema.rs)
- [app/Cargo.toml](app/Cargo.toml)
- [crates/warp_core/src/channel/mod.rs](crates/warp_core/src/channel/mod.rs)
- [crates/warp_core/src/channel/state.rs](crates/warp_core/src/channel/state.rs)
- [crates/warp_core/src/channel/config.rs](crates/warp_core/src/channel/config.rs)
- [crates/warp_cli/src/agent.rs](crates/warp_cli/src/agent.rs)
- [docker/linux-dev/Dockerfile](docker/linux-dev/Dockerfile)
- [CONTRIBUTING.md](CONTRIBUTING.md)
</details>

# Settings, Feature Flags, Build Channels & Extension Points

This page documents the *operational boundaries* of the Warp codebase: the levers that decide what a given binary does, who is allowed to turn them, and where third parties plug in. Four subsystems cooperate. The **settings system** owns user-tunable, persisted configuration and a generated JSON Schema for the TOML settings file. The **feature-flag system** (`warp_features`) owns runtime gating of in-progress functionality. **Build channels** (`warp_core::channel`) decide which server endpoints, telemetry, and flag sets a compiled binary ships with, and how that binary is packaged. Finally, the **extension surfaces** — MCP servers and BYO CLI agent harnesses — are the points where Warp's behavior is widened by code and configuration that live outside Warp itself.

These four are deliberately layered. A *compile-time* cargo feature decides whether code is built at all; a *channel* (selected by which binary target runs) decides which endpoints and flag baselines apply; a *runtime feature flag* decides whether a built path is live; and a *setting* decides how a live feature behaves for one user. Understanding the direction of this dependency chain is the key mental model for the whole boundary layer.

```mermaid
flowchart TD
    subgraph BuildTime["Build time (Cargo)"]
        CF["cargo features<br/>app/Cargo.toml"]
        RB["release_bundle feature"]
    end
    subgraph Entry["Channel binary targets (app/src/bin/*)"]
        STABLE["stable.rs / preview.rs / dev.rs<br/>local.rs / oss.rs / integration.rs"]
        CCFG["channel_config.rs<br/>load_config! macro"]
    end
    subgraph Runtime["Runtime state (warp_core::channel)"]
        CS["ChannelState<br/>channel + additional_features + ChannelConfig"]
        CONF["ChannelConfig<br/>server_config, oz_config,<br/>telemetry/autoupdate/crash/mcp_static"]
    end
    subgraph Gating["Gating layer"]
        FF["FeatureFlag (warp_features)<br/>FLAG_STATES + USER_PREFERENCE_MAP"]
        SETT["SettingsManager (crates/settings)<br/>public TOML + private native store"]
    end
    subgraph Ext["Extension surfaces"]
        MCP["MCP servers<br/>mcp_static_config / FileBasedMcp"]
        HARN["BYO CLI harnesses<br/>warp_cli::agent::Harness"]
    end

    CF --> STABLE
    RB --> CCFG
    STABLE --> CS
    CCFG --> CONF
    CONF --> CS
    CS -->|additional_features + RELEASE_FLAGS| FF
    CF -->|cfg!(feature=...)| FF
    FF -->|gates| SETT
    CONF --> MCP
    FF --> MCP
    FF --> HARN
```

Sources: [app/src/features.rs:8-13](app/src/features.rs#L8-L13), [crates/warp_core/src/channel/state.rs:26-65](crates/warp_core/src/channel/state.rs#L26-L65), [app/Cargo.toml:16-54](app/Cargo.toml#L16-L54)

## The Settings System

A *setting* is a typed, persisted, user-facing value. Settings are registered against a central `SettingsManager` keyed by a string **storage key**, and split into two backends: **public** settings live in the user-editable TOML settings file (when the `SettingsFile` flag is enabled) and **private** settings always live in the platform-native store (UserDefaults on macOS, a JSON file on Linux, the registry on Windows). The newtype wrappers `PublicPreferences` and `PrivatePreferences` enforce this split and keep the raw backend `pub(crate)`, so external code must go through the typed groups produced by `define_settings_group!` rather than touch preferences directly.

```rust
// crates/settings/src/lib.rs:66-90 (abridged)
/// Public settings (those marked `private: false` in `define_settings_group!`)
/// are stored in the user-visible settings file (TOML) when the `SettingsFile`
/// feature flag is enabled, otherwise in the platform-native store.
pub struct PublicPreferences(Box<dyn UserPreferences>);
```

`SettingsManager` stores, per storage key, a `SettingsInfo` record (sync behavior, supported platforms, serialized defaults, TOML key, table depth, privacy) plus a set of closures: `update_fn`, `clear_fn`, `load_fn`, `equals_fn`, and `is_syncable_fn`. The `equals_fn` exists because settings cannot be compared as raw JSON — types like `HashSet` serialize to arrays with no defined order — so equality is delegated to the setting's own value semantics. Cloud sync precedence is captured by `SyncToCloud`, and `sync_regardless_of_users_syncing_setting` distinguishes settings that sync even when the user has disabled syncing.

| `SettingsManager` responsibility | Method | Notes |
|---|---|---|
| Register a setting + its closures | `register_setting` | Called by the `define_settings_group!` expansion |
| Read current local value | `read_local_setting_value` | Routes private→private store, public→TOML when `SettingsFile` is on |
| Apply an update | `update_setting_with_storage_key` | `from_cloud_sync` flag distinguishes origin |
| Hot-reload from disk | `reload_all_public_settings` → `load_setting` | Loads into memory without writing back, avoiding file-watcher loops |
| Validate file values | `validate_all_public_settings` | Read-only deserialization check on startup |
| Emit defaults for the file | `default_values_for_settings_file` | Public settings only, with hierarchy + table depth |

Sources: [crates/settings/src/manager.rs:32-139](crates/settings/src/manager.rs#L32-L139), [crates/settings/src/manager.rs:224-250](crates/settings/src/manager.rs#L224-L250), [crates/settings/src/manager.rs:315-406](crates/settings/src/manager.rs#L315-L406), [crates/settings/src/lib.rs:66-128](crates/settings/src/lib.rs#L66-L128)

### Hot reload and validation

`reload_all_public_settings` is the heart of the live-edit experience for the TOML file. It reads every non-public-excluded setting from a freshly-reloaded preferences store, then applies each through `load_setting`, which updates in-memory state **without** persisting — this is the explicit mechanism for not fighting the file watcher with a write-back loop. Keys present in the file load with `explicitly_set = true`; absent keys reset to their serialized default with `explicitly_set = false`. A setting that fails to load is "re-inhibited" (`inhibit_writes_for_key`) so a user's broken-but-fixable value is not overwritten, and its key is returned to the caller for error reporting.

Sources: [crates/settings/src/manager.rs:315-375](crates/settings/src/manager.rs#L315-L375)

## The Settings Schema

Warp ships a JSON Schema for its settings file so editors can validate and autocomplete `settings.toml`. The schema is built from an `inventory`-collected registry: each setting registered via the macros emits one `SettingSchemaEntry` through `submit_schema_entry!`. An entry carries the storage key, description, TOML hierarchy, privacy flag, an optional gating `FeatureFlag`, and function pointers for the type schema and default values.

```rust
// crates/settings/src/schema.rs:25-46 (abridged)
pub struct SettingSchemaEntry {
    pub storage_key: &'static str,
    pub description: &'static str,
    pub hierarchy: Option<&'static str>,
    pub is_private: bool,
    /// If Some, the setting is only included in the schema when the flag
    /// is active for the target build channel.
    pub feature_flag: Option<warp_features::FeatureFlag>,
    // ...schema_fn, default_value_fn, file_default_value_fn, max_table_depth
}
inventory::collect!(SettingSchemaEntry);
```

The `generate_settings_schema` binary iterates that registry. It is **channel-aware**: `active_flags_for_channel` maps a channel name to flag lists (`stable` → `RELEASE_FLAGS`; `preview` → `RELEASE_FLAGS + PREVIEW_FLAGS`; `dev` → all four lists), and any setting whose `feature_flag` is not active for the requested channel is skipped — as are all private settings. The generator nests settings into TOML section hierarchies (`ensure_hierarchy`), prefers the file-format default over the serde default, and strips type-derived numeric metadata (`minimum`/`maximum`/`format` that schemars infers from Rust primitives) because those leak implementation bounds rather than semantic ones.

Sources: [crates/settings/src/schema.rs:7-99](crates/settings/src/schema.rs#L7-L99), [app/src/bin/generate_settings_schema.rs:87-107](app/src/bin/generate_settings_schema.rs#L87-L107), [app/src/bin/generate_settings_schema.rs:174-219](app/src/bin/generate_settings_schema.rs#L174-L219)

## Runtime Feature Gating: `warp_features`

`warp_features` defines a single large `FeatureFlag` enum (hundreds of variants, each documented inline) and resolves each flag's state from three layers of backing storage. State lives in fixed-size atomic arrays sized by `cardinality::<FeatureFlag>()`, so a lookup is an `O(1)` indexed atomic read with no allocation.

`FeatureFlag::is_enabled()` resolves with a strict precedence: a **thread-local test override** wins first, then a **user preference** (the `USER_PREFERENCE_MAP` tri-state, allowing explicit opt-in/opt-out), then the **global flag state** (`FLAG_STATES`), defaulting to `false`. In debug builds, calling `is_enabled()` before `mark_initialized()` panics, guaranteeing flags are never read before the channel wires them up.

```text
FeatureFlag::is_enabled() resolution order
┌─────────────────────────────┐
│ test override (thread-local)│  ← override_enabled(), test-util only
└──────────────┬──────────────┘
               │ None
┌──────────────▼──────────────┐
│ USER_PREFERENCE_MAP (TriState)│ ← set_user_preference(): explicit opt in/out
└──────────────┬──────────────┘
               │ Unset
┌──────────────▼──────────────┐
│ FLAG_STATES (AtomicBool[])  │ ← set_enabled(): global, from channel init
└──────────────┬──────────────┘
               │ default
            false
```

Flags are grouped into rollout tiers as `&[FeatureFlag]` constants: `DEBUG_FLAGS`, `DOGFOOD_FLAGS` (internal team, en route to Preview), `PREVIEW_FLAGS` (Friends of Warp; also enabled in dogfood), and `RELEASE_FLAGS` (every release build but `WarpLocal`). `RUNTIME_FEATURE_FLAGS` enumerates flags that may flip at runtime when `RuntimeFeatureFlags` is set. The `flag_description` method intentionally returns text only for Preview-exclusive flags, to control what surfaces in the Preview changelog.

Sources: [crates/warp_features/src/lib.rs:881-996](crates/warp_features/src/lib.rs#L881-L996), [crates/warp_features/src/lib.rs:1051-1054](crates/warp_features/src/lib.rs#L1051-L1054), [crates/warp_features/src/lib.rs:1139-1198](crates/warp_features/src/lib.rs#L1139-L1198)

### How flags become enabled at startup

`app/src/features.rs` is the bridge between compile-time configuration and runtime state. `init_feature_flags` calls `enabled_features()` and globally enables each returned flag, then marks the system initialized. `enabled_features()` unions three sources: the running channel's `additional_features`, `RELEASE_FLAGS` when the build is a release bundle, and a long list of flags each guarded by a `#[cfg(feature = "...")]` cargo feature. The cargo-feature layer is what makes a flag's code *exist* in a build; the channel layer is what turns baseline release features *on*.

```rust
// app/src/features.rs:15-24 (abridged)
fn enabled_features() -> HashSet<FeatureFlag> {
    let mut flags = ChannelState::additional_features();
    if ChannelState::is_release_bundle() {
        flags.extend(RELEASE_FLAGS);
    }
    flags.extend([ /* #[cfg(feature = "...")] FeatureFlag::... */ ]);
    flags
}
```

Sources: [app/src/features.rs:6-30](app/src/features.rs#L6-L30), [app/src/features.rs:494-497](app/src/features.rs#L494-L497)

## Build Channels and Release Binaries

A **channel** identifies which build is running. `Channel` enumerates `Stable`, `Preview`, `Dev`, `Local`, `Oss`, and `Integration`, and encodes their policy differences directly: `is_dogfood` (Dev/Local only), `allows_server_url_overrides` (only the internal channels honor `--server-root-url` and `WARP_*` env overrides, so shipped builds cannot be redirected), `cli_command_name` (e.g. `oz`, `oz-preview`, `warp-oss`), and a per-channel `url_scheme` (`warp`, `warppreview`, `warpdev`, …).

| Channel | Dogfood | Server-URL overrides | CLI command | URL scheme |
|---|---|---|---|---|
| `Stable` | no | no | `oz` | `warp` |
| `Preview` | no | no | `oz-preview` | `warppreview` |
| `Dev` | yes | yes | `oz-dev` | `warpdev` |
| `Local` | yes | yes | `oz-local` | `warplocal` |
| `Oss` | no | no | `warp-oss` | `warposs` |
| `Integration` | no | yes | `oz-integration` | `warpintegration` |

The channel and its endpoints are held by `ChannelState`, a process-global behind a `Mutex`, combining the active `Channel`, an `additional_features` set, and a `ChannelConfig`. `ChannelConfig` groups all the externally-facing endpoints and credentials: `WarpServerConfig` (server root, RTC websocket, session sharing, Firebase auth key), `OzConfig` (ambient-agent dashboard URL), and **optional** `telemetry_config`, `autoupdate_config`, `crash_reporting_config`, and `mcp_static_config`. The optionality is meaningful: a build such as OpenWarp intentionally ships with `telemetry_config: None`, and `is_telemetry_available()` lets the UI hide controls that would otherwise have no effect.

Sources: [crates/warp_core/src/channel/mod.rs:9-74](crates/warp_core/src/channel/mod.rs#L9-L74), [crates/warp_core/src/channel/state.rs:26-89](crates/warp_core/src/channel/state.rs#L26-L89), [crates/warp_core/src/channel/state.rs:183-197](crates/warp_core/src/channel/state.rs#L183-L197), [crates/warp_core/src/channel/config.rs:7-52](crates/warp_core/src/channel/config.rs#L7-L52)

### One binary target per channel

`app/Cargo.toml` declares a distinct `[[bin]]` for each channel (`oss`, `local`, `integration`, `stable`, `dev`, `preview`) plus the `generate_settings_schema` helper, with `autobins = false` so only these explicit targets compile and `default-run = "warp-oss"`. The comment in the manifest notes the binaries are otherwise identical to the main binary; the difference is icon, app name, and channel-specific config such as flag overrides. Each channel `main` is a thin wrapper that installs the channel state then calls `warp::run()`:

```rust
// app/src/bin/stable.rs:12-19
fn main() -> Result<()> {
    ChannelState::set(ChannelState::new(
        Channel::Stable,
        channel_config::load_config!("stable"),
    ));
    warp::run()
}
```

The `load_config!` macro (shared via `#[path = "channel_config.rs"]`) decides *where* the channel's JSON config comes from based on the `release_bundle` cargo feature. In a release bundle the config is embedded at compile time via `include_str!(env!("OUT_DIR")/<channel>_config.json)`; otherwise `load_config_from_generator` shells out at runtime to a `warp-channel-config` binary expected on `PATH`, passing `--channel`, `--target-family`, and `--target-os`. A missing generator prints actionable guidance (`./script/install_channel_config`).

Sources: [app/Cargo.toml:16-54](app/Cargo.toml#L16-L54), [app/src/bin/stable.rs:1-19](app/src/bin/stable.rs#L1-L19), [app/src/bin/channel_config.rs:25-101](app/src/bin/channel_config.rs#L25-L101)

### Docker packaging

Container assets are split by purpose under `docker/` (plus packaging helpers under `.github/actions/`). `docker/linux-dev/Dockerfile` builds a Debian-`sid` development environment: it installs build toolchain and X11/Vulkan runtime libraries, `protobuf-compiler` (needed to build the `warp-proto-apis` MAA crates), the GitHub and gcloud CLIs, a `dev` user, rustup pinned to the repository's `rust-toolchain.toml`, and an SSH server exposed on port 22 so a host can connect to the containerized build. This is an environment image for building/running Warp on Linux, not a distribution artifact of Warp itself.

Sources: [docker/linux-dev/Dockerfile:1-81](docker/linux-dev/Dockerfile#L1-L81)

## Extension Surfaces

The boundary layer also defines where outside code extends Warp. Two surfaces matter most.

**MCP (Model Context Protocol) servers.** Warp supports user-configured MCP servers as a tool/resource source for the agent. Channel-level OAuth credentials for providers that lack dynamic client registration are baked into `ChannelConfig::mcp_static_config` as `McpStaticConfig { providers: Vec<McpOAuthProviderConfig> }`, looked up at runtime by client ID or issuer (`mcp_oauth_provider_by_client_id` / `mcp_oauth_provider_by_issuer`). The feature is gated by several flags — `McpServer` (v0), `McpOauth`, `FileBasedMcp` (`.mcp.json` files discovered at repo roots), `MCPGroupedServerContext`, and `McpDebuggingIds` — and surfaced through dedicated settings UI under `app/src/settings_view/mcp_servers/`.

**BYO CLI agent harnesses.** A *harness* selects which engine executes an agent run. `warp_cli::agent::Harness` is a `clap` `ValueEnum` whose variants are `Oz` (Warp's built-in MAA, the default), `Claude`, `OpenCode`, `Gemini`, `Codex`, and a non-selectable `Unknown` for forward compatibility with newer servers. External harnesses are reached via the `--harness` flag, gated by the `AgentHarness` feature flag, and each third-party CLI has its own install/notification flag (`OpenCodeNotifications`, `CodexNotifications`, `GeminiNotifications`, all layered on `HOANotifications`). This is the BYO/BYOK-friendly seam: any agent CLI a contributor uses is a portable, provider-neutral plug-in point rather than a hardwired dependency — a model the contribution guide reinforces by stating you can "use **any coding agent**."

```rust
// crates/warp_cli/src/agent.rs:131-155 (abridged)
pub enum Harness {
    #[default] Oz,            // Warp's built-in MAA infrastructure
    Claude,                   // delegate to `claude` CLI
    OpenCode,                 // delegate to `opencode` CLI
    Gemini,                   // delegate to `gemini` CLI
    Codex,                    // delegate to `codex` CLI
    Unknown,                  // forward-compat, never CLI-selectable
}
```

Sources: [crates/warp_core/src/channel/config.rs:125-144](crates/warp_core/src/channel/config.rs#L125-L144), [crates/warp_core/src/channel/state.rs:357-377](crates/warp_core/src/channel/state.rs#L357-L377), [crates/warp_features/src/lib.rs:263-264](crates/warp_features/src/lib.rs#L263-L264), [crates/warp_features/src/lib.rs:670-671](crates/warp_features/src/lib.rs#L670-L671), [crates/warp_cli/src/agent.rs:128-198](crates/warp_cli/src/agent.rs#L128-L198), [CONTRIBUTING.md:119-125](CONTRIBUTING.md#L119-L125)

## Where to Look Next

The contribution model in `CONTRIBUTING.md` ties these boundaries together operationally: feature work proceeds through readiness labels and `specs/`, agent-readable context ships under `.agents/skills/`, and review is automated by the Oz agent. Concretely, to extend the boundary layer you would: add a `FeatureFlag` variant plus its `#[cfg(feature = "...")]` wiring in `app/src/features.rs`; register a setting through `define_settings_group!` so it joins both `SettingsManager` and the schema registry; add a channel endpoint to `ChannelConfig`; or register a new MCP server / agent harness. The strict layering — cargo feature → channel → flag → setting — means a change is usually localized to exactly one of these tiers, and the schema generator's channel-scoped flag filtering ensures the published settings surface always matches what a given release can actually do.

Sources: [CONTRIBUTING.md:16-55](CONTRIBUTING.md#L16-L55), [crates/settings/src/schema.rs:25-48](crates/settings/src/schema.rs#L25-L48), [crates/warp_core/src/channel/config.rs:7-28](crates/warp_core/src/channel/config.rs#L7-L28)

---