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

17 KiB

Gap Card — S19 · Skill Builder

UX-refactor planning artifact. Execution model is LOCKED in-place incremental refactor of apps/web + targeted sidecar extensions. Mockups are directional (PRD §24); PRD acceptance criteria win. Every claim below is grounded in a cited file.

Sources: PRD §12.6 + §16.8 (docs/.../Waggle_OS_UX_Refactor_PRD.md), Blueprint Screen 19 (_blueprint_extracted.txt:417-421, state model :464), mockup Waggle_OS_Handoff_Assets/screens_18_21_builders_and_marketplace.png, backend-map sections/03d + 05g, inventories under docs/ux-refactor/_inventory/.


1. Screen & purpose

Skill Builder — the create/edit surface for a reusable capability (Skill). PRD §12.6: a stepper Builder ("Basic Info → Instructions → Inputs & Outputs → Tools & Data → Review & Create"), with test-run before publishing and assignment to agents/workspaces/automations or direct use. Blueprint Screen 19 (_blueprint_extracted.txt:417-421): "Create reusable capability. Define prompt, inputs/outputs, tools, memory access, test." States: Draft; test pass/fail; published; archived. Acceptance: "Skills are inspectable and reusable by agents/automations" (PRD §12.6 acceptance: "a user can understand what a skill does, where it is used, and what access it has").

This is the Builder half of the Intelligence layer's Skills surface (S06 Skills Hub is the browse/library half). PRD Roadmap puts both in Sprint 6 / Phase 3 (PRD:344-351, :236-240). The mockup tile labelled "Skill Builder" shows a left form column (name/description/category + instructions textarea) and a right column (tools picker + memory access + a Test panel + a primary "Create Skill" action) — directional confirmation of the §12.6 stepper.


2. Required states (PRD / Blueprint)

PRD §14.1 global states (every screen) + Blueprint Skills row (_blueprint_extracted.txt:464): Loading, empty, populated, error; Installed, draft, custom, workspace, marketplace, update available; recovery: Test, install, publish, archive, rollback.

Builder-specific lifecycle (Blueprint Screen 19 :417-421): Draft → test pass/fail → published → archived, with PRD global add-ons: validation error, approval required (skills that request elevated tool/secret access), offline/local-only.

Stepper steps the Builder must implement (PRD §12.6 :542):

  1. Basic Info — name, description, category.
  2. Instructions — the prompt/steps body.
  3. Inputs & Outputs — declared input params + expected output shape.
  4. Tools & Data — tools/data + memory access (read scope).
  5. Review & Create — summary + Test run + publish-to-scope (personal/workspace/team).

Per-state behaviours required:

  • Validation error — name normalises to kebab-case; empty name/description/steps blocked (backend already 400s on these — §5).
  • Test pass/fail — inline Test panel showing the injected-prompt preview + parsed metadata.
  • Published — confirmation + the new skill appears in the Hub (Installed list).
  • Approval required — when declared tools include elevated/secret/code-exec permissions (frontmatter permissions block exists — skill-frontmatter.ts:40-48).

3. Current state in repo

Disposition: create-new (frontend Builder), keep-promote (backend structured-create contract). There is no Skill Builder component anywhere in apps/web/src — grep for SkillBuilder|Skill Builder|skill-builder over apps/web/src returns 0 matches. Skill creation today is only available to the agent (the create_skill tool, skill-creator.ts:8), not to the user via UI.

