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), mockupWaggle_OS_Handoff_Assets/screens_18_21_builders_and_marketplace.png, backend-mapsections/03d+05g, inventories underdocs/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):
- Basic Info — name, description, category.
- Instructions — the prompt/steps body.
- Inputs & Outputs — declared input params + expected output shape.
- Tools & Data — tools/data + memory access (read scope).
- 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
permissionsblock 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 (handleTestSkill→POST /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:652—createSkill({ name, description })exists but is lossy: it POSTs to/api/skills/createwith only{name,description}(nosteps/tools/category), while the backend requires a non-emptysteps[](skills.ts:434). So the one adapter method that targets the create route is under-specified and has no caller inapps/web/src(grep:createSkillappears only at its definition). Needs rework to the full template shape.apps/web/src/lib/types.ts:210—SkillPack(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:11—SkillTemplate(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:53—ParsedSkill/SkillFrontmatter(name, description,scopepersonal→workspace→team→enterprise:27,permissionsblock: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 inoverlays/(consistent withCreateWorkspaceDialog.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 theSKILL_FAMILIESfamily set inskills.ts:13-31: writing/research/decision/planning/communication/code/creative — surface these as the category options, not the narrowerSkillPack.category5-union). - Step 2 Instructions: ordered
steps[]editor (add/remove/reorder) + optionaltriggerPatterns[](maps directly toSkillTemplate.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 inCapabilitiesApp.tsx:422-434— extract that hardcoded list to a shared module to avoid a third copy; the agent tool registry ispackages/agent/src/tools.ts) + memory access / scope (SkillScopepersonal/workspace/team —skill-frontmatter.ts:27) + apermissionstoggle group (skill-frontmatter.ts:40-48). - Step 5 Review & Create: summary card + Test button (calls existing test route) + Create.
- Step 1 Basic Info:
- 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— widencreateSkill(:652) tocreateSkill(t: { name; description; steps: string[]; tools?: string[]; category?: string; triggerPatterns?: string[] })(fullSkillTemplateshape, matchingskills.ts:424-430). AddupdateSkill(name, content)→PUT /api/skills/:name(skills.ts:506) for edit, and reuse the existing test call (CapabilitiesApp inlinesfetch('/api/skills/test'):91— promote it to anadapter.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 dispatcheswaggle:open-appor opens the Builder overlay viauseOverlayState(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 touseOverlayState. - Ctrl+K "Create → Skill" command should open it (PRD §12.3 Create category;
GlobalSearch.tsxalready 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 optionalinputs?/outputs?/scope?toSkillTemplate); they round-trip as## Inputs/## Outputs/ frontmatterscope:sections.parseSkillFrontmatteralready readsscope(skill-frontmatter.ts:27) andpermissions. - 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 mirroringpackages/agent/src/skill-creator.ts:11(currently the FE only has the catalog-shapedSkillPacktypes.ts:210). Fields:name, description, category, steps[], triggerPatterns[], tools[]+ PRD additionsinputs[],outputs[],scope(SkillScope),permissions. KeepSkillPack(catalog) distinct fromSkillTemplate(authoring) — they are different objects. - Reuse
SkillScope(personal|workspace|team|enterprise) fromskill-frontmatter.ts:27rather than redeclaring (export it through the FE if needed; PRD §15.2Scopeis the broader personal/workspace/team/organization — reconcile: skills use theenterprisevariant). SkillPack.categoryis a narrow 5-union (types.ts:213) that does not match the backendSKILL_FAMILIES7-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/orcomponents/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
- Install vs create semantics. Authored skills write straight to
~/.waggle/skills/(create == installed). Does PRDPOST /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. - 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).
- 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. - Scope vocabulary reconciliation.
SkillScopeusesenterprise; PRD §15.2Scopeusesorganization. Pick one for the Builder's publish-to-scope picker. - Test-run fidelity.
POST /api/skills/testreturns 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.) - Category source of truth. Reconcile
SkillPack.category(5-union) vsSKILL_FAMILIES(7-set) vsSkillTemplate.category(free string) — which is canonical for the picker?