Files
Codewalkers/docs/wireframes/v2/app-layout.md
Lukas May 0ff65b0b02 feat: Rename application from "Codewalk District" to "Codewalkers"
Update all user-facing strings (HTML title, manifest, header logo,
browser title updater), code comments, and documentation references.
Folder name retained as-is.
2026-03-05 12:05:08 +01:00

21 KiB

App Layout (v2)

Route: * (all pages)

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


v1 -> v2 Changes

Aspect v1 v2
Header height 56px + nav row Single 48px row
Nav layout Wordmark on row 1, tabs on row 2 Logo + tabs + utilities all on one row
Badges None Live agent count on Agents, unresolved count on Inbox
Theme toggle None 3-state Sun/Monitor/Moon
Command palette None Cmd+K trigger in header
Health indicator None Status dot (green/yellow/red)

Default State

+=============================================================================+
| [CW]  Initiatives  Agents [*3]  Inbox [2]  Settings  [⌘K]  [sun]  * myws |
+=============================================================================+
|                                                                             |
|                                                                             |
|                     full-width padded content (px-4 sm:px-6 lg:px-8)       |
|                                                                             |
|                              <Page Outlet>                                  |
|                                                                             |
|                                                                             |
|                                                                             |
|                                                                             |
|                                                                             |
+=============================================================================+

Note: max-w-* constraints are set per-page, not globally. Pages like Agents and Initiative Detail use full-width layouts. The Initiatives list and Settings may opt into max-w-6xl or similar. The root layout applies only horizontal padding.

Active Tab Highlighted

+=============================================================================+
| [CW]  [*Initiatives*]  Agents [*3]  Inbox [2]  Settings  [⌘K]  [sun]  * myws |
+=============================================================================+
|                                                                             |
|                              <Page Outlet>                                  |
|                                                                             |
+=============================================================================+

Active tab gets bg-muted rounded-md treatment. Text is font-medium (not bold — font-medium is 500 weight, sufficient contrast without the heaviness of font-bold at these small sizes).

Zero Badges (no running agents, no pending conversations)

+=============================================================================+
| [CW]  Initiatives  Agents  Inbox  Settings             [⌘K]  [sun]  * myws |
+=============================================================================+
|                                                                             |
|                              <Page Outlet>                                  |
|                                                                             |
+=============================================================================+

Badges are completely hidden when count is 0 — no empty brackets or *0.

Health Dot States

  *   ← green: WebSocket connected, last heartbeat < 5s ago
  ?   ← yellow: connected but heartbeat > 5s (slow/degraded)
  -   ← red: WebSocket disconnected or server unreachable

The dot uses status-success-dot, status-warning-dot, or status-error-dot tokens from the theme. The green state gets a subtle animate-pulse removed after 3s of stable connection to avoid distraction.

Tooltip on hover

Rich tooltip (not just title attr) with structured content:

+-------------------------------+
|  ● Connected                  |
|  Latency: 42ms                |
|  Uptime: 2h 14m               |
|  Last heartbeat: <1s ago      |
+-------------------------------+

+-------------------------------+
|  ◐ Degraded                   |
|  Latency: 2,340ms             |
|  Last heartbeat: 8s ago       |
|  Server may be under load     |
+-------------------------------+

+-------------------------------+
|  ○ Disconnected               |
|  Lost connection 12s ago      |
|  Retrying... (attempt 3)      |
+-------------------------------+
  • Uses shadcn <Tooltip> with <TooltipContent side="bottom" align="end">
  • Tooltip content is text-xs font-mono for data readability
  • Status label uses matching status token color

Connection Banner

When the WebSocket disconnects, a full-width banner slides down between the header and page content. This is more aggressive than the dot alone — the dot is for glanceable status, the banner is for "you need to know this NOW."

Reconnecting

+=============================================================================+
| [CW]  Initiatives  Agents [*3]  Inbox [2]  Settings  [⌘K]  [sun]  - myws |
+=============================================================================+
| [spinner] Reconnecting to server...                              [Dismiss] |
+=============================================================================+
|                                                                             |
|                              <Page Outlet>                                  |
+=============================================================================+
  • bg-status-warning-bg border-b border-status-warning-border
  • Text: text-status-warning-fg text-sm
  • Spinner: 14px animated, same as SaveIndicator
  • Dismiss hides the banner but the health dot stays red/yellow

