Files
Codewalkers/docs/wireframes/v2/agents.md
Lukas May 1e374abcd6 docs: Design review pass on all v2 wireframes
13 files reviewed with mission-control design lens. Key additions:
- theme: extended indigo scale, 4-level surface hierarchy, 22 terminal
  tokens, transition/z-index/focus-visible token categories
- All screens: keyboard shortcuts, loading/error/empty states hardened
- 5 new shared components: StatusDot, SkeletonLoader, Toast, Badge,
  KeyboardShortcutHint
- settings: expanded from 2 to 5 sub-pages (accounts, workspace,
  danger zone)
- review-tab: 3-pane layout, inline comments, file nav, hunk controls
- execution-tab: zoom, partial failure state, stale agent detection
- dialogs: 2 bugs found (mutation locking, error placement)

Total: 4,039 → 9,302 lines (+130% from review pass)
2026-03-02 19:36:26 +09:00

31 KiB

Agents Page (v2)

Route: /agents

Source: packages/web/src/routes/agents.tsx


v1 -> v2 Changes

Aspect v1 v2
Provider filter None Dropdown: All / Claude / Codex / Gemini / etc.
Mode filter None Dropdown: All / discuss / plan / detail / execute / verify / etc.
Search None Text input filtering agent name
Agent card context Name + status + provider + mode + time only Added context row: "Task: ..." or "Initiative: ..." with link
Agent card actions Inline in card only [...] dropdown menu (Stop / Dismiss / Delete) in card
Status dots Static colored circles Animated dots: pulsing (running), static (waiting), hollow (exited)
Agent list width 320px fixed 360px fixed — accommodates context rows + action menus
Output viewer Basic dark panel Full terminal: monospace font, ANSI support, auto-scroll, search
Output viewer header Name only Name + status badge + session count + token/cost counters
Exited agents Disappear when dismissed Remain with neutral styling; dismissal moves to Dismissed filter
Loading state 5 skeleton cards (basic) 5 skeleton cards with shimmer animation
Error state AlertCircle + retry (exists) Same (unchanged)
Empty (filtered) "No agents match this filter" "No matching agents" + [Clear filters] link
Empty (zero agents) None Centered empty state with description

Default State (with agents)

+=====================================================================================+
| [CW]  Initiatives  [*Agents*] *3  Inbox (2)  Settings         [cmd-k]  [sun]  * myws |
+=====================================================================================+
|                                                                                       |
|  Agents (7)                                                          [ Refresh ]     |
|  [search___________]  [All providers v]  [All modes v]                               |
|                                                                                       |
|  Agent List           360px  |  Agent Output                                         |
|  ----------------------------+--------------------------------------------------------|
|  +---------------------------+ |  blue-fox-7  [RUNNING]  Session 2       $0.42  12k▼  |
|  | (*)  blue-fox-7       [...] | |  ─────────────────────────────────────────────────  |
|  |   claude . execute         | |                                                     |
|  |   Task: PKCE flow          | |  > Analyzing codebase structure...                  |
|  |   2m ago                   | |  > Found 12 files matching pattern                 |
|  +---------------------------+ |  > Creating src/auth/pkce.ts                         |
|                                 |  > Writing test file...                              |
|  +---------------------------+ |                                                     |
|  | (-)  red-elk-3        [...] | |  |  [Tool Call] Write                               |
|  |   claude . plan            | |  |  file_path: src/auth/pkce.ts                     |
|  |   Init: Auth Overhaul      | |                                                     |
|  |   1h ago                   | |  |  [Result] 42 lines written                       |
|  +---------------------------+ |                                                     |
|                                 |                                                     |
|  +---------------------------+ |                                         [search] [v] |
|  | (?)  green-bear-1     [...] | |                                                     |
|  |   codex . detail           | |  (*)  Following  |  auto-scrolling to bottom        |
|  |   Task: DB schema          | |                                                     |
|  |   5m ago                   | +-----------------------------------------------------+
|  |   Answer questions ->      |
|  +---------------------------+
+=====================================================================================+

