> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/warpdotdev/warp/llms.txt
> Use this file to discover all available pages before exploring further.

# Feature flags in the Warp codebase

> Understand the FeatureFlag enum in warp_features, the DOGFOOD, PREVIEW, and RELEASE rollout stages, and how to add, gate, and test a new feature flag.

Warp uses a lightweight feature flag system to control which behaviors are active in different build configurations. Flags are defined as variants on the `FeatureFlag` enum in the `warp_features` crate, evaluated at runtime via `is_enabled()`, and organized into static arrays that determine their default state in dogfood, preview, and release builds. This approach lets you ship incomplete features safely, run A/B experiments via server-side experiments, and clean up dead code after a feature graduates to stable.

## The FeatureFlag enum

All flags live in a single `FeatureFlag` enum in `crates/warp_features/src/lib.rs`. The enum derives `Sequence` (from the `enum_iterator` crate) so the framework can iterate over all variants to initialize and manage state arrays.

```rust theme={null}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Sequence)]
pub enum FeatureFlag {
    // Infrastructure
    Autoupdate,
    CrashReporting,
    DebugMode,
    RuntimeFeatureFlags,

    // Drive and sharing
    CloudObjects,
    CreatingSharedSessions,
    ViewingSharedSessions,
    SharedWithMe,
    SessionSharingAcls,
    SharedSessionWriteToLongRunningCommands,

    // AI and Agent Mode
    AgentMode,
    AgentModeWorkflows,
    AgentModeAnalytics,
    AgentPredict,

    // … 100+ additional variants
}
```

Each variant maps to an `AtomicBool` slot in a static `FLAG_STATES` array. The index is determined by the variant's position in the `Sequence` iteration order, so variants must never be reordered or removed until the flag is fully cleaned up.

## Rollout stages

Flags graduate through a series of static arrays, each representing a broader audience:

<Tabs>
  <Tab title="DEBUG_FLAGS">
    Enabled only in local debug builds. Used for low-level diagnostics that
    should never reach any users.

    ```rust theme={null}
    pub const DEBUG_FLAGS: &[FeatureFlag] = &[
        FeatureFlag::DebugMode,
        FeatureFlag::RuntimeFeatureFlags,
    ];
    ```
  </Tab>

  <Tab title="DOGFOOD_FLAGS">
    Enabled for the Warp development team (internal "dogfood" builds). This is
    where new features start their testing life. Examples from the codebase:

    ```rust theme={null}
    pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
        FeatureFlag::CreatingSharedSessions,
        FeatureFlag::AgentModeWorkflows,
        FeatureFlag::LazySceneBuilding,
        FeatureFlag::Projects,
        FeatureFlag::OzPlatformSkills,
        // … and many more
    ];
    ```
  </Tab>

  <Tab title="PREVIEW_FLAGS">
    Enabled for Preview ("Friends of Warp") builds in addition to dogfood.
    All `PREVIEW_FLAGS` are automatically included in dogfood builds too.

    ```rust theme={null}
    pub const PREVIEW_FLAGS: &[FeatureFlag] = &[
        FeatureFlag::Orchestration,
        FeatureFlag::BlocklistMarkdownTableRendering,
        FeatureFlag::MarkdownTables,
        FeatureFlag::GitOperationsInCodeReview,
        // Conditional compilation is allowed here for platform exclusions
        #[cfg(not(windows))]
        FeatureFlag::SshRemoteServer,
    ];
    ```
  </Tab>

  <Tab title="RELEASE_FLAGS">
    Enabled for all release builds. Features here are effectively on for
    everyone. Prefer enabling via `app/Cargo.toml` features when graduating
    a flag from Preview to stable launch.

    ```rust theme={null}
    pub const RELEASE_FLAGS: &[FeatureFlag] = &[
        FeatureFlag::Autoupdate,
        FeatureFlag::Changelog,
        FeatureFlag::CrashReporting,
        #[cfg(target_os = "macos")]
        FeatureFlag::ImeMarkedText,
    ];
    ```
  </Tab>
</Tabs>

## How to add a new flag

