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)
42 KiB
Plan Tab (v2)
Route: /initiatives/$id (Plan tab)
Source: packages/web/src/components/ExecutionTab.tsx, packages/web/src/components/execution/
v1 -> v2 Changes
| Aspect | v1 | v2 |
|---|---|---|
| Save indicator | None on phase description editor | <SaveIndicator> component (same as Content tab) |
| Empty state (no agent) | Single "No phases yet" with both spinner and buttons shown contextually | Split: dedicated "No phases yet" empty state with action buttons |
| Empty state (agent running) | Spinner + "Planning phases..." inline with buttons | Dedicated "Planning in progress..." state, NO action buttons |
| Empty state (agent failed) | None -- user had no signal | Dedicated "Planning failed" state with error message + retry button |
| Pending review | Banner only on individual phase detail | Additional top-level banner when proposals exist initiative-wide |
| Sidebar width | 260px (inconsistent with Content tab's 192px) | 240px (matches Content tab v2 -- consistent divider line across tabs) |
| Phase reordering | None | Drag-and-drop via [≡] toggle in sidebar header |
| Task tree | Flat list | Nested tree showing parent-child decomposition + dependency indicators |
| Task inline editing | None | Click task name to inline-edit; own <SaveIndicator> per row |
| Keyboard shortcuts | None | N to add task (when task list focused), E to edit selected task |
| Bulk task operations | None | [...] menu on Tasks header with bulk actions |
Default State (phases exist, one selected)
+=============================================================================+
| Phases [Detailing] [≡] [+] | Phase: OAuth Implementation |
| --------------------------+ [✓] Saved |
| +------------------------+| ------------------------------------------------|
| | 1. Auth Setup || Description: |
| | [DONE] 3/3 tasks || Implement OAuth 2.0 authorization code flow |
| +------------------------+| with PKCE extension for public clients. |
| +------------------------+| |
| |*2. OAuth Flow *|| Support Google, GitHub, and Microsoft as |
| | [READY] 0 tasks || identity providers with configurable scopes. |
| | dep: 1 || |
| +------------------------+| Dependencies |
| +------------------------+| [+ Add dependency v] |
| | 3. UI Components || * Phase 1: Auth Setup [DONE] [x] |
| | [PENDING] 2/5 tasks || |
| | dep: 1, 2 || Tasks (2/5) [...] [N] [+ Add Task]|
| +------------------------+| ├── Set up OAuth routes * [DONE] |
| | ├── Implement PKCE flow * [RUNNING] |
| | │ └─ agent: blue-fox-7 |
| | │ └─ child: Validate scopes [PENDING] |
| | ├── Google provider [PENDING] [x] |
| | │ ← blocked by: Implement PKCE flow |
| | ├── GitHub provider [BLOCKED] [x] |
| | │ ← blocked by: Google provider |
| | └── Microsoft provider [PENDING] [x] |
| | |
| 240px | detail panel (flex-1) |
| | |
+=============================================================================+
- Phase sidebar: 240px,
border-right(see Design Review Notes on sidebar width rationale) - Selected phase: left blue border +
bg-accentbackground [+]in header triggershandleStartAdd(inline input at bottom of list)[≡]in header toggles drag-and-drop reorder mode (via@dnd-kit/sortable)[✓] Savedshows after phase description auto-save completes- Task
[x]delete buttons appear on hover; Shift+click bypasses confirm dialog - Task tree shows parent-child nesting via indented
└─ child:rows under parent tasks - Dependency arrows (
← blocked by: <task-name>) shown inline below blocked tasks [N]keyboard hint badge next to "Add Task" -- pressingNwhen task list is focused triggers inline task creation[...]on Tasks header row opens bulk actions menu (see Bulk Task Operations section)
Phase Sidebar Cards
+------------------------+
| 1. Auth Setup | Phase number + name (truncated)
| [DONE] 3/3 tasks | StatusBadge (small) + "complete/total tasks"
+------------------------+
+------------------------+
|*2. OAuth Flow *| * = selected (border-l-2 border-primary bg-accent)
| [READY] 0 tasks | "0 tasks" when no tasks decomposed yet
| dep: 1 | dependency indicator
+------------------------+
+------------------------+
| 3. UI Components |
| [PENDING] 2/5 tasks | progress fraction: completed/total
| dep: 1, 2 | multiple dependency shorthand
+------------------------+
- Sidebar cards always show task progress as
N/M tasks(not just total count) N/Musestext-muted-foreground; turnstext-status-success-fgwhen N === M (all done)- In reorder mode (
[≡]active), each card gets a drag handle icon on the left - Sidebar is
overflow-y-autowithscrollbar-thin(webkit custom scrollbar, 4px wide) - When > 8 phases, a subtle gradient fade at bottom edge signals scrollable content
- Selected phase auto-scrolls into view on selection change (
scrollIntoView({ block: 'nearest' }))
Phase Actions (sidebar header)
Phases [Detailing (2)] [≡] [+] [Detail All]
^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^
spinner + count drag sparkles icon
when detail handle disabled when no
agents active toggle eligible phases
[Detailing (N)]spinner badge shows when N detail agents are running[Detail All]spawns detail agents for all phases with 0 tasks[+]opens inline input for new phase name[≡]toggles reorder mode -- when active, cards become draggable,bg-mutedhighlight on sidebar
Save Indicator on Phase Description
Same <SaveIndicator> component as Content tab, positioned top-right of phase detail header.
Saving
Phase: OAuth Implementation [spinner] Saving...
Saved
Phase: OAuth Implementation [✓] Saved
Failed
Phase: OAuth Implementation [!] Failed [retry]
Task Inline Editing
Tasks support inline name editing. Click a task name to toggle into an input field with its own save state.
Viewing (default)
├── Set up OAuth routes * [DONE]
Editing (after click on name)
├── [Set up OAuth routes_______] [✓] * [DONE]
- Input field replaces the text span;
Enteror blur saves,Escapecancels [✓]micro-indicator shows save state (same<SaveIndicator>logic, icon-only, no text viacompactprop)Ekeyboard shortcut opens edit mode on the currently focused/selected task rowTabwhile editing moves to the next task row in edit mode (rapid-fire renaming workflow)- Changes call
trpc.updateTask.useMutation({ taskId, name })with 300ms debounce (not on-blur-only; type-and-go feel) - Only one task can be in edit mode at a time -- clicking another task's name exits the current edit (triggering save)
- Running tasks (
status === 'running') have their name input disabled withcursor-not-allowed-- you cannot rename a task while an agent is working on it
Task Tree Structure (parent-child + dependencies)
The plan tab is the primary place users understand task structure. The task tree communicates two relationships:
1. Parent-child decomposition (vertical nesting)
├── Implement PKCE flow * [RUNNING]
│ └─ agent: blue-fox-7
│ └─ child: Validate scopes [PENDING]
│ └─ child: Generate challenge [PENDING]
- Child tasks are indented one level under their parent (
parentTaskId) child:prefix intext-muted-foregrounddistinguishes decomposition from agent info- Children inherit phase context from parent; can be expanded/collapsed per parent
- Collapse state: parent rows show
[>]/[v]chevron. Default: expanded if < 4 children, collapsed if >= 4 - Max nesting depth: 3 levels (parent > child > grandchild). Schema supports deeper, but UI truncates with "N deeper tasks..." link that opens Task Detail Modal
- Child count badge on collapsed parents:
Implement PKCE flow [3 subtasks] [RUNNING]
2. Dependency blocking (inline annotation)
├── Google provider [PENDING] [x]
│ ← blocked by: Implement PKCE flow
├── GitHub provider [BLOCKED] [x]
│ ← blocked by: Google provider
←arrow +blocked by:label intext-muted-foreground text-xs- Blocked task name is a clickable link that scrolls to / highlights the blocking task (300ms
ring-2 ring-primarypulse) - Only shown when task has unresolved dependencies (hidden once dependency completes)
- Cross-phase dependencies: if the blocking task is in a different phase, show
← blocked by: <task-name> (Phase: <phase-name>)-- clicking switches to that phase in the sidebar - Circular dependency guard: if a task chain forms a cycle (should not happen, but can via manual edits), show
[!] Circular dependencywarning intext-status-error-fginstead of the blocked-by annotation
Visual hierarchy
Task name text-sm font-medium
agent: <name> text-xs text-muted-foreground font-mono
child: <name> text-sm (indented, normal weight)
← blocked by: text-xs text-muted-foreground italic
Bulk Task Operations
The [...] menu on the Tasks section header provides bulk operations for all tasks in the selected phase.
Tasks (2/5) [...] [N] [+ Add Task]
|
+------------------------+
| Select All Ctrl+A |
|------------------------|
| Delete All Tasks |
| Reset All to Pending |
| Re-categorize All > |
| > execute |
| > verify |
| > research |
|------------------------|
| Expand All Children |
| Collapse All Children |
+------------------------+
Select All-- toggles checkbox selection on all task rows (for future multi-select operations);Ctrl+Ashortcut when task list focusedDelete All Tasks-- Shift+click bypasses confirm; normal click showswindow.confirm()Reset All to Pending-- resets all non-running tasks in the phase back topendingstatus. Useful after a failed batch.Re-categorize All-- submenu with category options; updates all tasks in the phaseExpand All Children/Collapse All Children-- bulk toggle for parent-child tree visibility- Batch mutations:
trpc.deleteTasksByPhase,trpc.updateTaskCategory,trpc.resetTasksByPhase - Menu is a
<DropdownMenu>from shadcn/ui - Disabled when phase has 0 tasks
Empty State -- No Phases (no agent running)
+=============================================================================+
| Phases | |
| --------------------------+ |
| (empty) | +------------------------------------------+ |
| | | | |
| | | [layers icon] | |
| | | No phases yet | |
| | | | |
| | | Add a phase to start planning, | |
| | | or let an agent plan for you. | |
| | | | |
| | | [sparkles Plan with Agent] [+ Add Phase] |
| | | | |
| | +------------------------------------------+ |
| | |
+=============================================================================+
- Centered
EmptyStatecard in the detail panel area [layers icon]-- LucideLayersicon,text-muted-foreground, 48px- Two action buttons side by side:
[sparkles Plan with Agent]--variant="default"(primary/filled), callsplanSpawn.spawn()-- this is the recommended action[+ Add Phase]--variant="outline"(secondary/outline), callsonAddPhase()for inline input
- Visual hierarchy: "Plan with Agent" is indigo filled button (primary CTA), "Add Phase" is outline (secondary)
- Only shown when:
phasesLoaded && phases.length === 0 && !isPlanRunning && !planFailed
Empty State -- Planning in Progress (agent running)
+=============================================================================+
| Phases | |
| --------------------------+ |
| (empty) | +------------------------------------------+ |
| | | | |
| | | [spinner] | |
| | | Planning in progress... | |
| | | | |
| | | Agent is analyzing the initiative | |
| | | and creating phases. | |
| | | | |
| | +------------------------------------------+ |
| | |
+=============================================================================+
[spinner]--Loader2withanimate-spin, 32px,text-primary- "Planning in progress..." --
text-base font-medium - Subtext --
text-sm text-muted-foreground - NO action buttons -- prevents user from adding phases while agent works
- Shown when:
phasesLoaded && phases.length === 0 && isPlanRunning
Empty State -- Planning Failed (agent crashed)
+=============================================================================+
| Phases | |
| --------------------------+ |
| (empty) | +------------------------------------------+ |
| | | | |
| | | [AlertTriangle icon] | |
| | | Planning failed | |
| | | | |
| | | The planning agent crashed before | |
| | | creating any phases. | |
| | | | |
| | | [sparkles Retry Planning] [View Log] | |
| | | | |
| | +------------------------------------------+ |
| | |
+=============================================================================+
[AlertTriangle icon]-- LucideAlertTriangle, 48px,text-status-error-fg- "Planning failed" --
text-base font-medium text-status-error-fg - Subtext --
text-sm text-muted-foreground; shows truncated error reason if available from agent's last output (e.g., "API rate limit exceeded", "Account exhausted") - Two action buttons:
[sparkles Retry Planning]--variant="default"(primary), callsplanSpawn.spawn()again[View Log]--variant="outline", opensAgentOutputViewerfor the crashed agent
- Shown when:
phasesLoaded && phases.length === 0 && !isPlanRunning && planAgent?.status === 'crashed' - Detection: query the most recent plan-category agent for this initiative; check
status === 'crashed' - Edge case -- partial failure: if the agent created some phases before crashing, this empty state does NOT show (phases exist). Instead, show a dismissible
AlertBannerat the top of the detail panel: "Planning agent crashed after creating N phases. Some phases may be incomplete. [Retry] [Dismiss]"
Pending Review Banner (top-level)
+=============================================================================+
| +---------------------------------------------------------------------+ |
| | [sparkles] 5 proposals ready for review [Go to Review ->] | |
| +---------------------------------------------------------------------+ |
| Phases [+] | Phase: OAuth Implementation |
| --------------------------+ [✓] Saved |
| ... | ... |
+=============================================================================+
- Full-width banner above the sidebar+detail grid
[sparkles]-- LucideSparklesicon,text-amber-500- Shows proposal count: "N proposals ready for review" (not generic "Agent has proposals")
- Background:
bg-amber-50 dark:bg-amber-950/20 border border-amber-200 dark:border-amber-800 [Go to Review ->]-- text button that navigates to?tab=review- Shown when: proposals with
status === 'pending'exist for this initiative - Query:
trpc.listProposals.useQuery({ initiativeId, status: 'pending' }) - Count derived from
pendingProposals.data?.length
Phase Detail Header
+------------------------------------------------------------------------+
| Phase 2: OAuth Implementation [READY] [git] branch [...] |
| | | |
| branch badge v |
| +--------------------+
| | Detail with Agent |
| | Duplicate Phase |
| |--------------------|
| | Delete Phase |
| +--------------------+
+------------------------------------------------------------------------+
- Phase name is inline-editable (click to toggle input); same
<SaveIndicator compact>pattern as task names [...]dropdown:Detail with Agent-- spawns a detail agent for this phase (disabled if detail agent already running or phase has tasks)Duplicate Phase-- deep-copies phase + tasks with "(copy)" suffix; useful for templating similar phasesDelete Phase-- destructive, red text. Shift+click bypasses confirm. Normal click:window.confirm()
[git] branchbadge shows initiative branch when set; clicking copies branch name to clipboard (toast: "Copied to clipboard")
Detailing In Progress (per-phase)
+------------------------------------------------------------------------+
| Phase 2: OAuth Implementation [READY] [spinner] Detailing |
+------------------------------------------------------------------------+
- Shown in phase detail header when a detail agent is active for this phase
[spinner]--Loader2withanimate-spin
Empty State -- Phase Selected, No Tasks
+------------------------------------------------------------------------+
| Phase 2: OAuth Implementation [READY] [...] |
|------------------------------------------------------------------------|
| Description: |
| Implement OAuth 2.0 authorization code flow... |
| |
| Tasks (0) [+ Add Task] |
| +------------------------------------------------------------------+ |
| | | |
| | [ListTodo icon] | |
| | No tasks in this phase | |
| | | |
| | Add tasks manually, or let an agent | |
| | decompose this phase into tasks. | |
| | | |
| | [sparkles Detail with Agent] [+ Add Task] | |
| | | |
| +------------------------------------------------------------------+ |
+------------------------------------------------------------------------+
- Only appears inside the Tasks section of the detail panel (NOT a full-panel takeover like the no-phases empty state)
[sparkles Detail with Agent]--variant="default"(primary CTA), spawns a detail agent for this phase[+ Add Task]--variant="outline"(secondary), opens inline task input[ListTodo icon]-- LucideListTodo, 36px,text-muted-foreground- Distinct from the top-level "No phases yet" empty state -- this one is scoped to the Tasks area of an existing phase
Per-Phase Pending Review Banner
+------------------------------------------------------------------------+
| [!] 3 proposals pending review. Go to the Review tab to review. |
+------------------------------------------------------------------------+
- Shown below phase header when phase-specific proposals are pending
[!]--AlertCircleicon,text-amber-500- Shows count: "N proposals pending review" (not generic text)
- Distinct from top-level banner (this is phase-scoped)
Task Row Hover & Focus States
Default:
├── Google provider [PENDING]
Hover:
├── Google provider [PENDING] [play] [x]
^^^^^^^^^^^^^ ^^^^^ ^^^
bg-muted/50 row bg queue delete
cursor-pointer (on hover only)
Focused (keyboard nav):
├── Google provider [PENDING] [play] [x]
^^^^
ring-1 ring-primary/50 outline on row
Selected (Space toggle):
├── [✓] Google provider [PENDING] [play] [x]
^^^
checkbox visible when any task selected
- Hover reveals action buttons (
[play]to queue,[x]to delete) at the right edge of the row [play]button:variant="ghost" size="icon"-- LucidePlayicon, callstrpc.dispatchTask[x]button:variant="ghost" size="icon"-- LucideXicon,text-destructiveon hover- Running tasks replace
[play]with[square](stop button) and hide[x](cannot delete running task) - Focus ring uses
ring-1 ring-primary/50(subtle, not aggressive -- this is keyboard nav, not a call to action) - Hover and focus states stack: hovering a focused row shows both
bg-muted/50and focus ring
Task Detail Modal (overlay)
+----------------------------------------------------------+
| Set up OAuth routes [x] |
| |
| Status [PENDING] | Category execute |
| Phase 2. OAuth Flow | Priority normal |
| Agent (none) | Parent Task (none) |
| |
| Description |
| Create Express routes for /auth/login, /auth/callback, |
| and /auth/logout with proper middleware chain. |
| |
| Child Tasks |
| (none -- will be created during decomposition) |
| |
| Dependencies |
| * DB Schema Migration [DONE] |
| |
| Blocks |
| * GitHub provider adapter [BLOCKED] |
| |
| [ Queue Task ] [ Stop Task ] |
+----------------------------------------------------------+
- Opened by clicking any task row (or pressing
Enteron focused row) [x]close button top-right;Escapealso closes- Parent Task field shows the parent task name (clickable) if
parentTaskIdis set, otherwise "(none)" - Child Tasks section lists decomposed children if any exist; each child is clickable to open its own modal
- Dependencies section shows blocking tasks with status;
[+ Add]button to add a new dependency (dropdown of other tasks in same phase) - Blocks section shows downstream tasks that depend on this one (read-only, informational)
- Description is a multi-line
<textarea>with auto-resize; auto-saves with 500ms debounce +<SaveIndicator> [ Queue Task ]dispatches the task;[ Stop Task ]kills the running agent[ Queue Task ]is disabled with tooltip "Blocked by N tasks" when task has unresolved dependencies[ Delete Task ]--variant="ghost"text-destructive, bottom-left of modal. Shift+click bypasses confirm.- Shared component via
<TaskModal>inExecutionContext
Keyboard Shortcuts (Plan Tab)
| Key | Context | Action |
|---|---|---|
N |
Task list focused | Open inline "Add Task" input at bottom of list |
E |
Task row focused | Toggle inline name editing on focused task |
Tab |
Inline edit active | Save current edit, move to next task in edit mode |
Delete / Backspace |
Task row focused | Delete task (with confirm unless Shift held) |
Arrow Up / Arrow Down |
Task list | Navigate between task rows |
Arrow Right |
Collapsed parent focused | Expand children |
Arrow Left |
Expanded parent focused | Collapse children |
Arrow Left |
Child task focused | Jump focus to parent task |
Enter |
Task row focused | Open Task Detail Modal |
Space |
Task row focused | Toggle task selection (for future multi-select) |
Escape |
Inline edit active | Cancel edit, restore original value |
Ctrl+A |
Task list focused | Select all tasks |
? |
Plan tab focused, no input active | Show keyboard shortcut overlay |
- Shortcuts are scoped to the task list container (
onKeyDownhandler on the task list wrapper) - Only active when no other input/textarea is focused (check
document.activeElement.tagName) - Discoverable via tooltip on
[+ Add Task]button: "Add task (N)" ?shortcut opens a shadcn<Dialog>listing all shortcuts -- same pattern as GitHub's?key
Source
packages/web/src/components/ExecutionTab.tsx(Plan tab = ExecutionTab with sidebar+detail layout)packages/web/src/components/execution/PlanSection.tsxpackages/web/src/components/execution/PhaseSidebarItem.tsxpackages/web/src/components/execution/PhaseDetailPanel.tsxpackages/web/src/components/execution/PhaseActions.tsxpackages/web/src/components/execution/TaskModal.tsxpackages/web/src/components/execution/BulkTaskMenu.tsx(new)packages/web/src/components/execution/TaskTree.tsx(new -- replaces flat list)packages/web/src/components/execution/TaskRowInlineEdit.tsx(new -- extracted edit mode)packages/web/src/components/execution/PhaseEmptyTasks.tsx(new -- per-phase empty state)packages/web/src/components/execution/PlanTabSkeleton.tsx(new -- loading skeleton)packages/web/src/components/KeyboardShortcutOverlay.tsx(new --?key dialog, reusable)packages/web/src/components/TaskRow.tsxpackages/web/src/hooks/useAutoSave.ts
Design Review Notes
Critique and rationale for all v2 Plan Tab design decisions. Each item maps to a review criterion.
1. Sidebar Width: 240px (consistent across tabs)
Problem: Content tab v1 used 192px for the page tree. Plan tab v1 was 260px. The 68px discrepancy means the divider line jumps when switching tabs -- jarring in a tabbed layout sharing the same viewport.
Resolution: Both Content tab and Plan tab now use 240px. The divider line is stable across tab switches. Rationale:
- Phase cards carry status badges, task counts, and dependency indicators. 192px was too cramped.
- Content tab v2 independently moved to 240px to accommodate deep nesting + breadcrumb truncation.
- The convergence at 240px is incidental but correct -- both sidebars have similar information density now.
- 240px is the canonical sidebar width for all tabbed views within initiative detail. Any future tabs with sidebars should use 240px unless there is a strong reason to deviate.
2. Three-Way Empty State Split (no phases / planning / planning failed)
Problem: v1 had no way to tell the user "planning failed." The agent could crash silently, leaving the user staring at a "No phases yet" screen with no signal.
Resolution: Added a third empty state -- "Planning failed" with AlertTriangle icon, error message, [Retry Planning] primary button, and [View Log] outline button. Detection: query the most recent plan-category agent for this initiative, check status === 'crashed'.
The three states form a clean state machine:
!isPlanRunning && !planFailed && phases.length === 0-> "No phases yet" (with action buttons)isPlanRunning && phases.length === 0-> "Planning in progress..." (no action buttons)!isPlanRunning && planFailed && phases.length === 0-> "Planning failed" (retry + log buttons)
Partial failure edge case: If the agent crashes after creating some phases, the empty states do not apply (phases exist). Instead, a dismissible AlertBanner appears at the top of the detail panel: "Planning agent crashed after creating N phases. [Retry] [Dismiss]". This is critical -- without it, partial failures are invisible.
Error context: The failed empty state now shows a truncated error reason extracted from the agent's last output (e.g., "API rate limit exceeded"). This saves the user from having to click "View Log" just to understand why it failed.
3. Task Tree: Parent-Child + Dependency Visualization
Problem: The v1 flat task list gave no signal about task structure. Users managing 10+ agents need to understand the DAG at a glance -- which tasks decompose into subtasks, which tasks block other tasks.
Resolution: The task tree now communicates two distinct relationships:
- Parent-child decomposition: Indented rows under parent tasks (uses
parentTaskIdfrom the schema). Collapsible per parent. Thechild:prefix distinguishes these from agent assignment lines. - Dependency blocking:
← blocked by: <task-name>annotations below blocked tasks. The blocking task name is a clickable link that scrolls to and highlights the blocking task. - Cross-phase dependencies: When a blocking task lives in a different phase, the annotation includes the phase name and clicking it switches the sidebar selection.
- Collapse behavior: Parents with >= 4 children default to collapsed, showing a child count badge. This prevents the tree from becoming unwieldy in heavily-decomposed phases.
What this is NOT: This is not a full DAG graph. The Plan tab shows a tree (hierarchical nesting + inline annotations), not a topological graph with SVG arrows. That is the Execution tab's job. The Plan tab's job is editing the structure, not visualizing execution order. The inline ← blocked by: annotations are sufficient for understanding dependency relationships during planning; the full pipeline visualization belongs to the Execution tab.
Known limitation: The tree representation cannot fully express a DAG with convergent dependencies (task C depends on both A and B, which are not parent-child related). The inline annotations handle this for display, but visually it is not as clear as a graph. This is an acceptable tradeoff -- the Plan tab prioritizes editability over visualization fidelity.
4. Button Hierarchy: "Plan with Agent" (primary) vs "Add Phase" (outline)
Problem: Both buttons were visually ambiguous about which action is recommended.
Resolution: Explicit variant assignment:
Plan with Agent--variant="default"(indigo filled, primary CTA). This is the happy path. New users should click this first.Add Phase--variant="outline"(secondary). This is for power users who want manual control.
The sparkles icon on "Plan with Agent" already signals "AI-powered," and making it the filled button reinforces it as the recommended action. The outline variant for "Add Phase" correctly communicates "alternative path."
5. Review Banner: Proposal Count
Problem: "Agent has proposals ready for review" is vague. Is it 1 proposal or 50? The user can't gauge urgency without switching tabs.
Resolution: Show the count: "5 proposals ready for review." Both the top-level banner and the per-phase banner now include counts. The count comes from pendingProposals.data?.length which is already fetched by the query.
6. Phase Reordering (drag-and-drop)
Problem: No way to reorder phases after creation. If the user adds phases manually or the agent creates them in the wrong order, there's no recourse.
Resolution: Added [≡] toggle button in the sidebar header. When active:
- Phase cards become draggable (via
@dnd-kit/sortable) - Sidebar gets a subtle
bg-mutedhighlight to indicate mode change - Drag handles appear on each card
- Drop triggers
trpc.updatePhaseSortOrdermutation - Toggle off returns to normal selection behavior
The toggle approach (vs. always-draggable) is intentional: drag-and-drop interferes with click-to-select in a sidebar this narrow. You don't want accidental drags when you're trying to navigate.
7. Phase Status Summary in Sidebar Cards
Problem: Sidebar cards showed task count but not progress. "5 tasks" tells you nothing about completion state.
Resolution: Changed to N/M tasks format (e.g., "2/5 tasks", "3/3 tasks"). When all tasks are complete (N === M), the text switches from text-muted-foreground to text-status-success-fg for a visual "done" signal without adding another badge.
8. Bulk Task Operations
Problem: No way to operate on all tasks in a phase at once. If the agent decomposes a phase poorly, the user has to delete tasks one by one.
Resolution: [...] dropdown menu on the Tasks section header, expanded to include:
- "Select All" (Ctrl+A) -- enables checkbox mode for future multi-select operations
- "Delete All Tasks" -- nukes all tasks in the phase.
window.confirm()unless Shift held. - "Reset All to Pending" -- resets all non-running tasks back to pending. Essential after a batch failure where some tasks are stuck in error states.
- "Re-categorize All" -- submenu to change the category of all tasks in the phase.
- "Expand All Children" / "Collapse All Children" -- tree visibility toggles for heavily decomposed phases.
The Select All + checkbox mode lays groundwork for future multi-select operations (bulk delete selected, bulk re-categorize selected) without building the full multi-select UI now.
9. Task Inline Editing + Save State
Problem: The <SaveIndicator> existed for phase descriptions but not for task names. If users can edit task names inline, they need feedback that the edit persisted.
Resolution: Each task row gets its own micro save indicator (icon-only <SaveIndicator> -- checkmark or spinner, no text label). The indicator appears inline next to the task name input during editing and disappears after save completes. This uses the same <SaveIndicator> component with a compact prop that renders icon-only.
10. Keyboard Shortcut for Add Task (and friends)
Problem: In a keyboard-first mission control UI, requiring a mouse click to add a task is a friction point. Power users managing dozens of tasks want to stay on the keyboard.
Resolution: Full keyboard shortcut table added (see "Keyboard Shortcuts" section). Key decisions:
Nfor new task (mnemonic: New). Scoped to task list focus.Efor edit (mnemonic: Edit). Opens inline editing on the focused row.Tabduring inline edit advances to the next task in edit mode (rapid-fire renaming).Delete/Backspacefor delete. With confirm unless Shift held (consistent with mouse Shift+click pattern).Arrow Up/Downfor row navigation.Arrow Left/Rightfor tree expand/collapse (borrowed from VS Code tree behavior).Spacetoggles task selection (multi-select mode).Ctrl+Aselects all.Enterto open modal.?opens a shortcut overlay dialog (GitHub-style discoverability).- All shortcuts are scoped to the task list container and disabled when an input is focused.
- The
[N]badge hint next to "Add Task" button makes the primary shortcut discoverable. The?overlay covers the rest.
11. Missing: Per-Phase Empty State (phase exists, no tasks)
Problem caught in review: The spec documented empty states for "no phases" and "planning in progress/failed," but NOT for the case where a phase exists with zero tasks. The user selects a phase, sees the description, and then... a blank Tasks section with just the "Add Task" button. No guidance.
Resolution: Added "Empty State -- Phase Selected, No Tasks" section. The Tasks area (not full panel) shows a small inline empty state with two CTAs: "Detail with Agent" (primary, spawns decomposition) and "Add Task" (outline, manual). This mirrors the plan-level empty state pattern: AI-first is primary, manual is secondary.
12. Missing: Task Row Hover & Focus States
Problem caught in review: The spec defined keyboard shortcuts and inline editing but never documented what happens on mouse hover or keyboard focus. In a dense list UI, hover states are not cosmetic -- they communicate interactivity and reveal action affordances.
Resolution: Added "Task Row Hover & Focus States" section. Key decisions:
- Hover reveals
[play](queue) and[x](delete) action buttons at row's right edge. Hidden by default to keep the list clean. - Running tasks swap
[play]for[square](stop) and hide[x](cannot delete running tasks). - Keyboard focus uses a subtle
ring-1 ring-primary/50outline (notring-2-- that's too aggressive for navigation). - Hover and focus states stack visually (both can be active on the same row).
13. Missing: Phase Detail Header Actions
Problem caught in review: The original phase header dropdown only had "Delete Phase." That is one action in a dropdown -- just use a button. A dropdown implies a menu with multiple options.
Resolution: Expanded the [...] dropdown to three actions:
- "Detail with Agent" -- spawns task decomposition for the selected phase
- "Duplicate Phase" -- deep-copies phase + tasks, appends "(copy)" suffix. Useful for templating similar phases (e.g., duplicating "Google OAuth" to create "GitHub OAuth" with the same task structure).
- "Delete Phase" -- destructive, red text, bottom of menu with separator above.
Now the dropdown earns its existence.
14. Concern: Task Description Editing in Modal Only
The current spec puts task description editing exclusively in the Task Detail Modal. For quick edits, opening a modal is friction. Consider adding expandable inline description editing (click to expand a 2-line textarea below the task row) in a future iteration. Not adding it now because the tree is already vertically dense and expandable descriptions would make it harder to scan. But log this as a known future improvement.
15. Concern: No Loading / Skeleton States Documented
The spec documents empty states comprehensively but says nothing about what the user sees while phases are loading. On a slow connection or large initiative, there is a flash of empty state before data arrives. The plan tab should show:
- Sidebar: 3 skeleton cards (pulsing
bg-muted animate-pulse, matching card dimensions) - Detail panel: skeleton lines for title + description + task list
This prevents the "No phases yet" empty state from flashing before the actual phases load, which would be confusing.
16. Implementation Note: Component Boundary Map
New or modified components for v2 Plan Tab:
| Component | Path (proposed) | New? |
|---|---|---|
PhaseSidebarItem |
packages/web/src/components/execution/PhaseSidebarItem.tsx |
Modified -- add task progress, dep indicator, drag handle |
PhaseActions |
packages/web/src/components/execution/PhaseActions.tsx |
Modified -- add [≡] toggle, [Detail All], detailing badge |
TaskTree |
packages/web/src/components/execution/TaskTree.tsx |
New -- replaces flat task list with nested tree |
TaskRow |
packages/web/src/components/TaskRow.tsx |
Modified -- add inline edit, hover actions, focus state, child indent |
TaskRowInlineEdit |
packages/web/src/components/execution/TaskRowInlineEdit.tsx |
New -- extracted edit mode for TaskRow |
BulkTaskMenu |
packages/web/src/components/execution/BulkTaskMenu.tsx |
New |
PhaseEmptyTasks |
packages/web/src/components/execution/PhaseEmptyTasks.tsx |
New -- per-phase "no tasks" empty state |
PlanTabSkeleton |
packages/web/src/components/execution/PlanTabSkeleton.tsx |
New -- loading skeleton |
KeyboardShortcutOverlay |
packages/web/src/components/KeyboardShortcutOverlay.tsx |
New -- ? key dialog, reusable across tabs |