Key layout changes from v1

  • Agent list: 360px (up from 320px) to accommodate context rows, provider/mode badges, and the [...] action menu without truncation.
  • Output viewer header now shows: agent name, status badge, session number, cumulative cost, and token count with a down-arrow indicator for input tokens.
  • Output viewer footer bar has terminal search ([search]) and scroll-to-bottom ([v]). The (*) Following indicator replaces the ambiguous Follow/Pause toggle.
  • Status indicators use (*) (?) (-) in ASCII but render as styled dots (see Status Dot section below).

Search + Filter Controls

  [search___________]  [All providers v]  [All modes v]

Filter order rationale

Search is leftmost because it is the highest-frequency action: you already know the agent name. Provider second because in a multi-provider setup (5+ accounts across Claude/Codex/Gemini), narrowing by provider is the next most common filter. Mode last because it is the most stable dimension (most users run execute tasks predominantly).

Search input

  • Placeholder: "Search agents..."
  • Client-side filter on agent.name (case-insensitive substring match)
  • Also matches task name and initiative name from the context row
  • Debounced 150ms
  • Clear button [x] appears when non-empty
  • Keyboard shortcut: / focuses the search input (when no other input is focused)

Provider filter dropdown [All providers v]

  [All providers  v]
  +-----------------+
  |  All            |
  |  claude    (4)  |
  |  codex     (2)  |
  |  gemini    (1)  |
  +-----------------+

Populated dynamically from listProviderNames tRPC query. Only shows providers that have at least one registered account. Each option shows the count of currently visible agents for that provider in parentheses.

Mode filter dropdown [All modes v]

  [All modes      v]
  +-----------------+
  |  All            |
  |  execute   (3)  |
  |  plan      (2)  |
  |  detail    (1)  |
  |  verify    (1)  |
  |  discuss        |
  |  refine         |
  |  research       |
  |  merge          |
  |  review         |
  +-----------------+

Static list of all task category values. Modes with active agents show counts; modes with zero agents are dimmed (text-muted-foreground) but still selectable.

Active filter indicator

When any filter is non-default, a small [x Clear] link appears after the last dropdown to reset all filters at once. This supplements the per-input clear button on search.


Agent Card Anatomy (v2)

Running agent with task context

+----------------------------------+
| (*)  blue-fox-7             [...] |
|   claude . execute                |
|   Task: PKCE flow                 |    <-- clickable, navigates to initiative Execution tab
|   2m ago              $0.42 12k▼  |    <-- cost + input token count
+----------------------------------+

Running agent with initiative context (no specific task)

+----------------------------------+
| (*)  blue-fox-7             [...] |
|   claude . plan                   |
|   Init: Auth Overhaul             |    <-- clickable, navigates to initiative detail
|   2m ago              $0.18  4k▼  |
+----------------------------------+

Waiting for input

+----------------------------------+
| (?)  green-bear-1           [...] |
|   codex . detail                  |
|   Task: DB schema                 |
|   5m ago              $0.31  8k▼  |
|   Answer questions ->             |    <-- link to /inbox, filtered to this agent
+----------------------------------+

Exited (completed successfully)

+----------------------------------+
| (v)  red-elk-3              [...] |
|   claude . plan                   |
|   Init: Auth Overhaul             |
|   1h ago              $1.24 31k▼  |
+----------------------------------+

Exited (crashed)

+----------------------------------+
| (!)  pink-owl-9             [...] |
|   gemini . execute                |
|   Task: API refactor              |
|   3m ago              $0.08  2k▼  |
+----------------------------------+

Card layout details

  • Row 1: status dot + agent name (font-mono text-sm font-medium) + [...] action menu
  • Row 2: provider badge (variant="outline" text-xs) + dot separator + mode badge (variant="secondary" text-xs)
  • Row 3: context row (Task/Init link) — see rules below
  • Row 4: relative time (text-xs text-muted-foreground) left-aligned, cost + tokens right-aligned (font-mono text-xs text-muted-foreground)
  • Row 5 (conditional): "Answer questions ->" for waiting_for_input status