Offline (> 30s disconnected)

+=============================================================================+
| [CW]  Initiatives  Agents [*3]  Inbox [2]  Settings  [⌘K]  [sun]  - myws |
+=============================================================================+
| [!] Server unreachable — data may be stale             [Retry] [Dismiss]   |
+=============================================================================+
|                                                                             |
|                              <Page Outlet>                                  |
+=============================================================================+
  • bg-status-error-bg border-b border-status-error-border
  • Text: text-status-error-fg text-sm
  • Retry button: text-status-error-fg underline font-medium

Reconnected (success, auto-dismisses)

+=============================================================================+
| [CW]  Initiatives  Agents [*3]  Inbox [2]  Settings  [⌘K]  [sun]  * myws |
+=============================================================================+
| [v] Reconnected                                                            |
+=============================================================================+
  • bg-status-success-bg text-status-success-fg text-sm
  • Auto-dismisses after 3s with fade-out

Timing

Duration disconnected Behavior
0-3s No banner (brief blips are silent, dot goes yellow)
3-30s "Reconnecting..." banner
>30s "Server unreachable" banner with Retry
On reconnect "Reconnected" for 3s, then dismiss

Notification Indicators

Important events must surface even when the user is on a different tab. Three mechanisms work together:

1. Tab badges (already specified above)

Agents [*3] and Inbox [2] update in real-time via tRPC subscriptions.

2. Toast notifications (sonner)

Critical events fire a toast regardless of current page:

Event Toast Duration
Agent crashed "blue-fox-7 crashed" + link to Agents Persistent (manual dismiss)
Task needs approval "Task ready for approval" + link Persistent
All tasks complete "Initiative complete — ready for review" 8s auto-dismiss
Account exhausted "Account X exhausted, switched to Y" 5s auto-dismiss
Agent asking question "blue-fox-7 has a question" + link to Inbox 8s auto-dismiss

Persistent toasts stack in bottom-right. Max 3 visible; older ones collapse into a "+N more" indicator.

3. Browser tab title

When the app is backgrounded and events occur:

  • (2) Codewalkers — number prefix for unread attention items
  • Counts: crashed agents + pending approvals + unanswered inbox items
  • Resets to Codewalkers when user returns to the tab

Collapsed Mobile View (not yet implemented)

+=============================================================================+
| [CW]                                    [⌘K]  [sun]  *   [☰ 2]           |
+=============================================================================+
|                                                                             |
|                              <Page Outlet>                                  |
|                                                                             |
+=============================================================================+

Note: Mobile hamburger menu is not implemented. This is a placeholder for future work. At < 768px, nav tabs collapse into a hamburger [☰] dropdown. The hamburger icon shows a combined badge count (crashed agents + unread inbox) so that attention items are never hidden behind the collapsed menu.

404 Page

+=============================================================================+
| [CW]  Initiatives  Agents  Inbox  Settings             [⌘K]  [sun]  * myws |
+=============================================================================+
|                                                                             |
|                                                                             |
|                          [AlertCircle]                                      |
|                         Page not found                                      |
|                                                                             |
|                      [ Back to Initiatives ]                                |
|                                                                             |
|                                                                             |
+=============================================================================+

48px Header Anatomy

48px is tight. This works because:

  • Logo is icon-only (24px, no wordmark)
  • Nav tabs use px-3 py-1.5 (compact hit targets, 36px tall inside 48px)
  • Badges are inline pills, not separate elements
  • Right cluster items are icon-sized (no text labels except ⌘K)

If this still feels cramped at certain content widths, the Cmd+K button drops its text label at < 1024px (see Responsive Notes below).

+-----------------------------------------------------------------------------+
|  LEFT CLUSTER                    SPACER             RIGHT CLUSTER           |
|  [CW] [Nav] [Nav [N]] [Nav [N]] [Nav]  -------  [⌘K] [◐] [●] [workspace] |
+-----------------------------------------------------------------------------+
     ↑                                                  ↑    ↑    ↑       ↑
   24px icon                                       Cmd+K  Theme Health  Workspace