What exists today:

  • apps/web/src/components/os/apps/CapabilitiesApp.tsx — "Skills & Apps". A browse/install/test surface only. Tabs: installed | starter | marketplace | tools | audit (:80, :358). It lists packs (PackCard :190), shows a detail drawer (PackDetail :249), installs (handleInstall/handleMarketplaceInstall :164,:174), and tests an existing skill (handleTestSkillPOST /api/skills/test :88-102). It has NO create/edit form. This is the natural host to add a "+ Create Skill" entry point that launches the new Builder.
  • apps/web/src/lib/adapter.ts:652createSkill({ name, description }) exists but is lossy: it POSTs to /api/skills/create with only {name,description} (no steps/tools/category), while the backend requires a non-empty steps[] (skills.ts:434). So the one adapter method that targets the create route is under-specified and has no caller in apps/web/src (grep: createSkill appears only at its definition). Needs rework to the full template shape.
  • apps/web/src/lib/types.ts:210SkillPack (id/name/description/category/skills[]/installed/trust). This is a pack/catalog shape, NOT a skill-authoring shape (no instructions/inputs/outputs/tools).
  • packages/agent/src/skill-creator.ts:11SkillTemplate (name, description, triggerPatterns[], steps[], tools[], category) + generateSkillMarkdown() (:26). This is the canonical authored-skill model the backend writes from.
  • packages/agent/src/skill-frontmatter.ts:53ParsedSkill/SkillFrontmatter (name, description, scope personal→workspace→team→enterprise :27, permissions block :40-48). This is the read/parse side; the Builder's "memory access / permissions" + "scope" map onto this.

Conclusion: backend authoring contract is solid and reusable; the frontend Builder UI is greenfield, and the adapter method must be widened to the full template.


4. Frontend work

Create (new):

  • apps/web/src/components/os/overlays/SkillBuilder.tsx — a 5-step stepper modal/drawer. Place it in overlays/ (consistent with CreateWorkspaceDialog.tsx, SpawnAgentDialog.tsx). Reuse the DS Builder-stepper pattern (PRD §19.1 lists "Builder stepper" as a core component — none exists yet, so this is the first stepper; AgentBuilder S18 + AutomationBuilder S20 should share it — see §7).
    • Step 1 Basic Info: name, description, category (select from the SKILL_FAMILIES family set in skills.ts:13-31: writing/research/decision/planning/communication/code/creative — surface these as the category options, not the narrower SkillPack.category 5-union).
    • Step 2 Instructions: ordered steps[] editor (add/remove/reorder) + optional triggerPatterns[] (maps directly to SkillTemplate.steps/.triggerPatterns).
    • Step 3 Inputs & Outputs: inputs[] / outputs[] param rows. Backend does not persist these structured today (§5) — render them into the markdown body for v1, or block on the §5 backend extension.
    • Step 4 Tools & Data: tools[] multiselect (source the tool catalog already enumerated in CapabilitiesApp.tsx:422-434 — extract that hardcoded list to a shared module to avoid a third copy; the agent tool registry is packages/agent/src/tools.ts) + memory access / scope (SkillScope personal/workspace/team — skill-frontmatter.ts:27) + a permissions toggle group (skill-frontmatter.ts:40-48).
    • Step 5 Review & Create: summary card + Test button (calls existing test route) + Create.
  • Optional apps/web/src/components/os/overlays/skill-builder/ substeps if the file exceeds ~400 LOC (CLAUDE.md file-org rule).

Rework:

  • apps/web/src/lib/adapter.ts — widen createSkill (:652) to createSkill(t: { name; description; steps: string[]; tools?: string[]; category?: string; triggerPatterns?: string[] }) (full SkillTemplate shape, matching skills.ts:424-430). Add updateSkill(name, content)PUT /api/skills/:name (skills.ts:506) for edit, and reuse the existing test call (CapabilitiesApp inlines fetch('/api/skills/test') :91 — promote it to an adapter.testSkill(skillName, testInput?) method so the Builder and CapabilitiesApp share one path).
  • apps/web/src/components/os/apps/CapabilitiesApp.tsx — add a "+ Create Skill" button (header, next to the grid/list toggle :340) that dispatches waggle:open-app or opens the Builder overlay via useOverlayState (the overlay open/close registry — hooks/useOverlayState.ts, per frontend inventory §c). Optionally render an edit affordance on installed custom skills.