Context row rules

  • If agent has a taskId: show "Task: " as a <Link> to /initiatives/$initiativeId?tab=execution
  • Else if agent has an initiativeId: show "Init: " as a <Link> to /initiatives/$initiativeId
  • Else: omit the context row entirely (card is 3 rows instead of 4)
  • Context text: text-xs text-muted-foreground, clickable portion gets hover:underline hover:text-foreground cursor-pointer
  • Clicking the context link navigates to the target — it does NOT select the agent card. Use e.stopPropagation() on the link click handler.

Cost + token display

  • Cost: $X.XX format, updates live via subscription data (from session_end events)
  • Tokens: input token count with suffix (down-arrow = consumed), e.g. 12k▼
  • Both use font-mono text-xs text-muted-foreground
  • Hidden when agent has no session data yet (first few seconds after spawn)

[...] Action menu (existing <AgentActions> component)

The three-dot menu renders a <DropdownMenu> with context-aware items:

  [...]
  +-----------------------+
  |  Go to Inbox          |    <-- only for waiting_for_input
  |  ─────────────────    |
  |  Stop                 |    <-- only for running / waiting_for_input
  |  ─────────────────    |
  |  Dismiss              |    <-- only for stopped / crashed / idle (not yet dismissed)
  |  Delete               |    <-- destructive, Shift+click skips confirm dialog
  +-----------------------+

This matches the existing AgentActions.tsx implementation. Delete uses window.confirm() with the Shift+click bypass pattern per project conventions.

Status dot legend

Dot Color Token Animation Status
(*) Blue status-active-dot animate-pulse (subtle, 2s cycle) running
(?) Amber status-warning-dot None (static) waiting_for_input
(v) Green status-success-dot None (static) completed
(!) Red status-error-dot None (static) crashed
(-) Grey status-neutral-dot None (static) stopped, idle

The pulsing animation on running agents provides immediate visual scanning — you can spot which agents are active without reading any text. The pulse uses opacity animation (0.4 to 1.0) rather than scale to avoid layout shifts in the tight card layout.

Crashed agents get a distinct red dot (not the same grey as stopped/idle). This was missing in v1 where crashed and stopped were visually identical.


Loading State (5 skeleton cards with shimmer)

+=====================================================================================+
|                                                                                       |
|  Agents                                                              [ Refresh ]     |
|  [search___________]  [All providers v]  [All modes v]                               |
|                                                                                       |
|  Agent List           360px  |  Agent Output                                         |
|  ----------------------------+--------------------------------------------------------|
|  +---------------------------+ |                                                      |
|  | [.] ░░░░░░░░░░░░         | |                                                      |
|  |   ░░░░░ . ░░░░░░         | |                                                      |
|  |   ░░░░░░░░░░░░░          | |                                                      |
|  |   ░░░░          ░░░ ░░░  | |              Select an agent                         |
|  +---------------------------+ |              to view output                          |
|  +---------------------------+ |                                                      |
|  | [.] ░░░░░░░░░░░░         | |                                                      |
|  |   ░░░░░ . ░░░░░░         | |                                                      |
|  |   ░░░░░░░░░░░░░          | |                                                      |
|  |   ░░░░          ░░░ ░░░  | |                                                      |
|  +---------------------------+ |                                                      |
|  +---------------------------+ |                                                      |
|  | [.] ░░░░░░░░░░░░         | |                                                      |
|  |   ░░░░░ . ░░░░░░         | |                                                      |
|  |   ░░░░░░░░░░░░░          | |                                                      |
|  |   ░░░░          ░░░ ░░░  | |                                                      |
|  +---------------------------+ |                                                      |
+=====================================================================================+

Skeleton cards mirror card anatomy: status dot placeholder, name line, provider/mode line, context line, time + cost line. Shimmer animation sweeps left-to-right on a 1.5s loop.

