Files
waggle-os/docs/ux-refactor/gap-cards/S03-command-center.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

14 KiB
Raw Permalink Blame History

Gap Card — S03 · Command Center (Ctrl+K)

Execution model is the LOCKED in-place incremental refactor of apps/web + targeted backend extensions. Mockup (Waggle_OS_Handoff_Assets/screen_03_win_k_command_center.png) is DIRECTIONAL only; PRD §12.3 acceptance criteria win. Every claim below is grounded in a real file.


1. Screen & purpose

The universal command layer — opens from anywhere with Ctrl+K / Cmd+K — for search, launch, create, run, navigate, and extend across every major object type. PRD §12.3 (lines 449-482), blueprint screen 3 (_blueprint_extracted.txt:284-290, 633, 679). It is the product's "primary interaction" per blueprint line 19 ("Primary interaction: Ctrl+K") and the IA spine item #3 (PRD line 19). Goal: "No user needs to know where a feature lives to use it" (PRD line 482).

The mockup shows a centered modal titled "What do you want to do?" with: a search input ("Search anything…"), pill tabs (Show my tasks / Open … STM Strategy / Find market analysis / Summarize…), five category columns — Launch · Create · Run · Navigate plus a Search bucket — each listing object/action rows, a "Suggested for you" card strip (review reports, draft proposals), and a footer "Type a natural-language command…". A second "Open in new window" affordance is top-right.


2. Required states (PRD/Blueprint)

PRD §12.3 functional requirements (lines 461-467):

  • Opens from anywhere via Ctrl+K / Cmd+K.
  • Searches across workspaces, memory, artifacts, sessions, people, agents, skills, commands, connectors, MCPs.
  • Category sections: Search, Launch, Create, Run, Navigate, Extend.
  • Supports natural-language command input.
  • Displays recent and suggested actions.
  • Permission-gated actions show an approval prompt before execution.
  • Reachable by both mouse and keyboard.

PRD §12.3 states (lines 469-477) + blueprint (:289-290): Idle · Query active · Grouped results · No results · Permission prompt · Command success · Command failure.

Acceptance (lines 479-482): every major object and action is reachable; no user needs to know where a feature lives.


3. Current state in repo

