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)
22 KiB
Initiative Detail (v2)
Route: /initiatives/$id
Source: packages/web/src/routes/initiatives/$id.tsx
v1 -> v2 Changes
| Aspect | v1 | v2 |
|---|---|---|
| Header layout | Single row: back + name + all badges | Two rows: Row 1 = back + name + actions menu, Row 2 = badges |
| Initiative name | Static text | Editable on hover (pencil icon -> inline input) |
| Actions menu | Only on cards in list view ([...]) |
[...] menu on Row 1: Discuss, Plan, Refine, Change Mode, Archive, Delete |
| Tab badges | None | Content (5), Plan (3), Execution 3/7, Review (2) with yellow tint |
| Keyboard hints | None | Tooltip on tab hover + CommandPalette entries + first-visit hint |
| Activity feed | None | Collapsible ticker at bottom of tab content area |
| Tab transition | None specified | Explicitly instant (no animation) |
| Tab internal headers | Inconsistent | Consistent left=context, right=action pattern documented |
| Not found state | Same as generic error | Distinct 404 message: "Initiative not found" |
| Branch editing | Inline edit on click | Unchanged (still inline) |
| Project editing | Popover checklist | Unchanged (still popover) |
Default State
+=============================================================================+
| [CW] [*Initiatives*] Agents *3 Inbox (2) Settings [cmd-k] [sun] * |
+=============================================================================+
| |
| [<] Auth System Overhaul [...] |
| [ACTIVE] [REVIEW] [git] cw/auth-overhaul [P] backend, frontend |
| |
| Content (5) Plan (3) Execution 3/7 Review (2) |
| ----------------------------------------------------------------------- |
| |
| |
| < tab content area > |
| |
| |
| |
+=============================================================================+
Two-Row Header Anatomy
Row 1: [<] Initiative Name [pencil-on-hover] [...]
Row 2: [STATUS] [MODE] [git] branch [P] project1, project2
Row 1
[<]— Back chevron, navigates to/initiatives- Initiative name —
text-2xl font-bold. Not inline-editable by default. On hover, a pencil icon (Pencil, 14px,text-muted-foreground) appears to the right of the name. Clicking it replaces the<h1>with an<Input>(sametext-2xl font-boldstyling). Enter saves, Escape cancels. UsesupdateInitiativemutation. This keeps the title line clean 99% of the time while making rename discoverable. [...]— Actions menu, right-aligned on Row 1 (see Initiative Actions Menu below)- Row 1 has no badges — clean title line + actions menu
Row 2
- Indented to align under the initiative name (not under the back chevron)
[STATUS]— StatusBadge:[ACTIVE]green,[DONE]grey,[ARCHIVED]dim[MODE]— ExecutionMode:[YOLO]amber (clickable toggle),[REVIEW]blue (clickable toggle)[git] cw/<branch>— GitBranch icon + branch name. Hidden if no branch yet.[P] project1, project2— Folder icon + project names. Hidden if none linked.
No Branch Yet
[<] Mobile App Redesign
[ACTIVE] [REVIEW] [P] frontend
Branch badge simply absent. No placeholder or "add branch" button — branch is auto-generated on first execution task dispatch.
No Projects Yet
[<] Scratch Initiative
[ACTIVE] [YOLO] [git] cw/scratch [+ Add projects]
[+ Add projects] link opens project picker popover.
Name Editing (click pencil on hover)
[<] [Auth System Overhaul___________________] [v] [x] [...]
[ACTIVE] [REVIEW] [git] cw/auth-overhaul [P] backend, frontend
Inline text input replaces the <h1>. Same text-2xl font-bold sizing.
[v] saves via updateInitiative({ id, name }), [x] cancels.
Enter also saves, Escape also cancels.
Branch Editing (click branch badge)
[<] Auth System Overhaul
[ACTIVE] [REVIEW] [git] [cw/auth-overhaul______] [v] [x] [P] backend
Inline text input replaces branch badge. [v] saves, [x] cancels.
Project Editing (click pencil icon on project badges)
[<] Auth System Overhaul
[ACTIVE] [REVIEW] [git] cw/auth-overhaul
+----------------------------------+
| [x] backend github.com/... |
| [ ] frontend github.com/... |
| [ ] shared github.com/... |
| + Register new project |
+----------------------------------+
[ Save ] [ Cancel ]
Tab Bar
Content (5) Plan (3) Execution 3/7 Review (2)
-----------------------------------------------------------------------
^^^^^^^^^^^^^^^^^^
active tab (border-b-2 border-primary)
Tab badge rendering
All non-progress badges use a consistent (N) format. Execution is
the exception because it communicates a ratio (done/total), not a count.
| Tab | Badge | Format | When |
|---|---|---|---|
| Content | (5) |
Page count | Hidden if 0 pages (only root page exists and is empty) |
| Plan | (3) |
Phase count | Hidden if 0 phases |
| Execution | 3/7 |
Completed/total tasks (fraction) | Hidden if 0 total tasks |
| Review | (2) |
Pending proposal count, yellow tint | Hidden if 0 pending |
Why the fraction for Execution? It is a progress indicator, not a simple
count. 3/7 tells you "3 done out of 7" at a glance — a count (7) would
not convey progress. The other tabs show cardinality, not progress, so (N)
is the right format for them.
Active tab indicator
border-b-2 border-primaryunderline on active tabfont-medium text-foregroundfor active tab texttext-muted-foregroundfor inactive tab text
Tab with zero badges
Content Plan Execution Review
-----------------------------------------------------------------------
When all counts are zero, all badges are hidden. No (0) or 0/0.
Each badge appears independently as its count becomes non-zero.
Hover state with keyboard hint (tooltip)
Content Plan Execution 3/7 Review (2)
-----------------------------------------------------------------------
^
+-------------+
| 3 Execution |
+-------------+
Tooltip shows the keyboard shortcut number + tab name.
Pressing 1/2/3/4 switches tabs when no input is focused.
Keyboard shortcuts:
1— Content2— Plan3— Execution4— Review
Keyboard shortcut discoverability
Tooltips are hover-only — users who never hover will never find them. Two additional discoverability mechanisms:
-
CommandPalette integration: When the user opens Cmd+K and types "content", "plan", "execution", or "review", results include entries like
Go to Content tab [1]with the shortcut shown as a right-aligned<kbd>badge. These appear in a "Navigation" group. -
First-visit hint (one-time): On the first render of the initiative detail page (tracked via
localStoragekeycw-tab-hints-shown), a subtle muted-foreground line below the tab bar reads:Tip: press 1-4 to switch tabs. Auto-dismisses after 5s or on any tab switch. Never shown again.
Initiative Actions Menu
Row 1's [...] button opens a <DropdownMenu> anchored to the right.
This mirrors the [...] menu on initiative cards in the list view but
adds initiative-level actions relevant in the detail context.
[...]
+------------------+
| Discuss |
| Plan |
| Refine |
| ────────────── |
| Change Mode | → submenu: YOLO / Review
| ────────────── |
| Archive |
| Delete | ← destructive, red text
+------------------+
Actions
| Action | Behavior |
|---|---|
| Discuss | Spawns a discuss agent for this initiative |
| Plan | Spawns a plan agent to generate phases |
| Refine | Spawns a refine agent on content pages |
| Change Mode | Submenu: YOLO / Review. Calls updateInitiativeConfig. Active mode has a checkmark. |
| Archive | Sets status to archived. window.confirm() dialog; Shift+click bypasses. |
| Delete | Calls deleteInitiative. window.confirm("Delete permanently?"); Shift+click bypasses. Navigates to /initiatives on success. |
The "Change Mode" action duplicates the [MODE] badge toggle in Row 2.
That is intentional — the badge is for quick toggle, the menu is for
discoverability and for users who do not realize the badge is clickable.
Activity Feed
A collapsible activity ticker at the bottom of the tab content area, showing the most recent cross-cutting events for this initiative. Think "mission control status bar" — always visible, never overwhelming.
Collapsed (default)
-----------------------------------------------------------------------
[^] blue-fox-7 completed "Implement PKCE flow" . 2m ago [View All]
Single-line ticker showing the most recent event. [^] expands the feed.
[View All] opens a full activity log (future page, not in v2 scope — link
is a no-op stub that shows a toast "Activity log coming soon").
Expanded (click [^])
-----------------------------------------------------------------------
[v] Activity [View All]
-----------------------------------------------------------------------
. 2m ago blue-fox-7 completed "Implement PKCE flow" [EXECUTION]
. 5m ago Proposal submitted: "Add rate limiting" [REVIEW]
. 8m ago green-fox-3 started "Google provider" [EXECUTION]
. 12m ago Phase "OAuth Flow" marked ready [PLAN]
. 15m ago Page "Architecture" updated [CONTENT]
-----------------------------------------------------------------------
- Max 10 items visible, scrollable if more
- Each item has: relative timestamp, description, tab context badge
- Tab context badge links to the relevant tab (clicking
[EXECUTION]switches to Execution tab) [v]collapses back to single line- Feed populated from EventBus events filtered by
initiativeId - Persists expanded/collapsed state in
localStoragekeycw-activity-feed-${initiativeId}
Event Types Shown
| Event | Display |
|---|---|
task:completed |
{agent} completed "{task}" |
task:failed |
{agent} failed on "{task}" — error tint |
task:dispatched |
"{task}" dispatched to {agent} |
agent:spawned |
{agent} started "{task}" |
agent:completed |
{agent} finished |
agent:crashed |
{agent} crashed — error tint |
proposal:created |
Proposal submitted: "{title}" |
proposal:accepted |
Proposal accepted: "{title}" |
phase:status_changed |
Phase "{phase}" marked {status} |
page:updated |
Page "{page}" updated |
Tab Transition Behavior
Tab switches are instant with no transition animation. Rationale:
- Mission control aesthetic prizes immediacy over polish
- Content in each tab can be tall and complex — crossfade or slide animations on heterogeneous heights look janky
- The
border-b-2 border-primaryunderline provides sufficient visual feedback for which tab is active - Keyboard shortcut
1-4switching should feel instantaneous
The only animation is the tab underline itself, which uses
transition-colors duration-150 (already specified in active tab styling).
No opacity, transform, or height transitions on tab content.
Tab Content Internal Header Pattern
Each tab has its own internal header area, but they should follow a consistent layout to avoid visual jarring when switching tabs.
Tab Name / Context [Primary Action]
-----------------------------------------------------------------------
< tab-specific content >
Per-tab headers
| Tab | Left side | Right side |
|---|---|---|
| Content | Pages [+] (sidebar header) |
[breadcrumb] [SaveIndicator] (editor header) |
| Plan | Phases [+] (sidebar header) |
[SaveIndicator] (phase editor) |
| Execution | Execution (section title) |
[Queue All Pending] |
| Review | Diff: <filepath> N unresolved |
Threads [v] (sidebar header) |
The pattern is: left = context/navigation, right = primary action. Tab-specific wireframes (content-tab.md, plan-tab.md, etc.) define the full detail. This section documents the cross-tab consistency expectation.
Not Found State (404)
When getInitiative returns a NOT_FOUND error (initiative was deleted
or ID is bogus), show a distinct 404-flavored error instead of the
generic error state.
+=============================================================================+
| |
| [<] |
| |
| [AlertCircle] |
| Initiative not found |
| This initiative may have been deleted. |
| |
| [ Back to Initiatives ] |
| |
+=============================================================================+
Detection: check if error.message includes "not found" (already done
in existing code). The heading changes from "Error loading initiative"
to "Initiative not found" and the description changes accordingly.
Loading State
+=============================================================================+
| |
| [<] ░░░░░░░░░░░░░░░░░░░░░ |
| ░░░░░░░ ░░░░░░░ ░░░░░░░░░░░░░░░ ░░░░░░░░░░░░ |
| |
| ░░░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░░░ |
| ----------------------------------------------------------------------- |
| +-------------------------------------------------------------------+ |
| | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | |
| | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | |
| | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ | |
| +-------------------------------------------------------------------+ |
| |
+=============================================================================+
Skeleton matches two-row header + tab bar + content area.
Error State
+=============================================================================+
| |
| [<] |
| |
| [AlertCircle] |
| Error loading initiative |
| Could not fetch initiative data. |
| |
| [ Back to Initiatives ] |
| |
+=============================================================================+
Back chevron still functional. Error body uses <ErrorState> component
(see shared-components.md) but with navigation button instead of retry.
Source
packages/web/src/routes/initiatives/$id.tsxpackages/web/src/components/InitiativeHeader.tsxpackages/web/src/components/InitiativeTabBar.tsx(proposed)packages/web/src/components/InitiativeActionsMenu.tsx(proposed)packages/web/src/components/ActivityFeed.tsx(proposed)
Design Review Notes
Findings from a design review of this wireframe against the mission control aesthetic, implementation reality, and cross-wireframe consistency.
1. Inline-editable initiative name (ADDED)
The original spec showed the name as static text-2xl font-bold with no
edit affordance. This is a problem: the only way to rename an initiative was
via updateInitiative in the tRPC layer with no UI surface. Added a
hover-to-reveal pencil icon pattern. The pencil only appears on hover so
the title line stays clean. This matches the pattern used for branch editing
(click to activate inline input, Enter/Escape to save/cancel).
Decision: Not always-editable (clicking directly on text). That would create accidental edit activations and conflicts with text selection. The pencil-on-hover is the right middle ground.
2. Tab badge consistency (FIXED)
Original spec had Execution 3/7 (fraction, no parens) and Review (2)
(count in parens). Content and Plan had no badges at all. This was
inconsistent in two ways: mixed formats, and missing information.
Fix: All count badges use (N) format. Execution keeps the fraction
format 3/7 because it communicates progress, not cardinality. Content
and Plan now show (N) for page count and phase count respectively.
Rationale documented inline.
3. Keyboard shortcut discoverability (ADDED)
The original spec relied entirely on tooltip-on-hover for 1-4 shortcuts.
Tooltips are invisible to keyboard-only users and to anyone who does not
happen to hover over a tab. Two mechanisms added:
- CommandPalette results surface tab shortcuts with
<kbd>badges - One-time first-visit hint below the tab bar
The first-visit hint is the more impactful one. It teaches the pattern once without being permanently noisy.
4. Initiative actions menu (ADDED)
This was a genuine gap. The list view had [...] menus with Discuss, Plan,
Archive, Delete. The detail view had none of these. A user navigating into
an initiative had no way to archive, delete, or spawn agents without going
back to the list.
The [...] menu is right-aligned on Row 1. It duplicates the mode toggle
intentionally (badge = fast toggle, menu = discoverable).
Concern raised and resolved: "Change Mode" in the menu is redundant
with the clickable [MODE] badge. Kept both because badge clickability
is not obvious (it looks like a status indicator, not a button).
5. Activity feed (ADDED)
The original spec had no cross-tab awareness. If you were on the Content tab, you had zero visibility into agent completions, task failures, or proposal submissions happening on other tabs. For a mission control tool managing 10+ agents, this is a critical gap.
The activity feed is a collapsible ticker at the bottom. Collapsed by default (single line) so it does not steal vertical space. Each event includes a tab context badge that doubles as a navigation shortcut.
Scope note: The [View All] link is a stub in v2. A full activity
log page is deferred. The ticker covers the 80% case.
6. Tab transition (DOCUMENTED)
Original spec was silent on this. Explicitly documented as instant (no animation) with rationale. This is a deliberate choice, not an oversight to be "fixed later" with a fade-in.
7. Tab content internal header pattern (DOCUMENTED)
Each tab wireframe defines its own layout, but there was no cross-tab
consistency expectation documented. Added a section specifying the
left=context, right=action pattern that all four tabs already follow
in practice. This is documentation of an emergent pattern, not a new
requirement.
8. Not Found vs generic Error state (SPLIT)
The original spec had one Error State wireframe for all errors. But the
existing code already differentiates "not found" from other errors (line 70
of $id.tsx). Added a distinct Not Found wireframe with a more specific
message. This is already partially implemented; the wireframe now matches.
9. Minor fix: Source path corrected
The header listed $initiativeId.tsx but the actual file is $id.tsx.
Fixed.
Open questions for implementation
-
Activity feed event source: The feed needs a tRPC subscription or SSE stream filtered by
initiativeId. The existinguseLiveUpdateshook invalidates queries but does not expose raw events. A newonInitiativeActivitysubscription may be needed. -
Tab badge data loading: Content
(N)requires alistPagescount, Plan(N)requires alistPhasescount. These queries already run on their respective tabs but would need to be hoisted to the tab bar level (or the tab bar reads from the query cache). Ensure no waterfall. -
Activity feed performance: Storing events in memory (not DB) is fine for the ticker (last 50 events). But if
[View All]eventually becomes a real page, a persistent activity log table will be needed.