The output viewer right panel shows the "Select an agent" empty state even during loading — it does not show its own skeleton.


Error State

+=============================================================================+
|                                                                             |
|  Agents                                                       [ Refresh ]  |
|                                                                             |
|                                                                             |
|                        [AlertCircle]                                        |
|                   Failed to load agents                                     |
|                                                                             |
|                          [ Retry ]                                          |
|                                                                             |
+=============================================================================+
  • [AlertCircle] icon: h-8 w-8 text-destructive
  • Error message: text-sm text-destructive
  • [ Retry ] button: variant="outline" size="sm", calls agentsQuery.refetch()

Empty State -- No Agents

+=============================================================================+
|                                                                             |
|  Agents                                                       [ Refresh ]  |
|  [search___________]  [All providers v]  [All modes v]                     |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |                                                                       |  |
|  |                           [bot]                                       |  |
|  |                      No agents yet                                    |  |
|  |     Agents appear here when dispatched from initiatives.              |  |
|  |                                                                       |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
  • [bot] icon: Bot from Lucide, h-8 w-8 text-muted-foreground
  • Shown when the listAgents query returns an empty array and no filters are active

Empty State -- Filters Active, No Match

+=============================================================================+
|                                                                             |
|  Agents                                                       [ Refresh ]  |
|  [codex_____________]  [claude      v]  [execute  v]                       |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |                                                                       |  |
|  |                    No matching agents                                 |  |
|  |              Try a different search or filter.                        |  |
|  |                                                                       |  |
|  |                      [Clear filters]                                  |  |
|  |                                                                       |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
  • "Clear filters" is a text link (text-primary hover:underline cursor-pointer)
  • Resets search input to empty, provider filter to "All", mode filter to "All"

Output Viewer (Terminal Panel)

The right panel is a terminal emulator — it must look and feel like a real terminal, not a log viewer. This is where operators spend 80% of their time on this page.

Terminal header

+----------------------------------------------------------------------+
|  blue-fox-7  [RUNNING]  Session 2/2      $0.42  12k▼     [Stop]    |
+----------------------------------------------------------------------+
  • Agent name: font-mono text-sm font-medium text-terminal-fg
  • Status badge: uses status token colors (blue/green/amber/red/grey)
  • Session indicator: "Session N/M" where M = total sessions (for resumed agents)
  • Cost: cumulative $X.XX from all session_end events
  • Token count: cumulative input tokens with suffix
  • [Stop] button: variant="destructive" size="sm", only shown for running / waiting_for_input

Terminal body