Disposition: rework (keep the proven overlay shell + keyboard nav + adapter calls; restructure categories to Search/Launch/Create/Run/Navigate/Extend; add execute + permission-prompt + recent/suggested; back it with the net-new /api/command/* provider).

  • apps/web/src/components/os/overlays/GlobalSearch.tsx (362 lines) — the existing Ctrl+K/Cmd+K overlay. Today it does client-side federated search only across 5 categories (SearchCategory = 'command' | 'workspace' | 'memory' | 'session' | 'skill', line 15):
    • command = a hardcoded static COMMANDS array of 23 app ids (lines 40-64) that must be hand-kept in sync with appConfig in Desktop.tsx (the file's own comment flags this drift as "the cause of FR #13", lines 33-39).
    • workspace/session/skill pre-fetched on open via adapter.getWorkspaces(), adapter.getSessions(ws.id) (first 5 ws × 3 sessions, lines 98-127), adapter.getSkills() (lines 129-138).
    • memory = debounced (300 ms, min 2 chars) server call adapter.searchMemory(query, globalScope?'global') (lines 142-168) — the only server-backed category.
    • Matching is client-side fuzzyMatch (lib/fuzzy-match, line 11/177-187); keyboard nav (↑/↓/Enter/Esc), selection clamp, scroll-into-view all already work (lines 224-239).
    • There is no execute path — every Enter calls onNavigate(category, id) (lines 231-235, 320), i.e. it only opens a window. No Create/Run/Extend, no recent, no suggested, no permission prompt.
  • Desktop.tsx wiring<GlobalSearch open onClose onNavigate={handleSearchNavigate} /> (:464), toggled by ov.toggleGlobalSearch (Ctrl/Cmd+K via useKeyboardShortcuts, :207) and the StatusBar search button (:424). handleSearchNavigate (Desktop.tsx:217-225) handles only commandwm.openApp, workspaceselectWorkspace+openChatForWorkspace, memoryopenApp('memory'). No session/skill navigation, no execute.
  • apps/web/src/components/os/overlays/KeyboardShortcutsHelp.tsx (92 lines) — static cheat-sheet modal (shortcuts array, lines 9-32). Lists "⌘K → Global Search" (line 21). Disposition keep — it is the separate Cmd+? help overlay, not the command center; only update its label if Ctrl+K is rebranded "Command Center".
  • adapter.executeCommand(command, workspaceId) (lib/adapter.ts:1345-1350) → POST /api/commands/execute (note plural commands). Runs slash commands only (/catchup, /status, /memory, /skills); workflow/spawn commands return "not available" (packages/server/src/local/routes/commands.ts:1-87). Exists but is not the generic palette execute.
  • adapter.searchSessions (adapter.ts:424-427), adapter.searchMemory (:476-487) exist and are reusable as federation inputs. lib/suggested-actions.ts is chat-message-scoped (extracts follow-up chips from the last assistant message) — NOT command-palette suggestions; do not reuse for §12.3 "suggested".

4. Frontend work

Rework GlobalSearch.tsxCommandCenter.tsx (rename or keep filename; founder-directional). Reuse 100% of the modal chrome, framer-motion animation, debounce, keyboard-nav, selection/scroll logic.

Concrete changes:

  • Expand SearchCategory to the PRD §12.3 verbs: add 'create', 'run', 'navigate', 'extend' alongside 'search' (today's command/workspace/memory/session/skill become Search/Navigate result feeds). Category headers + ordering (CATEGORY_LABELS/CATEGORY_ORDER, lines 67-75) extend accordingly — this matches the mockup's Launch/Create/Run/Navigate columns.
  • Replace client federation with a server provider. Swap the multi-call client logic (lines 91-168) for a single debounced adapter.commandSearch(q, { scope })GET /api/command/search?q= (net-new adapter method on lib/adapter.ts, the one contract surface). Keep the existing per-category calls only as offline/fallback. Eliminates the hardcoded COMMANDS-vs-appConfig drift (FR #13).
  • Add an execute path. New onExecute(commandId|nlInput)adapter.commandExecute()POST /api/command/execute. On Enter for a Run/Create/Extend item (vs Navigate items which keep calling onNavigate). Render the §12.3 permission prompt state inline before executing gated actions (reuse the approvals pattern — useChat().pendingApproval/approveAction and ApprovalRequest type, lib/types.ts), plus command success / command failure toasts (hooks/use-toast).
  • Recent + Suggested. On idle (empty query), render two strips matching the mockup: "Recent" from adapter.commandRecent()GET /api/command/recent, and "Suggested for you" from adapter.commandSuggestions()GET /api/command/suggestions.
  • Natural-language input (PRD line 464): when the query doesn't match a structured result, surface a "Run as command: ''" row that posts the raw string to execute.
  • New adapter methods (4): commandSearch, commandExecute, commandRecent, commandSuggestions.
  • State: keep local query/selected/sections; add recent, suggested, pendingPermission, executing states. Props: extend GlobalSearchProps (line 27) with onExecute and a workspace-id for execute scoping. New optional hook useCommandCenter() (wraps the 4 adapter calls + debounce) is the clean home for the provider, mirroring the existing domain-hook pattern.

5. Backend work (PRD §16.3)

All four are MISSING from the sidecar (grep-confirmed in backend-routes.md:448-451; /api/command/* = 0 matches in packages/server/src/local/routes/*.ts). None needs a new data store — all federate over existing substrate, consistent with the in-place model.

PRD §16.3 endpoint Status Plan
GET /api/command/search?q= MISSING NET-NEW route file packages/server/src/local/routes/command.ts. Federates over existing reads: workspaces (WorkspaceManager.list()), memory (MindDB full-text, reuse memory.ts search), sessions (reuse sessions.ts /sessions/search), skills (skills.ts), connectors (connectors.ts), MCPs (from capabilities/status mcpServers[] + @waggle/shared mcp-catalog.ts), agents/personas (personas.ts+agent-groups.ts), and the app/command catalog (extract from a shared catalog to kill the COMMANDS drift). Substrate touched: read-only across memory_frames, sessions JSONL, install-audit/marketplace, workspace configs. No .mind migration.
POST /api/command/execute PARTIAL EXTEND, do not duplicate. POST /api/commands/execute (plural, commands.ts) already runs slash commands with a real CommandContext. Either (a) add a singular /api/command/execute alias that broadens the context to also dispatch Navigate/Create/Run/Extend intents (open app, create object, fleet-spawn, install), or (b) widen the existing plural route. Reuses commandRegistry.execute, fleet/spawn, marketplace/install. Substrate: same as the underlying action; add an install-audit write for gated executes (InstallAuditStore.record, core/install-audit.ts). No migration.
GET /api/command/recent MISSING NET-NEW (or derive client-side). Cheapest server path: record executed commands to ai_interactions / a small recents list and read back; or derive from session/event history (events.ts). Substrate: ai_interactions table (read) — no schema change required.
GET /api/command/suggestions MISSING NET-NEW. Reuse the workspace-state next-actions seed: deriveNextActions in packages/server/src/local/workspace-state.ts:182-218 + buildWorkspaceNowBlock (workspace-context.ts) give cross-workspace suggestion candidates; skills.ts /skills/suggestions is the skill-domain analog to fold in. Substrate: read-only over memory/awareness/cron. No migration.

Permission gating: the execute route should run gated actions through the existing approval/SecurityGate path so the FE permission-prompt state has a real backend (reuse approval.ts + marketplace SecurityGate).


6. Shared types needed (PRD §15 vs lib/types.ts)

PRD §15 defines no dedicated Command type, but the palette needs a result/command union. Add to apps/web/src/lib/types.ts (and mirror server-side in the route):

  • CommandResult { id; kind: 'search'|'launch'|'create'|'run'|'navigate'|'extend'; objectType: 'workspace'|'memory'|'artifact'|'session'|'person'|'agent'|'skill'|'connector'|'mcp'|'command'|'app'; title; subtitle?; icon?; score; requiresApproval?: boolean; payload? } — supersedes the local SearchResult interface (GlobalSearch.tsx:17-25).
  • CommandExecuteRequest/CommandExecuteResult (success/failure + optional permission descriptor).
  • Reuse existing ApprovalRequest (lib/types.ts) for the permission-prompt state rather than inventing a new one.
  • The objectType union overlaps PRD §15.2's missing unions (ArtifactKind, AgentType) and the absent Artifact entity (substrate-types §e) — Artifact/Agent results are blocked until those screens land (see §7).

7. Dependencies (screens/phases first)

  • PRD Sprint 3 = Command Center (PRD lines 1321-1326: indexed search provider, result groups, command execution, recent/suggested) — this card IS Sprint 3. Depends on Sprint 1 (Shell + Ctrl+K, blueprint :582) being the home of the command provider.
  • Search breadth is gated by other screens' substrate. "artifacts" and "agents/people" facets need: Artifacts (S05, PRD §16.6 — entirely net-new, substrate-types §e: no Artifact entity exists) and Agents (S09, PRD §16.7 — sidecar agent CRUD MISSING). Ship Command Center with the available facets (workspaces/memory/sessions/skills/commands/connectors/MCPs) and add artifact/agent facets when those screens land. Do not block the whole screen on them.
  • Execute's Create/Run/Extend intents lean on existing fleet-spawn / marketplace-install / cron — already present.

8. Effort

L. The FE overlay is largely reusable (shell, keyboard nav, debounce all done — that caps it below XL), but the work spans: 4 net-new/extended backend routes federating across ~8 substrates, an execute + permission-prompt path with audit writes, recent/suggested providers, a shared CommandResult type, and killing the COMMANDS/appConfig drift — full-stack across multiple existing route files.


9. Open questions

  1. Route naming: add singular /api/command/* (PRD-literal) as the new surface, or rename the existing plural /api/commands/execute? Plural is already referenced by adapter.executeCommand + commands.ts. Recommend: new singular command.ts + alias execute to the existing registry to avoid a breaking rename.
  2. "Open in new window" affordance in the mockup (top-right) — is the Command Center expected to also open as a persistent windowed app (an AppId), or is it modal-only? Affects whether it needs an appConfig/dock entry vs staying an overlay.
  3. Suggested/recent scope: cross-workspace blended, or scoped to the active workspace? PRD says "recent and suggested" without scope; deriveNextActions is per-workspace today.
  4. Natural-language commands (PRD line 464): heuristic intent-parse (cheap, deterministic) vs an LLM round-trip? The existing commands.ts is registry-keyed; NL needs an intent resolver — confirm budget.
  5. Permission prompt reuse: is the chat approvals pipeline (approval.ts + useChat.pendingApproval) the intended mechanism for palette-initiated gated actions, or a lighter inline confirm?
  6. The COMMANDS-vs-appConfig drift (FR #13) — confirm the shared app-catalog refactor is in-scope here vs a separate cleanup (it is the right place to consolidate AppId and retire stale AppView).