# Gap Card — S18 Agent Builder > UX-refactor planning artifact. Execution model: **in-place incremental refactor** of > `apps/web` + targeted backend extensions. Every claim is grounded in a real file. > PRD = `docs/Waggle_OS_UX_Refactor_Master_Handoff_Package/Waggle_OS_UX_Refactor_PRD.md` > (§12.9 + §16.7). Mockup (directional only) = > `Waggle_OS_Handoff_Assets/screens_18_21_builders_and_marketplace.png`. --- ## 1. Screen & purpose Create an **agent as an explicit work actor** through a guided stepper, with no hidden memory/tool access. PRD §12.9: "Manage agents as explicit work actors… User can explain what an agent can see and do before enabling it." Blueprint Screen 18 (`_blueprint_extracted.txt:410-416`): "Create an agent with goal, model, autonomy, memory, skills and permissions. Configure, test, review, create. States: Draft; validation; approval needed; created. Acceptance: No agent has hidden memory/tool access." The Agent Builder is the create-flow companion to the **Agent Center** (Screen 9, a separate gap card). S18 is one of four builder/marketplace screens grouped in the same mockup (18 Agent Builder, 19 Skill Builder, 20 Automation Builder, 21 Marketplace). PRD §16.7 names the agent CRUD/run/traces API surface this builder writes to. --- ## 2. Required states (PRD / Blueprint) **Builder steps (PRD §12.9, line 589):** `Basic Info → Capabilities → Memory & Tools → Permissions → Review & Create` (5-step stepper). **Agent fields the builder must collect (PRD §12.9 line 590 + §15.5 lines 1015-1036):** name, goal, description, persona/avatar, model, autonomyLevel (`manual|guided|medium|high`, PRD §15.2), type (`personal|workspace|team|autonomous`), memoryScopes, skillIds, connectorIds, mcpIds, permissions, status, workspaceIds, createdBy, lastRunAt, successRate. **Per-screen states (blueprint `:413-414` + `:461-463`):** - `Draft` — partially-filled builder, save without activating. - `Validation` — required-field gating (goal, model, memory scope, skills/tools/MCPs, autonomy per blueprint `:134`). - `Approval needed` — elevated permission selections require an approval prompt before create (PRD §12.9 "all elevated access is reviewed"; §17.3 "elevated actions require human approval"). - `Created` — agent appears in Agent Center + target workspace (Journey 10, PRD lines 746-753). - Plus global states (PRD §14.1): Loading, Error, Offline/local-only, Permission denied. **Hard acceptance gate (blueprint `:415-416`, `:134`):** "No agent has hidden memory/tool access" and "Agent Builder must require model, goal, memory scope, skills/tools/MCPs and autonomy level." The Review step must render the full effective permission/memory/tool surface before the user confirms. **Test affordance:** blueprint `:413` "Configure, **test**, review, create" — a dry-run before create (analogous to Skill Builder's test). PRD §12.9 does not list test as a functional requirement; treat as optional (open question §9). --- ## 3. Current state in repo — disposition: **create-new** (builder) + **partial** (substrate reuse) There is **no Agent Builder and no first-class Agent entity** today. The closest existing surface is a **persona/agent-group** model, which is a strict subset of the PRD Agent. **Existing frontend (the seed):** - `apps/web/src/components/os/overlays/SpawnAgentDialog.tsx` — a 2-step dialog (`config → confirm`, `:29`) that spawns a **transient sub-agent** (task + persona + model + parent workspace) via `adapter.spawnAgent` → `POST /api/fleet/spawn`. It collects only `task/persona/model/workspaceMode` (`:37-44`); it has model-fetch with 3-tier fallback (`:50-99`) and a cost-estimate review pane (`:388-421`). It does **not** persist an agent definition — it fires a one-shot fleet job. This is the seed named in the task, but it is a *spawn* dialog, not a *builder*. - `apps/web/src/components/os/apps/AgentsApp.tsx` — titled **"Personas"** (`:175`), two tabs (`agents`/`groups`, `:16`). Lists personas via `adapter.getPersonas()` (`:36`) and agent-groups via `adapter.getAgentGroups()` (`:38`). "New Persona" → `CreateAgentForm`. - `apps/web/src/components/os/apps/agents/CreateAgentForm.tsx` — a **single-page** form (not a stepper) collecting `name/description/icon/systemPrompt/tools[]` (`:9`), with an "Generate with AI" box (`:58-81`) → `adapter.generatePersona`. This is the closest existing "create-an-agent" UI, but it maps to a **persona** (no goal/autonomy/model/memoryScope/connectors/mcps/permissions). - `apps/web/src/components/os/apps/agents/AgentDetail.tsx` — read view showing icon/name/description/tools/commands/affinity (`:49-103`). No goal/model/autonomy/permissions/successRate/status. **Existing backend (the substrate to reuse, not rebuild):** - `packages/server/src/local/routes/personas.ts` — `GET/POST/PATCH/DELETE /api/personas` + `POST /api/personas/generate`. POST persists a custom `AgentPersona` to disk (`saveCustomPersona`, `:57`); fields are `id/name/description/icon/systemPrompt/modelPreference/tools/workspaceAffinity/suggestedCommands/defaultWorkflow` (`:45-56`). **No** goal/autonomy/memoryScopes/connectorIds/mcpIds/permissions/status. PRO-tier gated (`:32`). - `AgentPersona` interface (`packages/agent/src/personas.ts`; full field list in `docs/backend-map/sections/05a-subsystem-agent-runtime.md:198-218`) already carries `suggestedSkills?/suggestedConnectors?/suggestedMcpServers?/disallowedTools?/isReadOnly?` — useful seed columns for the richer Agent. - `packages/server/src/local/routes/agent-groups.ts` — `GET/POST/PATCH/DELETE /api/agent-groups` + `POST /api/agent-groups/:id/run` (the run is a **placeholder stub**, `:105-127` — returns a queued jobId, does not execute). Groups persist to `{dataDir}/agent-groups.json` (`:29`). This is the closest "agent persistence on disk via JSON file" precedent. - `packages/server/src/local/routes/fleet.ts` — `POST /api/fleet/spawn` is the **only real agent-execution path** (`:66-257`): creates a session, emits Waggle signals, and **fire-and-forgets `runAgentLoop`** in the background (`:142-245`). `POST /api/fleet/:workspaceId/pause|resume|kill` (`:260-290`). This is what `/api/agents/:id/run` and `/pause` must wire onto. - `execution_traces` table (`packages/hive-mind-core/src/mind/schema.ts:199`) is written from `chat.ts` and `evolution.ts` (grep-confirmed) but has **no HTTP read route** — `/api/agents/:id/traces` is net-new over this store. **Why create-new, not rework:** the PRD Agent (§15.5) is a **superset** of persona — it adds goal, autonomy, type, memoryScopes, connectorIds, mcpIds, permissions, status, workspaceIds, lastRunAt, successRate. A persona is the *behavioral template*; a PRD Agent is an *instantiated, scoped, governed actor*. Bending `CreateAgentForm`/persona-POST to carry all of that would corrupt the persona contract (shared by the runtime prompt composer). The clean model: **net-new Agent entity + 5-step builder**, with a persona selected *as one field* of the agent. Heavy reuse of persona catalog, model picker, tool catalog, fleet-spawn, and execution-traces underneath. --- ## 4. Frontend work **Create new — `apps/web/src/components/os/overlays/AgentBuilder.tsx`** (or `components/os/apps/agents/AgentBuilder.tsx` if hosted inside the Agents app shell). A 5-step stepper matching PRD §12.9: 1. **Basic Info** — name, goal (required), description, persona/avatar picker, type (`AgentType`). 2. **Capabilities** — model (required), autonomyLevel (required), defaultWorkflow. 3. **Memory & Tools** — memoryScopes (required), skillIds, tools[] (required-ish per blueprint `:134`). 4. **Permissions** — connectorIds, mcpIds, explicit permissions; surface elevated-access warnings here (drives the "approval needed" state). 5. **Review & Create** — full effective surface (the "no hidden access" gate), then create. **Reuse targets (do not rebuild):** - **Stepper chrome:** there is no shared `BuilderStepper` primitive yet (PRD §19.1 lists "Builder stepper" as a design-system component to create). S18/S19/S20 all need it — build it **once** as `components/ui/builder-stepper.tsx` and share. (Cross-screen dependency — flag to the Skill Builder & Automation Builder cards.) - **Model picker:** reuse `components/os/ModelSelector.tsx` (already used by Spawn/Settings/onboarding) instead of `SpawnAgentDialog`'s bespoke model-button grid (`SpawnAgentDialog.tsx:328-344`). - **Persona picker:** reuse the persona grid pattern from `SpawnAgentDialog.tsx:258-276` + `PERSONAS` from `@/lib/personas`; or fetch live via `adapter.getPersonas()` (as `AgentsApp.tsx:36`). - **Tool picker:** reuse the searchable checkbox list from `CreateAgentForm.tsx:104-145` (tools sourced from `adapter.getCapabilityStatus()` → flattened `ToolDef[]`, `AgentsApp.tsx:49-55`). - **Skills/connectors/MCPs pickers:** `adapter.getSkills()`, `adapter.getConnectors()`, and MCP list (see §5 — MCP list endpoint is itself partial). Persona's `suggestedSkills/suggestedConnectors/suggestedMcpServers` (05a `:216-218`) can pre-seed recommendations. - **Cost-estimate review pane:** lift from `SpawnAgentDialog.tsx:388-421` (`adapter.getModelPricing()`). - **Approval prompt:** reuse the approvals pattern (`ApprovalsApp` / inline chat approvals) for the elevated-access gate; do not invent a new modal. **Adapter methods to add (`apps/web/src/lib/adapter.ts` — the single sidecar gateway, ~150 methods):** `getAgents()`, `createAgent(def)`, `getAgent(id)`, `patchAgent(id, partial)`, `runAgent(id, {task?})`, `pauseAgent(id)`, `getAgentTraces(id)`. (Today the adapter has `getPersonas/createPersona/…`, `spawnAgent`, `getFleet/fleetAction`, `getAgentGroups/…` — none of these is the PRD Agent CRUD.) **Wiring:** register the builder open path through the existing `waggle:open-app` CustomEvent / overlay state (`useOverlayState`); add it as a "New Agent" entry in the Agents app (which should be renamed/retitled from "Personas" to host both — Agent Center card decides final IA). **Reuse SpawnAgentDialog** as the quick "run now without saving" path — keep it; it is a different verb (ephemeral spawn) from the builder (persisted definition). --- ## 5. Backend work (PRD §16.7 endpoints) > Naming collision (backend-routes inventory `:486-492`): the **Cloud** server has a > Clerk-gated `routes/agents.ts` with `/api/agents` CRUD — but that is NOT the sidecar. > The desktop frontend talks only to the **local sidecar**, where the sidecar agent surface > is `/api/agent/*` (singular) + `/api/agents/active` + `/api/agent-groups/*` + `/api/fleet/*`. > So in the desktop context every §16.7 row below is MISSING-or-PARTIAL **locally**. | PRD §16.7 endpoint | Status (sidecar) | Extend vs net-new + substrate | |---|---|---| | `GET /api/agents` | **MISSING** | Net-new route. Reads a net-new agent-definition store. Closest existing "definitions": `GET /api/personas` (`personas.ts:15`) + `GET /api/agent-groups` (`agent-groups.ts:49`) — neither is the PRD Agent. | | `POST /api/agents` | **MISSING** | Net-new. **Pattern to reuse:** agent-groups JSON-file persistence (`agent-groups.ts:29-43`, `{dataDir}/agent-groups.json`) → store agents at `{dataDir}/agents.json` (no SQLite, mirrors persona/group precedent). Validate goal/model/memoryScopes/autonomy/permissions. PRO-tier gate like `personas.ts:32`. | | `GET /api/agents/:id` | **MISSING** | Net-new read over the new store. | | `PATCH /api/agents/:id` | **MISSING** | Net-new partial-update (mirror `agent-groups.ts:74-90` PATCH shape). | | `POST /api/agents/:id/run` | **PARTIAL** | **Extend, do not build new execution.** Resolve agent → call the real executor `POST /api/fleet/spawn` (`fleet.ts:66`, the only path that actually runs `runAgentLoop` `:185`). Map agent's persona/model/memoryScope/workspace onto the spawn body. (`/api/agent-groups/:id/run` is a stub — `agent-groups.ts:105` — do NOT reuse it as the model.) | | `POST /api/agents/:id/pause` | **PARTIAL** | **Extend.** Map agent's running session → `POST /api/fleet/:workspaceId/pause` (`fleet.ts:260`). | | `GET /api/agents/:id/traces` | **PARTIAL / net-new route** | No HTTP route reads traces today. The `execution_traces` table exists (`schema.ts:199`) and is written by `chat.ts`/`evolution.ts`. Add a thin read route over the execution-trace store, filtered by agent/session. Fallback: session timeline `GET /api/workspaces/:wid/sessions/:sid/timeline` (`sessions.ts`). | **Substrate touched:** new `{dataDir}/agents.json` (file store — no DB migration); `personas.ts` (read for persona field); `fleet.ts` (run/pause delegation); `execution_traces` (read for traces); `install_audit` (write an audit entry on agent create when elevated connectors/MCPs are attached — `InstallAuditStore`, see §d of the substrate inventory; note the `risk_level='critical'` CHECK-constraint drift bug flagged there `install-audit.ts:16` vs DDL `:65`). **.mind migration:** **NONE required.** The agent definition lives in a JSON file (precedent: persona disk store + `agent-groups.json`), not in SQLite. `lastRunAt`/`successRate` are derived (successRate from `execution_traces.outcome` / `procedures.success_rate` `schema.ts:147,206`), not new columns. This matches the LOCKED in-place model and the backend-routes inventory verdict ("none require a new data store"). --- ## 6. Shared types needed (PRD §15 vs `lib/types.ts`) Per substrate inventory §(e): **none of the PRD §15.2 unions exist in `apps/web/src/lib/types.ts`.** S18 needs: - `AgentType = 'personal' | 'workspace' | 'team' | 'autonomous'` (PRD §15.2) — **MISSING**. - `AutonomyLevel = 'manual' | 'guided' | 'medium' | 'high'` (PRD §15.2) — **MISSING** in FE (note: a *different* `AutonomyLevel` exists in `hooks/useWindowManager.ts` for chat windows — Normal/Trusted/YOLO; do **not** reuse, they are different vocabularies — flag the collision). - `Scope = 'personal' | 'workspace' | 'team' | 'organization'` (for `memoryScopes`) — **MISSING**. - A full **`Agent`** interface (PRD §15.5 fields) — **MISSING**. Today `packages/shared/src/types.ts` has a thin `AgentDef` (`:36-47`: id/userId/teamId/name/role/systemPrompt/model/tools/config/createdAt) lacking goal/type/autonomy/memoryScopes/skillIds/connectorIds/mcpIds/permissions/status/lastRunAt/successRate. Decide: extend `AgentDef` (shared, cloud-aligned) vs add a desktop-local `Agent` in `lib/types.ts`. Given the sidecar-only execution model, a **new `Agent` interface in `lib/types.ts` + a matching server-side type** is cleanest; keep `AgentDef` for the cloud path. - `ExtensionType` (for the connector/mcp/skill pickers' provenance) — **MISSING** but shared with S19/S21. Keep types consistent with the new `agents.json` shape (PRD §22.2 "Frontend types are consistent with API contracts"). --- ## 7. Dependencies (screens / phases first) - **Phase 3 (Intelligence layer)** per PRD §8 / Sprint 6 — same phase as Agent Center (S9), Skill Builder (S19), Automation Builder (S20). - **Agent Center (Screen 9)** — the builder's create result must land somewhere; the Agent Center list/card view + the new `Agent` type + `GET /api/agents` are a shared prerequisite. Sequence: define `Agent` type + agent store + `GET/POST /api/agents` **with** Agent Center, then layer the builder on top. - **Shared `BuilderStepper` primitive** (PRD §19.1) — build once, shared by S18/S19/S20. Whichever builder ships first owns it. - **Connector Hub (S?) / MCP Hub (S?)** — the Permissions step picks connectorIds/mcpIds; the MCP listing is itself PARTIAL (no `GET /api/mcps`; data lives in `capabilities/status.mcpServers[]` + `@waggle/shared mcp-catalog.ts`). The picker can read those existing surfaces without waiting for the full Hubs, but the canonical MCP list endpoint is a cross-card dependency. - **Approval prompt** component (PRD §19.1) — reuse existing approvals plumbing; not a hard blocker. - **AppShell / IA** (Phase 0/1) — the builder opens via the existing window-manager overlay path; no new routing (single-route windowed desktop, per frontend inventory §b). --- ## 8. Effort: **L** Net-new 5-step builder UI + net-new `Agent` entity, store, and CRUD routes, plus run/pause delegation onto fleet and a net-new traces read route — but **every backend piece reuses an existing substrate** (persona catalog, agent-groups JSON-file precedent, fleet-spawn executor, execution-traces store; no `.mind` migration). The heavy reuse and absence of a DB migration keep it off XL; the breadth (4 new + 3 partial endpoints, a new shared entity/type, a shared stepper primitive, and the elevated-access approval gate) keeps it above M. --- ## 9. Open questions 1. **Agent vs persona boundary.** Confirm the model: persona = behavioral template (one *field* of an agent) vs agent = scoped governed instance. This card assumes that split. Should creating an agent ever auto-create a backing persona, or always reference one? 2. **Store location.** `{dataDir}/agents.json` (mirrors `agent-groups.json`) vs a new `agents` row in personal `.mind`. This card recommends the JSON file (no migration, matches precedent). Confirm. 3. **`/run` semantics.** Does Agent Builder's eventual run mean "fleet-spawn a one-shot in a chosen workspace" (current real path) or "persistent agent that keeps running"? PRD agent states include `Running/Paused/Completed` (§14.5) — confirm the lifecycle the sidecar must support beyond fleet's ephemeral sessions. 4. **Test step.** Blueprint says "configure, **test**, review, create" (`:413`); PRD §12.9 omits test. Include a dry-run (like Skill Builder's `POST /api/skills/:id/test`) or defer? 5. **`successRate` source.** Derive from `execution_traces.outcome` vs `procedures.success_rate` vs a new counter? (Both exist; pick one to avoid a third tally vocabulary.) 6. **Autonomy vocabulary collision.** PRD `AutonomyLevel` (`manual/guided/medium/high`) vs the chat-window `AutonomyLevel` (Normal/Trusted/YOLO in `useWindowManager.ts`) vs the agent-loop's tiered-autonomy. Which governs an agent's tool execution at run time? 7. **Cloud vs sidecar `/api/agents`.** The Cloud server already has Clerk-gated `/api/agents` CRUD. Should the desktop sidecar's new routes share a contract/shape with it for future sync, or stay independent?