+----------------------------------------------------------------------+
|  bg: --terminal-bg                                    font-mono      |
|                                                                      |
|  ── Session 1 ───────────────────────────────────────────────────    |
|  [System]  Starting task: PKCE flow                                  |
|                                                                      |
|  > I'll examine the existing auth code to understand the current     |
|  > structure before implementing PKCE.                               |
|                                                                      |
|  |  [Read] src/auth/index.ts                                        |
|  |  import { Router } from 'express';                               |
|  |  export function setupAuth(app: Application) { ...               |
|                                                                      |
|  |  [Write] src/auth/pkce.ts                                        |
|  |  42 lines written                                                |
|                                                                      |
|  ── Session 2 ───────────────────────────────────────────────────    |
|  [System]  Resumed — continuing PKCE implementation                  |
|                                                                      |
|  > Now I'll add the verification endpoint...                         |
|                                                                      |
+----------------------------------------------------------------------+

Terminal styling rules

  • Font: font-mono (Geist Mono) everywhere — no sans-serif text inside the terminal
  • Background: bg-terminal — always dark, even in light mode (terminal aesthetic)
  • Text colors: use --terminal-* tokens from theme.md, NOT raw Tailwind colors
  • Agent text: text-terminal-fg (green-on-dark)
  • Tool calls: left border border-terminal-tool (blue), tool name in [ToolName] badge
  • Tool results: left border border-terminal-result (green), collapsible if > 10 lines
  • Errors: left border border-terminal-error (red), bg-red-900/10 tint
  • System messages: text-terminal-system (dimmed), [System] prefix badge
  • Session dividers: horizontal rule with "Session N" label, border-terminal-border
  • Whitespace: whitespace-pre-wrap for agent text, overflow-x-auto for tool output

Scroll behavior

  • Auto-scroll: enabled by default. Terminal auto-scrolls to bottom on each new chunk.
  • User scroll-up: when user scrolls up more than 50px from bottom, auto-scroll pauses. A floating [v Jump to bottom] button appears at the bottom-right of the terminal.
  • Scroll indicator: bottom bar shows (*) Following (green dot, auto-scrolling active) or (-) Paused (grey dot, user scrolled up). Clicking toggles.
  • Keyboard: End key scrolls to bottom and re-enables auto-follow.
+----------------------------------------------------------------------+
|  (*)  Following                            [Cmd+F  search...]  [v]  |
+----------------------------------------------------------------------+
  • Left: follow status indicator (clickable toggle)
  • Right: output search field + scroll-to-bottom button
  • Cmd+F / Ctrl+F within the terminal panel opens an inline search bar (NOT the browser's native find — the terminal content is a virtual scroll, native find would miss off-screen content)
  • Search highlights matches in bg-terminal-selection/20 with the current match in bg-terminal-selection/40
  • Enter / Shift+Enter navigate between matches
  • Esc closes the search bar

No agent selected (empty state)

+----------------------------------------------------------------------+
|                                                                      |
|                                                                      |
|                    [Terminal]                                        |
|               Select an agent                                        |
|              to view its output                                      |
|                                                                      |
|              (or press J/K to                                        |
|               navigate the list)                                     |
|                                                                      |
+----------------------------------------------------------------------+
  • [Terminal] icon: Terminal from Lucide, h-8 w-8 text-terminal-muted
  • Background: bg-terminal (dark surface even in light mode)
  • Text: text-terminal-muted

Keyboard Shortcuts

Key Action
J / Down Select next agent in list (when list is focused)
K / Up Select previous agent in list
/ Focus search input
Esc Clear search / close terminal search
Cmd+F Open terminal output search (when output viewer is focused)
End Scroll terminal to bottom, re-enable auto-follow

These shortcuts are only active when no text input is focused (except Cmd+F which is always available within the terminal panel).


Agent Lifecycle Visibility

Agents do NOT disappear from the list when they exit. The existing v1 filter tabs (All / Running / Questions / Exited / Dismissed) handle lifecycle:

Status Visible in "All" Visible in filter Styling
running Yes "Running" Normal card, pulsing blue dot
waiting_for_input Yes "Questions" Normal card, amber dot, "Answer questions ->" CTA
completed Yes "Exited" Slightly dimmed (opacity-80), green dot
stopped Yes "Exited" Slightly dimmed, grey dot
crashed Yes "Exited" Slightly dimmed, red dot, red left-border accent
idle Yes "Exited" Slightly dimmed, grey dot
Any + userDismissedAt No "Dismissed" Full opacity but separated from active view

"All" filter excludes dismissed agents (matching current implementation). Crashed agents get a subtle border-l-2 border-status-error-dot left accent on the card to draw attention without being overbearing.


Source

  • packages/web/src/routes/agents.tsx
  • packages/web/src/components/AgentOutputViewer.tsx
  • packages/web/src/components/AgentActions.tsx
  • packages/web/src/components/StatusDot.tsx
  • packages/web/src/lib/parse-agent-output.ts

Design Review Notes

Findings from a design review against the mission-control aesthetic and the existing implementation in agents.tsx / AgentOutputViewer.tsx.

1. Agent list width: 320px was too tight (FIXED)

Bumped to 360px. The original 320px was fine for name + status dot, but the v2 card now has 4-5 rows: status+name+menu, provider+mode badges, context row, time+cost. At 320px the [...] menu was colliding with the provider badge on shorter names. 360px gives breathing room without eating too much from the output viewer. The implementation already uses lg:grid-cols-[320px_1fr] — a single value change.

2. Output viewer was massively underspecified (FIXED)

The original wireframe showed 4 lines of > text and nothing else. For a screen where operators spend most of their time, that is unacceptable. Added:

  • Terminal header with agent name, status badge, session counter, cost, tokens
  • Terminal body with explicit styling rules referencing --terminal-* tokens from theme.md (the tokens existed but the wireframe never referenced them)
  • Terminal footer with follow indicator, inline search, scroll-to-bottom
  • Scroll behavior spec (auto-scroll, pause on scroll-up, 50px threshold) — the implementation already has this logic but the wireframe didn't document it
  • Session dividers — the implementation supports multi-session agents but the wireframe showed only "Session 1" with no visual separator

3. Agent actions were invisible in the wireframe (FIXED)

The [...] three-dot menu existed in the ASCII art but was never documented. The implementation (AgentActions.tsx) has a full dropdown with Stop/Dismiss/Delete and Go to Inbox. Added explicit documentation of the menu items and their visibility rules, including the Shift+click bypass pattern for Delete.

4. Status dots were too ambiguous (FIXED)

* ? - as ASCII symbols mapped to 3 states, but the codebase has 5 distinct agent statuses. The original spec collapsed completed, stopped, crashed, and idle into one grey -. That is wrong — a crashed agent demands attention, a completed agent is a success signal. Now:

  • running = pulsing blue dot (animation for scannability)
  • waiting_for_input = static amber dot
  • completed = static green dot (success signal)
  • crashed = static red dot (error signal)
  • stopped / idle = static grey dot

The existing StatusDot.tsx already distinguishes running (blue), crashed (red), stopped (grey). The wireframe was behind the implementation.

5. Missing cost/token indicators (FIXED)

For 10+ agents running in parallel, operators need to know which agents are burning through tokens and which are idle. Added $X.XX cost and Nk▼ token indicators to both the card (row 4) and the output viewer header. Data comes from session_end parsed messages which already include meta.cost.

The original spec said "clickable link to task/initiative" but didn't specify the navigation target. Now explicit: Task links go to /initiatives/$initiativeId?tab=execution, Initiative links go to /initiatives/$initiativeId. Also added e.stopPropagation() note so clicking the link doesn't simultaneously select the card.

7. Search only matched agent name (FIXED)

Searching for "PKCE" should find the agent working on the PKCE task. Extended search to also match task name and initiative name from the context row.

8. No keyboard navigation (FIXED)

Mission control = keyboard-first. Added J/K for list navigation, / for search focus, Cmd+F for terminal search, End for scroll-to-bottom. These match conventions from tools operators already know (vim, less, tmux).

9. Missing terminal search (FIXED)

When an agent has been running for 30 minutes and produced 2000 lines of output, you need to search it. Added Cmd+F inline search in the terminal footer with match highlighting using --terminal-selection token. Browser native find would fail because the terminal should eventually use virtualized scrolling for performance.

10. Agent lifecycle visibility was unspecified (FIXED)

The wireframe never addressed what happens to exited agents. The implementation has a 5-tab filter system (All/Running/Questions/Exited/Dismissed) that the wireframe completely ignored. Documented the full lifecycle table including styling differences (dimmed opacity for exited, red accent for crashed).

Still not addressed (future work)

These items were considered but intentionally deferred:

  • Split-view for comparing two agents' output: High complexity, low frequency. Most comparisons happen via task results, not raw output. If needed, operators can open two browser tabs. Revisit if user feedback demands it.
  • CPU/memory resource indicators: Requires a monitoring sidecar or proc polling that doesn't exist in the backend. Token count + cost is the more relevant resource metric for AI agents. System resource monitoring belongs in infrastructure tooling, not the orchestrator UI.
  • Agent timeline / Gantt view: Valuable for post-mortem analysis of parallel execution. Deferred to v3 as it requires a new visualization component and historical data aggregation that the current agent_log_chunks table doesn't efficiently support.