Wiring:

  • Register the overlay in Desktop.tsx (overlays block) + add a flag to useOverlayState.
  • Ctrl+K "Create → Skill" command should open it (PRD §12.3 Create category; GlobalSearch.tsx already loads skills :129).

Props/state: local stepper state object { step, name, description, category, steps[], triggerPatterns[], inputs[], outputs[], tools[], scope, permissions, testResult, status }. On Create → adapter.createSkill(template); on Test → adapter.testSkill(name). No new global store; optimistic insert into the Skills Hub list on success (CapabilitiesApp already refetches via getSkills).


5. Backend work (PRD §16.8)

PRD §16.8 endpoint Status Note / what to EXTEND vs NET-NEW Substrate
GET /api/skills EXISTS skills.ts:164 — list installed skills. Hub/Builder list source. ~/.waggle/skills/*.md files
POST /api/skills EXISTS skills.ts:167 raw {name,content}; POST /api/skills/create (skills.ts:431) is the structured one the Builder should use ({name,description,steps[],tools?,category?}generateSkillMarkdown + redactSkillContent + audit + hash). skill files + auditStore + skillHashStore
PATCH /api/skills/:id PARTIAL Update is PUT /api/skills/:name keyed by name, method PUT, body {content} (skills.ts:506-510). PRD uses PATCH+:id. EXTEND: accept PATCH alias + name↔id mapping (skills have no numeric id — name is the id). skill files
POST /api/skills/:id/test PARTIAL Test exists as POST /api/skills/test (body {skillName, testInput?}, skills.ts:570-575) — not a per-id path. EXTEND: add :id-path variant (or keep body-driven; Builder can call either). Returns injected-prompt preview + metadata. skill files + starter dir
POST /api/skills/:id/install PARTIAL No unified per-skill install-by-id. Closest: POST /api/skills/starter-pack/:id (skills.ts:161), POST /api/skills/capability-packs/:id (:163), marketplace POST /api/marketplace/install (marketplace.ts, Tier: PRO, SecurityGate). EXTEND: add a dispatcher /skills/:id/install that routes by source — OR leave install to the Hub (S06) and have the Builder only create (create == installed, since authored skills write straight to ~/.waggle/skills/). skill files / marketplace

Net-new backend gap surfaced by the PRD stepper (NOT in §16.8, but needed for §12.6 Step 3): the structured-create contract (SkillTemplate, skill-creator.ts:11) has no inputs/outputs and no memoryScopes fields. PRD §15 skill object (and Blueprint §551 "Skill … inputs, outputs, requiredTools, requiredMemoryScopes") expects them. Two options, both in-place:

  • v1 (no migration, recommended): Builder serialises inputs/outputs/memory-scope into the markdown body via an extended generateSkillMarkdown (add optional inputs?/outputs?/scope? to SkillTemplate); they round-trip as ## Inputs / ## Outputs / frontmatter scope: sections. parseSkillFrontmatter already reads scope (skill-frontmatter.ts:27) and permissions.
  • v2 (later): promote to structured frontmatter if inputs/outputs become a query/filter axis.

No .mind migration. Skills are filesystem markdown (~/.waggle/skills/*.md), not SQLite — confirmed skills.ts:46-49. The only DB touch is the install-audit record on create (skills.ts:476, writes to .mind install_audit) + the skill-hash store. The audit record() call already passes riskLevel:'low' so it sidesteps the latent risk_level CHECK drift noted in substrate-types §(d) — no new exposure.

Security: create/update already pass content through redactSkillContent() (strips secrets+user-paths, skills.ts:464,:521) and guard path-traversal in the name (:447). The Builder must NOT bypass these — always go through /api/skills/create / PUT /api/skills/:name, never write files another way. Elevated permissions (codeExecution/secrets/network) in a skill should trigger the §2 "approval required" UX (PRD §12.6 / §17.3 elevated-action approval) — currently no approval gate fires on skill authoring; flag as an open item (§9).


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

PRD §15.2 declares ExtensionType = 'skill' | ...MISSING in apps/web/src/lib/types.ts (substrate-types §e). For S19 specifically:

  • Add SkillTemplate (authoring) FE type mirroring packages/agent/src/skill-creator.ts:11 (currently the FE only has the catalog-shaped SkillPack types.ts:210). Fields: name, description, category, steps[], triggerPatterns[], tools[] + PRD additions inputs[], outputs[], scope (SkillScope), permissions. Keep SkillPack (catalog) distinct from SkillTemplate (authoring) — they are different objects.
  • Reuse SkillScope (personal|workspace|team|enterprise) from skill-frontmatter.ts:27 rather than redeclaring (export it through the FE if needed; PRD §15.2 Scope is the broader personal/workspace/team/organization — reconcile: skills use the enterprise variant).
  • SkillPack.category is a narrow 5-union (types.ts:213) that does not match the backend SKILL_FAMILIES 7-set (skills.ts:13). Widen the FE category union to the family set so the Builder category picker and the Hub badges agree.

7. Dependencies (screens/phases first)

  • Phase/Sprint: PRD Sprint 6 / Phase 3 — Intelligence layer (PRD:344-351, :236-240).
  • Hard prereq — DS Builder Stepper component (PRD §19.1). None exists. S19 is the cheapest place to introduce it, but S18 Agent Builder and S20 Automation Builder share the exact same stepper pattern — build the stepper as a reusable primitive (components/ui/ or components/os/overlays/builder-stepper/) so all three Builders consume it.
  • Sibling — S06 Skills Hub (the browse/library half, hosted today by CapabilitiesApp.tsx). S19 launches from the Hub and writes into it (created skill → Installed list). They should ship together or S06 first.
  • Soft — Command Center (Ctrl+K) (S03) for the "Create → Skill" entry (PRD §12.3); not blocking.
  • Soft — Agent Builder (S18) / Automation Builder (S20) consume skills via skillIds (PRD §15.5) — they depend on skills existing, not on the Builder UI. Skill→agent assignment is a downstream wiring concern.

8. Effort: M

Backend is mostly EXISTS/PARTIAL (structured-create, test, update all present — only thin aliases PATCH/:id-path + an optional inputs/outputs/scope extension to generateSkillMarkdown, no DB migration). The frontend is a net-new 5-step stepper + adapter widening + a reusable stepper primitive shared with S18/S20 — real but bounded UI work. Not S (greenfield component + 3 endpoint extensions); not L (no new substrate, no migration, backend authoring path already proven via the create_skill tool).


9. Open questions

  1. Install vs create semantics. Authored skills write straight to ~/.waggle/skills/ (create == installed). Does PRD POST /api/skills/:id/install (§16.8) apply to the Builder at all, or only to the Hub/Marketplace install flow? Recommend: Builder = create-only; install-by-id lives in S06.
  2. Inputs/Outputs persistence. v1 markdown-body serialisation vs structured frontmatter — confirm whether inputs/outputs need to be queryable (drives the v1-vs-v2 backend choice in §5).
  3. Approval gate on elevated skills. Should authoring a skill that declares permissions: {codeExecution|secrets|network} trigger the PRD §17.3 approval prompt at create time, or only at run time? No gate fires today on authoring.
  4. Scope vocabulary reconciliation. SkillScope uses enterprise; PRD §15.2 Scope uses organization. Pick one for the Builder's publish-to-scope picker.
  5. Test-run fidelity. POST /api/skills/test returns only the injected-prompt preview + parsed metadata (skills.ts:570), it does not execute the skill against an LLM. Is preview-only sufficient for the PRD "test pass/fail" state, or is a live dry-run expected? (Live run would be net-new and lean on /api/agent/run.)
  6. Category source of truth. Reconcile SkillPack.category (5-union) vs SKILL_FAMILIES (7-set) vs SkillTemplate.category (free string) — which is canonical for the picker?