# Gap Card — S02 · Workspace Desktop > Screen S02 of the Waggle OS UX-refactor. PRD §12.2 (lines 412-447). Execution model: **in-place > incremental refactor** of `apps/web` + targeted sidecar extensions. Mockup > (`screen_02_workspace_desktop.png`) is **directional**; PRD acceptance criteria win. > Every claim grounded in repo source (paths cited). --- ## 1. Screen & purpose **Purpose (PRD §12.2):** the primary runtime for a single bounded work context. It demotes chat from "the whole product" to **one widget among many**, surfacing workspace state, artifacts, memory, tasks, research, and activity on a single screen, with chat/agent interaction co-resident. **Mockup reading** (`Waggle_OS_Handoff_Assets/screen_02_workspace_desktop.png`): a full-screen (non-floating) layout for "Germany GTM Strategy" with: - **Left nav rail** — Workspaces / Memory / Agents / Automations / Files / MCP Hub / Connectors + favourites + user tile. - **Header** — workspace name + status pill ("Active"), team avatar stack, Share button, global search. - **Tab bar** — Overview · Chat · Research · Artifacts · Memory · Tasks · Timeline. - **Main canvas (Overview tab)** — multi-widget grid: AI workspace/chat preview, Key Artifacts list, Tasks list, Memory highlights, Research overview (donut), Recent activity feed. - **Right panel** — Workspace info, Members, Last activity, quick actions. - (Implied) **status bar** — agents running / automations active / MCPs connected. > The blueprint text page for "Screen 2 — Workspace Desktop" (`_blueprint_extracted.txt:675`) is an > image-only placeholder; the only textual spec is PRD §12.2 + the §0/§9/§19 spine references > (`_blueprint_extracted.txt:15,42,63,274,513,585`). --- ## 2. Required states (PRD/Blueprint) **Functional requirements (PRD §12.2, lines 423-430):** - Header: workspace name, **type**, **status**, team/avatar stack, share controls. - Tabs: Overview, Chat, Research/Notes, Artifacts, Memory, Tasks, Timeline, Settings. - Main canvas widgets: AI workspace/chat, key artifacts, tasks, memory highlights, research overview, recent activity. - Right panel: workspace info, members, last activity, quick actions. - Bottom/status bar: agents running, automations active, MCPs connected. - Fixed default layout initial release; configurable widgets deferred to a later phase. **States (PRD §12.2, lines 432-441):** No memory · Active work · Agent running · Artifact ready · Task blocked · Sync conflict · Permission denied · Offline. **Acceptance criteria (PRD §12.2, lines 443-447):** - Chat is one widget, not the whole product. - Workspace state is always visible. - User can reach memory, artifacts, agents, skills, tasks, automations, and settings from the workspace. **Cross-cutting (Blueprint §state-rules):** server-derived state — "Home Cockpit and Workspace Desktop must use server workspace-state/context APIs" (`_blueprint_extracted.txt:513`); cache invalidation on memory import / artifact update / agent-run completion / connector sync / automation completion / RBAC change (`:514`). --- ## 3. Current state in repo **Disposition: `create-new` (the tabbed Workspace Desktop screen does not exist), reusing existing substrate heavily.** There is **no** workspace-runtime surface today. The closest analog is a chat-only floating window: - **`apps/web/src/components/os/Desktop.tsx`** — root OS shell. `renderAppContent()` is a `switch(win.appId)` (`:276-360`); a workspace "opens" only as `case 'chat'` → `` (`:278-296`). There is **no `case 'workspace'`** and no tabbed runtime. Apps are floating windows (`AppWindow` chrome), not a full-screen workspace surface. `appConfig` (`:77`) has no workspace entry. - **`apps/web/src/components/os/apps/ChatWindowInstance.tsx`** — per-window wrapper: owns model fetch + per-window persona/autonomy, renders only `` (`:221-248`). Chat **is** the whole window — the exact inversion PRD §12.2 forbids. - **`apps/web/src/components/os/WorkspaceBriefing.tsx`** — ChatApp "home screen" shown when a session has no messages. Fetches `GET /api/workspaces/:id/context` via `adapter.getWorkspaceContext()` (`:57`) and renders greeting / stats / pending tasks / recent decisions / "I Remember" memories / recent threads / cross-workspace hints / suggested prompts / upcoming schedules. **This is the single best reuse seed** — it already consumes the "Workspace Now" block the Overview tab needs, but it lives *inside* chat and is read-only (no artifacts, no tasks CRUD, no tabs, no right panel). - **`apps/web/src/components/os/apps/DashboardApp.tsx`** — Workspaces grid (select/create/open-chat). This is the workspace **list** (S01-adjacent), not the per-workspace runtime. - **`apps/web/src/components/os/apps/RoomApp.tsx`** — live sub-agent tiles via `useRoomState` SSE (`:24`); the "agents running" status indicator can be derived from this per-workspace. - **`apps/web/src/components/os/overlays/ContextRail.tsx`** — right-side rail for a clicked frame/entity (`ContextRailTarget`); a **reuse target for the right-panel detail pattern**, but it is an overlay keyed to a single frame, not a persistent workspace info/members/activity panel. **Tabs that already have a host component** (to embed, not rebuild): Memory → `MemoryApp.tsx`, Timeline → `TimelineApp.tsx`, Chat → `ChatWindowInstance`/`ChatApp`, Settings → `SettingsApp.tsx`. **Tabs with NO host:** Overview (new), Research/Notes (new), Artifacts (no backing entity at all — see §5), Tasks (store exists server-side, never wired to FE — see §4/§5). **Adapter gap (confirmed by grep on `apps/web/src/lib/adapter.ts`):** `getWorkspaceContext` (`:272`), `getWorkspaceFiles` (`:277`), `getPins`/`addPin` (`:1353/:1361`), `getDocuments` (`:1371`) exist; **no `getTasks` / `getWorkspaceState` / `getWorkspaceActivity` methods** (0 matches). So the Tasks list, the `/state` Overview source, and the activity feed have no client plumbing yet. --- ## 4. Frontend work ### Components to create | Component | Role | Reuse / source | |---|---|---| | `apps/WorkspaceApp.tsx` (new) | Full-screen workspace runtime shell: header (name/type/status/avatars/Share) + `Tabs` + right panel + status bar. Owns `activeTab` state. | `components/ui/tabs.tsx`; header layout from `StatusBar.tsx` + `chat-header-layout.ts`; tab gating via `useFeatureGate`. | | `workspace/OverviewTab.tsx` (new) | Default tab: widget grid (chat preview, key artifacts, tasks, memory highlights, research, recent activity). | **Port the read-only sections of `WorkspaceBriefing.tsx`** (greeting/decisions/memories/threads) into widget cards; add artifacts/tasks/activity widgets. | | `workspace/WorkspaceInfoPanel.tsx` (new) | Right panel: info, members, last activity, quick actions. | Members from `adapter.getTeamMembers()`; "last activity" from new activity hook; quick actions raise `waggle:open-app`. ContextRail stays a separate frame-detail overlay. | | `workspace/TasksTab.tsx` (new) | Task list/board for the workspace. | Net-new FE; backs onto existing `/api/workspaces/:id/tasks` (server store exists, FE plumbing missing). | | `workspace/ResearchTab.tsx` (new) | Research/Notes surface. | Lightweight: notes-as-frames (memory) + wiki pages (`adapter.getWikiPages`). Lowest-fidelity tab; can ship as "notes" v1. | | `workspace/ArtifactsTab.tsx` (new) | Artifacts grid (see S05 dependency). | Backs onto new `/api/artifacts` (net-new) or interim file-registry view via `getWorkspaceFiles`/`getDocuments`. | ### Components to rework / wire - **`Desktop.tsx`** — add `case 'workspace'` to `renderAppContent` + an `appConfig.workspace` entry; route `openChatForWorkspace` callers that should open the *desktop* (not a chat window) to a new `openWorkspace(workspaceId)`. Decide window-vs-fullscreen (recommend full-bleed window using existing maximize path in `AppWindow.tsx` to avoid a parallel layout system). **Surgical** — do not refactor the window manager. - **`useWindowManager.ts`** — add `workspace` to the `AppId` consumption; reuse `workspaceId` field already on `WindowState`. No new state shape. - **Embed existing apps as tab panels** — Memory/Timeline/Chat/Settings render their existing components scoped by `workspaceId` (already accepted props on `TimelineApp`, `ChatWindowInstance`). ### Adapter methods / hooks to add (`lib/adapter.ts` — the one contract surface) - `getWorkspaceState(id)` → `GET /api/workspaces/:id/state` (Overview; PARTIAL backend, §5). - `getWorkspaceActivity(id, {limit})` → `GET /api/workspaces/:id/activity` (activity feed; PARTIAL, §5). - `getTasks(workspaceId)` / `createTask` / `updateTask` / `deleteTask` → `/api/workspaces/:id/tasks*` (routes EXIST, adapter methods MISSING). - New hook `useWorkspaceDesktop(workspaceId)` composing state + activity + tasks + members + fleet (agents-running) + cron (automations) + capabilities/status (MCPs-connected) for the status bar. Reuse `useRoomState` for live agents. --- ## 5. Backend work Per PRD §16.2 plus the substrate the Overview/widgets/status-bar need. Cross-referenced against backend-routes inventory + backend-map `03c`. | PRD §16 endpoint | Status | Extend vs net-new · substrate · migration | |---|---|---| | `GET /api/workspaces/:id` | **EXISTS** | `workspaces.ts`. Header name/team. But `type`+`status` fields are **MISSING** on `WorkspaceConfig` (`hive-mind-core/src/workspace-manager.ts:5-58`) — additive JSON fields, **no DB migration** (workspace.json file). Default `status:'active'`; derive `type` from `templateId`/`group`. | | `PATCH /api/workspaces/:id` | **EXISTS** | `workspaces.ts`. Used for status change / Share controls. Stamp `updatedAt` in `update()` (`workspace-manager.ts:222`, currently unstamped). | | `GET /api/workspaces/:id/context` | **EXISTS** | `workspaces.ts:311` — the "Workspace Now" block (`buildWorkspaceNowBlock()`, `workspace-context.ts:191-404`). Direct feed for Overview widgets (greeting/decisions/memories/threads/pending/schedules). | | `GET /api/workspaces/:id/state` | **PARTIAL → EXTEND** | No `/state` route. `buildWorkspaceState()` (`workspace-state.ts:234-311`) already produces `active/openQuestions/pending/blocked/completed/stale/recentDecisions/nextActions` and is surfaced *inside* `/context` as `workspaceState`. Add a thin `/state` route returning that sub-object directly (Overview/Tasks consume `pending`+`blocked` as task seeds). Substrate: `memory_frames` + session JSONL + `awareness`. No migration. | | `GET /api/workspaces/:id/activity` | **PARTIAL → EXTEND** | No per-workspace `/activity`. Closest: `GET /api/events?workspaceId=` (`events.ts`) and `GET /api/teams/:id/activity`. Add a thin `/activity` alias over the audit-event query (substrate: `ai_interactions`/`execution_traces`/events). No migration. | | Tasks: `GET/POST /api/workspaces/:id/tasks`, `PATCH/DELETE …/:taskId` | **EXISTS (server)** | `tasks.ts` (backend-routes §1.7). Only FE plumbing missing — no net-new backend. | | Status bar feeds | **EXISTS, no aggregate** | agents → `GET /api/fleet` (`fleet.ts`); automations → `GET /api/cron` (`cron.ts`); MCPs connected → `GET /api/capabilities/status` (`mcpServers[]`) / `install_audit`. Compose client-side in v1; an aggregate `/status` route is optional. | | Members / Share | **PARTIAL** | Members → `GET /api/team/members` (EXISTS). **Share** → PRD §16.11 `POST /api/share` is **MISSING** (grep-confirmed, backend-routes §16.11). Header Share button is net-new backend; for non-team workspaces it can be a no-op/disabled in v1. | | Artifacts widget/tab | **MISSING (largest gap)** | No `Artifact` entity, table, or `/api/artifacts*` route anywhere (substrate-types §e; backend-routes §16.6). Interim: render the **file registry** `GET /api/workspaces/:id/files` (`workspaces.ts`) + document versions `GET /api/workspaces/:id/documents` (`documents.ts`) as "artifacts". Full Artifact Center is **S05's** scope — S02 should depend on it, not build it. | **Migration flag:** the only `.mind` SQLite migration *adjacent* to this screen is the optional `memory_frames.metadata`/`confidence`/`kind` additions (substrate-types §c) needed for richer Memory **filters** — **not required for S02's Overview/Tasks/Timeline tabs**; defer to S04 (Memory Center). S02's own missing fields (`type`, `status`, `updatedAt`, `lastActiveAt`) are JSON-file additive — **no DB migration**. --- ## 6. Shared types needed (PRD §15 vs `lib/types.ts`) - **`WorkspaceType`, `Scope`, `Confidence` literal unions** (PRD §15.2) — **none exist** in `apps/web/src/lib/types.ts` (substrate-types §e). Add `WorkspaceType` + `WorkspaceStatus` (`active`/`paused`/`archived`) for header. - **`Workspace` → `WorkspaceConfigV2` alignment** (PRD §15.3) — FE `Workspace` (`types.ts:22-40`) lacks `type`, `status`, `description`, `updatedAt`, `lastActiveAt` and uses `persona` vs config's `personaId`. Add the 5 missing fields (optional) for header/last-activity; keep DERIVED display fields. - **`WorkspaceState` type** — exists server-side (`workspace-state.ts:38-55`) but is **not mirrored** in FE `types.ts`. Add a FE `WorkspaceState` mirror for the new `getWorkspaceState` method. - **`Task` type** — `lib/types.ts` has no Task interface (server `tasks.ts` shape only). Add one for the Tasks tab. - **`Artifact` type** — **greenfield** (PRD §15.6). Owned by S05; S02 imports it once defined. - `WorkspaceContext` already exists in `types.ts` (consumed by `WorkspaceBriefing`) — reuse for Overview. --- ## 7. Dependencies (screens / phases first) - **Phase 1 (Shell + Ctrl+K)** — `_blueprint_extracted.txt:582` — must land first: this screen is opened *from* the shell/route map and the left nav. S02 needs the new `route`/`activeWorkspaceId` global state + the `case 'workspace'` shell wiring. - **Phase 2 (Home + Workspace)** — `_blueprint_extracted.txt:585` — S02 ships **with** S01 (Home Cockpit); both share `/api/workspaces/:id/context` + `/state`. S01's cross-workspace briefing reuses S02's per-workspace builder. - **S05 Artifact Center** — hard dependency for the Artifacts tab/widget (entity + `/api/artifacts*` are entirely net-new there). S02 must ship the Artifacts tab as an **interim file-registry view** if S05 is not ready. - **S04 Memory Center** — the Memory tab embeds `MemoryApp`; richer confidence/kind filters (and the `memory_frames` metadata migration) live there, not in S02. - **S03 Command Center (Ctrl+K)** — the header search + quick actions route through the command provider. --- ## 8. Effort **XL.** Net-new full-screen tabbed runtime that re-architects the product's primary surface (chat → one-widget), needs 5-6 new FE components + several adapter methods/hooks, 2 thin backend routes (`/state`, `/activity`) + workspace `type`/`status`/`updatedAt`/`lastActiveAt` additive fields, and is gated on S05 (Artifacts) for one full tab. The read-only Overview seed exists (`WorkspaceBriefing`), which keeps it from being 2×XL, but the shell-integration + tab embedding + status-bar aggregation breadth dominate. --- ## 9. Open questions 1. **Window vs full-screen.** Should the Workspace Desktop be a maximized `AppWindow` (reuse existing window manager + chrome) or a dedicated full-bleed route bypassing the floating-window system? The mockup is full-screen; the current OS is windowed. Recommend maximized-window to avoid a parallel layout system — needs founder/eng confirmation. 2. **Chat-as-widget vs Chat-tab.** PRD says "chat is one widget" (Overview) AND lists a "Chat" tab. Is the Overview chat widget a live mini-composer or a read-only preview that deep-links to the Chat tab? Affects whether `ChatApp` must run in two render modes. 3. **`workspace.type` taxonomy.** PRD §15.2 names `WorkspaceType` but no enum values are given. Derive from the 15 existing `workspace-templates` categories, or define a new fixed set? 4. **`status` lifecycle.** Who/what sets `paused`/`archived` (manual header action vs automation)? PRD §12.2 lists the status states but not the transitions. 5. **Share scope.** `POST /api/share` is net-new (PRD §16.11). Is Share in S02's MVP, or stubbed until Team Workspace (S10)? For a solo/non-team workspace, what does Share do? 6. **Tasks store of record.** Tasks tab — back onto the existing `/api/workspaces/:id/tasks` store, or model tasks as `pending`/`blocked` `StateItem`s from `WorkspaceState` (which are session/awareness- derived, not first-class)? These are two different sources of truth to reconcile.