<Steps>
  <Step title="Add the variant to FeatureFlag">
    Open `crates/warp_features/src/lib.rs` and add your variant to the
    `FeatureFlag` enum. Add a doc comment explaining what the flag gates:

    ```rust theme={null}
    /// Enables the new branch history sidebar.
    BranchHistorySidebar,
    ```

    Add it near related flags for readability, but do not reorder existing
    variants — their array indices are load-bearing.
  </Step>

  <Step title="Optionally add to a rollout array">
    Add the variant to `DOGFOOD_FLAGS` if you want it on by default for
    internal builds, or to `PREVIEW_FLAGS` for preview users:

    ```rust theme={null}
    pub const DOGFOOD_FLAGS: &[FeatureFlag] = &[
        // … existing flags …
        FeatureFlag::BranchHistorySidebar,
    ];
    ```

    Skip this step if you want the flag off everywhere by default (e.g., for
    a server-controlled experiment that is toggled via `set_enabled`).
  </Step>

  <Step title="Gate code paths with is_enabled()">
    Use `FeatureFlag::YourFlag.is_enabled()` at each gated call site:

    ```rust theme={null}
    if FeatureFlag::BranchHistorySidebar.is_enabled() {
        // show the sidebar entrypoint
    }
    ```

    For UI components, gate the entire component's construction:

    ```rust theme={null}
    if FeatureFlag::BranchHistorySidebar.is_enabled() {
        elements.push(BranchHistorySidebar::render(ctx));
    }
    ```
  </Step>

  <Step title="Add a flag description (Preview-only)">
    If the flag is in `PREVIEW_FLAGS` and you want it to appear in the Preview
    changelog, add a match arm in `flag_description()`:

    ```rust theme={null}
    BranchHistorySidebar => {
        Some("Enables the branch history sidebar for quick navigation between recent branches.")
    }
    ```
  </Step>
</Steps>

## Checking flag state

```rust theme={null}
// Check whether a flag is currently enabled
if FeatureFlag::CreatingSharedSessions.is_enabled() {
    show_share_button(ctx);
}
```

`is_enabled()` resolves state in priority order:

1. **Thread-local test override** (if set via `override_enabled`)
2. **User preference** (set via `set_user_preference`, e.g. from a UI toggle)
3. **Global flag state** (set at startup from `DOGFOOD_FLAGS`, `PREVIEW_FLAGS`, `RELEASE_FLAGS`, or server experiments)

## Runtime and server-controlled flags

Some flags are toggled at runtime by the server rather than at startup. The server can enable or disable flags via a `ServerExperiment` mechanism. For example, `CreatingSharedSessions` is enabled for paying team plans and members of the session-sharing experiment group, even without the flag being in `DOGFOOD_FLAGS`.

The `RuntimeFeatureFlags` flag gates the runtime toggle mechanism itself — when it is on, the set of `RUNTIME_FEATURE_FLAGS` can be changed without restarting.

## Testing with flag overrides

In unit tests, use `override_enabled` to set a flag for the duration of the test without affecting global state. The override is thread-local and automatically reverts when the returned guard is dropped:

```rust theme={null}
#[cfg(test)]
mod tests {
    use warp_features::FeatureFlag;

    #[test]
    fn test_share_button_visibility() {
        // Enable the flag for this test only
        let _guard = FeatureFlag::CreatingSharedSessions.override_enabled(true);

        // … run assertions …
    } // _guard dropped here; flag reverts to its previous state
}
```

<Warning>
  `override_enabled` is only available when the `test-util` feature is enabled
  on the `warp_features` crate. Do not use `set_enabled` in unit tests — it
  mutates global state and can cause interference between parallel tests.
</Warning>

## Best practices

* **Prefer runtime checks**: use `FeatureFlag::YourFlag.is_enabled()` over `#[cfg(...)]` compile-time directives so flags can be toggled without recompilation and are easier to clean up. Reserve `#[cfg(...)]` for code that genuinely cannot compile without the feature (platform-specific dependencies, etc.).
* **Keep flags high-level and product-focused**: one flag per feature, not one flag per call site.
* **Remove flags after launch**: once a feature has stabilized in a release build, delete the enum variant, all `is_enabled()` checks, and any dead branches. The codebase should not accumulate permanent flags.
* **Gate the UI entry point**: if a flag hides a new UI surface, gate the entry point (button, menu item, panel) with the same flag so the feature is invisible when disabled.