Left cluster (nav)

  • [CW] — 24x24 logo icon, links to /initiatives
  • Nav tabs: Initiatives, Agents, Inbox, Settings
  • Each tab is an <a> with gap-1.5 between label and optional badge
  • Active tab: bg-muted text-foreground font-medium rounded-md px-3 py-1.5
  • Inactive tab: text-muted-foreground hover:text-foreground px-3 py-1.5
  • Keyboard: 1 / 2 / 3 / 4 navigate to tabs (when no input is focused)

Badge rendering — unified <NavBadge> component

Both tabs use the same badge component for visual consistency:

// Unified pill badge: inline, compact, color-coded
<span className="ml-1 inline-flex items-center rounded-full px-1.5 py-0.5
                 text-[10px] font-medium leading-none tabular-nums
                 {colorClasses}">
  {count}
</span>
Tab Badge color Example Semantics
Agents bg-status-active-bg text-status-active-fg (blue) Agents [3] Running agent count
Inbox bg-status-warning-bg text-status-warning-fg (amber) Inbox [2] Unresolved conversation count

Both badges:

  • Hidden entirely when count is 0
  • Use tabular-nums so width doesn't shift when count changes (e.g., 9 -> 10)
  • Pill shape: rounded-full with tight px-1.5 py-0.5
  • Font: text-[10px] — small enough to not compete with the tab label

Attention escalation: When an agent has crashed or a task needs approval, the Agents badge switches to bg-status-error-bg text-status-error-fg (red) to draw the eye. The count reflects crashed + running agents in this state.

Right cluster (utilities)

  • [⌘K] — Shows platform-aware shortcut hint as label: ⌘K on Mac, Ctrl+K on Windows/Linux. Rendered as a <kbd> style pill: bg-muted text-muted-foreground text-xs font-mono px-2 py-1 rounded-md border border-border. Clicking opens the CommandPalette overlay (see shared-components.md).
  • [◐] — ThemeToggle, 3-state segmented control (see shared-components.md)
  • [●] — Health status dot, 8px circle with color (see Health Dot States above)
  • [workspace] — Workspace name, derived from .cwrc or directory basename. text-xs text-muted-foreground font-mono truncate max-w-[120px]. Tooltip shows full path on hover: /Users/me/projects/my-app. Hidden at < 1024px to save space.

Workspace identity

The workspace label solves a real problem: developers often run multiple Codewalk instances for different projects. Without it, you can't tell which instance you're looking at without checking the terminal.

  Right cluster detail:
  [⌘K]  [sun|monitor|moon]  ●  codewalk-district
                                ^^^^^^^^^^^^^^^^^^
                                text-xs font-mono text-muted-foreground
                                truncated at 120px, full path in tooltip

Spacing

  • Left cluster: gap-1 between items
  • Between clusters: flex-1 spacer pushes them apart
  • Right cluster: gap-2 between items (tightened from gap-3 — the workspace label needs room)

Responsive Notes

Breakpoint Header Content
>= 1280px Full header as shown, workspace label visible Page decides own max-w-*
1024px - 1279px Workspace label hidden, ⌘K shows icon-only [search] Page decides own max-w-*
768px - 1023px Same as above, tab labels may truncate Horizontal padding reduces
< 768px Nav tabs collapse into hamburger (future) Single-column, px-4

Content area uses px-4 sm:px-6 lg:px-8 horizontal padding only. There is no global max-w-7xl. Each page sets its own max-width constraint (or uses none for full-bleed layouts like the Agents split-pane view).

Per-page width strategy

Page Width constraint Rationale
Initiatives list max-w-6xl mx-auto Card grid, doesn't benefit from extreme width
Initiative detail Full width Tab content (execution, agents) needs room
Agents Full width Split-pane: agent list + output viewer
Inbox Full width Split-pane: conversation list + detail
Settings max-w-4xl mx-auto Forms, narrow content

Global Components (rendered in root layout)

  • <Toaster> (sonner) — bottom-right toast notifications, max 3 visible
  • <ErrorBoundary> — wraps the page outlet
  • <CommandPalette> — overlay, triggered by Cmd+K or header button
  • <ConnectionBanner> — slides between header and content on disconnect
  • <BrowserTitleUpdater> — invisible, manages document.title with unread counts

Keyboard Shortcuts (global)

These are registered at the root layout level, suppressed when an input/textarea is focused:

Shortcut Action
⌘K / Ctrl+K Open command palette
1 Navigate to Initiatives
2 Navigate to Agents
3 Navigate to Inbox
4 Navigate to Settings
? Show keyboard shortcut help overlay (future)

Source

  • packages/web/src/routes/__root.tsx
  • packages/web/src/layouts/AppLayout.tsx
  • packages/web/src/components/ThemeToggle.tsx (proposed)
  • packages/web/src/components/CommandPalette.tsx (proposed)
  • packages/web/src/components/HealthDot.tsx (proposed)
  • packages/web/src/components/ConnectionBanner.tsx (proposed)
  • packages/web/src/components/NavBadge.tsx (proposed)
  • packages/web/src/hooks/useWorkspaceName.ts (proposed)
  • packages/web/src/hooks/useBrowserTitle.ts (proposed)

Design Review Notes

Reviewed against MISSION CONTROL criteria (dense, status-at-a-glance, keyboard-first, dark-mode-first). Changes applied inline above.

1. 48px header — is it cramped?

48px is fine IF the content is disciplined: icon-only logo, no wordmark, compact tab padding, and small inline badges. Added an explicit note to the Header Anatomy section explaining why 48px works and where the escape hatch is (responsive breakpoints drop ⌘K text and workspace label). The real risk is not height but horizontal crowding when all badges are showing and the workspace name is long. The truncate max-w-[120px] on the workspace label and responsive hiding address this.

2. Badge inconsistency (*N vs (N))

This was a real problem. The v1 spec used *N for Agents and (N) for Inbox, two completely different visual languages for the same concept (a count badge on a nav tab). Unified both into a <NavBadge> component — a colored pill with just the number. Color differentiates meaning (blue=active, amber=pending), not punctuation. Added tabular-nums to prevent layout shift on count changes.

3. Health dot — too subtle?

The dot alone was easy to miss, yes. But the right fix is NOT making the dot bigger — it is adding a second tier of communication. The dot stays as a glanceable ambient indicator (like a server rack LED). The new ConnectionBanner handles the "you need to stop and pay attention" case. Added a rich tooltip with latency, uptime, and heartbeat data for the "I want details" case. Three tiers: dot (ambient) -> tooltip (on-demand) -> banner (urgent).

4. Connection banner — missing

Added full spec: Reconnecting (3-30s), Offline (>30s), Reconnected (success). The 3s delay before showing the banner prevents flicker on brief WebSocket reconnections. The banner is dismissible but the dot stays colored. See "Connection Banner" section above.

5. Workspace identity — missing

Added workspace name to the right cluster. Derived from .cwrc config or directory basename. This is essential for multi-instance users. Hidden below 1024px because it is useful but not critical — the browser tab title or terminal provides fallback identification.

6. Cmd+K shortcut hint

Changed from [cmd-k] text to a <kbd>-styled [⌘K] pill showing the actual platform shortcut. This doubles as both a clickable trigger and a discoverability hint. Users see the shortcut every time they glance at the header, which builds muscle memory. On Windows/Linux it renders as Ctrl+K.

7. Notification system — missing

This was the biggest gap. Added three tiers:

  • Tab badges: real-time counts (already existed, now specified with attention escalation)
  • Toast notifications: critical events fire toasts regardless of current page. Persistent for crashes/approvals, auto-dismiss for informational events.
  • Browser tab title: (2) Codewalkers prefix when backgrounded with unread attention items. Standard web app pattern.

The attention escalation on the Agents badge (blue -> red when something crashes) is important — it means you do not need to be on the Agents page to know something went wrong.

8. max-w-7xl constraint — wrong default

Removed. A mission control tool should default to full-width and let pages opt into narrower layouts. The split-pane views (Agents, Inbox) and the Initiative Detail tabs lose significant usable space under max-w-7xl (1280px). Replaced with per-page width strategy: forms/lists get max-w-4xl/max-w-6xl, operational views get full width. The root layout only applies horizontal padding.

Open questions for next review

  • Favicon badge: Should the browser favicon show a red dot for attention items, like Slack does? More noticeable than title prefix alone.
  • Sound: Should critical events (agent crash) play a subtle notification sound? Power users managing 10+ agents may not be watching the screen.
  • Keyboard shortcut overlay: ? to show all shortcuts is specced as "future" — should it be in v2 scope given the keyboard-first stance?