7.4 KiB
7.4 KiB
PRODUCT.md
Summary
Add a Harness filter dropdown to AgentManagementView so users can narrow the Runs list to runs driven by a specific execution harness (Warp Agent, Claude Code, Gemini CLI), and surface the harness on each run card's metadata line.
Figma
Figma: none provided. Visual treatment matches the existing filter dropdowns in app/src/ai/agent_management/view.rs (Status, Source, Has artifact, etc.) and the harness icon + brand-color treatment established by the conversation details sidebar in specs/REMOTE-1455/PRODUCT.md.
Behavior
- A Harness dropdown is present in the filters row of the Runs header on
AgentManagementView, alongside the existing Status, Source, Created on, Has artifact, Environment, and Created by dropdowns. It is visible under the same conditions as the existing dropdowns (no extra feature-flag gating beyond whatever already gates the view). - The dropdown label prefix is
Harness, so the button readsHarness: <selected>after a selection, matching theStatus: …/Source: …treatment from the adjacent dropdowns. - The dropdown exposes exactly these options, in this order:
All— no harness filtering.Warp Agent— the default/Oz harness.Claude Code— the Claude harness.Gemini CLI— the Gemini harness. Display names matchapp/src/ai/harness_display.rs::display_name. If a new harness is added towarp_cli::agent::Harnesslater, it is expected to appear here too, but adding it is out of scope for this feature.
- Each non-
Alloption renders its harness's leading logo icon, tinted with that harness's brand color, matching the treatment used in the conversation details sidebar (REMOTE-1455): Warp/Oz uses the first-party Warp icon + theme foreground, Claude usesIcon::ClaudeLogotinted Claude orange, Gemini usesIcon::GeminiLogotinted Gemini blue. TheAlloption has no leading icon, consistent with the existing Status dropdown'sAllrow. - The selected harness appears in the dropdown's collapsed button label, e.g.
Harness: Claude Code. The default selection isAll. - Selecting a harness option filters the visible Runs list to items whose resolved harness equals the selected value:
- A cloud task whose
agent_config_snapshot.harness.harness_typeis set matches the option for that harness. - A cloud task whose
agent_config_snapshotis present but has noharnessfield is treated asWarp Agentand matches only theWarp Agentoption. - A cloud task whose
agent_config_snapshothas not loaded yet (e.g. a stub row) has an unknown harness; it matches only theAlloption and is excluded from every specific-harness filter, includingWarp Agent. This mirrors the conversation details sidebar behavior, which omits the harness row when the harness is unknown. - A local/interactive conversation (no ambient task) is treated as
Warp Agentand matches only theWarp Agentoption. - No item ever matches more than one specific-harness option.
- A cloud task whose
- Selecting
Allclears the harness constraint and restores the list to what it would be with no harness filter applied (all other filters still respected). - The Harness filter is independent of every other filter. It combines with the existing Owner, Status, Source, Created on, Has artifact, Environment, Creator, and search filters via logical AND — an item appears only if it matches all active filters.
- When the Harness filter is set to anything other than
All,AgentManagementFilters::is_filtering()reportstrue, so the existingClear allchip appears and, when clicked, resets Harness toAllalong with the other non-owner filters. Clear filtersfrom the empty-results view (render_no_results_view) also resets Harness toAll.- The selected Harness value persists across app restarts via
PersistedAgentManagementFilters, matching how Status, Source, Created on, Artifact, and Environment already persist. On first launch after upgrade (no persisted value), the filter defaults toAll. - Changing the Harness filter triggers the same server refresh path that other filter changes do — i.e. the view calls its common "filter changed" handler so the server list fetch is retried with the new filter set and the local list re-renders. If the server does not yet support filtering by harness, the visible list must still honor the selected harness by filtering client-side over tasks already loaded in the model; users must not see runs from harnesses other than the one selected.
- The Harness filter never changes which tasks are loaded into the underlying model for other views (details panel, transcript panel, deep-link navigation). It only affects which of those already-loaded items are displayed in the Runs list.
- If the Runs list ends up empty solely because the Harness filter excluded every loaded item, the existing no-results state (
No results matched your filters+Clear filtersbutton) is shown, identical to what other filters already produce. - The Owner toggle (
PersonalvsAll) does not affect Harness semantics: Harness filters the same way regardless of whether the user is viewing personal-only or team-wide runs. - The deep-link flow that scopes the view to a specific environment (
apply_environment_filter_from_link) resets Harness toAllalong with the other non-owner filters, so a deep link never leaves a stale harness constraint in place. - Telemetry: changing the Harness dropdown emits the existing
FilterChangedtelemetry event with a newFilterType::Harnessvariant, consistent with how Status, Source, CreatedOn, Owner, and Creator changes are already tracked. - Keyboard and focus behavior for the Harness dropdown matches the other filter dropdowns in the same row — it is reachable via Tab navigation from adjacent dropdowns and obeys the same open/close keybindings the existing filter dropdowns already honor. No new global keybinding is introduced for Harness.
- Every run card in the list renders a
Harness: <display name>segment on its metadata line, immediately after theSource: …segment and beforeRun time: …/Credits used: …, using the existing•separator between segments. Example:Source: Oz Web • Harness: Claude Code • Run time: 2 minutes. - The
<display name>on each card uses the same resolution as the Harness filter (invariant 6): explicit, knownharness_type→ that harness's display name; snapshot-present-but-no-harness →Warp Agent; local/interactive conversations →Warp Agent. Display names matchapp/src/ai/harness_display.rs::display_name(Warp Agent,Claude Code,Gemini CLI). When a card's harness is unknown (per invariant 6, third bullet), the Harness segment is omitted entirely — the card does not guessWarp Agent. - The Harness segment is included on every card whose harness is known (per invariant 20). It is not gated on any filter, the Source segment's presence, or card hover state. If the Source segment is omitted (e.g. a local conversation with no
AgentSource), a present Harness segment becomes the row's leading segment. - The Harness segment on cards is text-only — no leading icon, no brand color, no click target, no tooltip. It uses the same text color and font as the rest of the metadata row.
- Selecting a specific harness in the Harness filter hides cards whose resolved harness does not match (including cards with an unknown harness); cards that remain visible continue to show their own Harness segment, which will match the selected filter value.