OR Key
drop another .md file to compare - side-by-side diff against shape-builder

shape-builder

personal 2 files

What it does for you

This skill does one job for you, the same careful way every time.

What it produces

A recent result, so you can see the kind of work it returns.

loading…

How to get it

These run inside the Snappy workspace. Want this working in your business? I set skills like this up with you, in one focused week.

Work with me
For developers how this skill is built, graded, and how it runs

at a glance- the short version

eval modeshape
stages4

what's inside - the parts that make up a skill 2/4 present

A skill is just a few plain-text files. Only the main one is required. The rest are optional, added as the work needs them. This is what the skill is made of; how it runs is just below.

The skill
state/skills/shape-builder/SKILL.md present
the skill itself, in plain text
The main file. It says what the skill is and lays out the steps in plain English.
Code
state/lib/shape-builder.ts not present
code the skill can run
Optional. Many skills are just words and need no code at all.
Scripts
state/bin/shape-builder/ not present
helper scripts
Optional. Added when a skill has a few commands to run.
Loader
state/skills/shape-builder/AGENTS.md present
what the AI loads on the fly
Loaded automatically the moment this skill is needed. Kept short on purpose.

how it's graded - what counts as a good run 8 criteria · 7 deterministic · 1 judge

Each row is one thing a good run has to get right. deterministic means a quick check decides, pass or fail. judge means the AI reads the result and rates it. Grading each piece on its own (instead of one overall score) shows exactly where a run fell short, so the fix is obvious.

name
kind
check
primary_path_emits_shape
deterministic
DISPATCH_REGISTRY fires render for <Name>; TOOL_CALL_START/ARGS/END events emit (not text fallback).
shape_renders_nonzero
deterministic
Rendered shape is visually present (not null-render, not blank card). Screenshot required.
all_three_legs_wired
deterministic
(a) TSX file, (b) DISPATCH_REGISTRY, (c) KNOWN_COMPONENTS in server.ts. Any missing = 0.0.
both_library_registration
deterministic
Component appears in BOTH genuiLibrary AND canvasLibrary components[] arrays.
no_name_collision
deterministic
Name does not collide with openuiChatLibrary exports. If it does, score = 0.0.
css_class_present
deterministic
web/src/styles.css has a .snappy-<kebab> class for the component.
typecheck_and_build_clean
deterministic
npx tsc --noEmit = 0 errors. bash scripts/build-app.sh --install exits 0.
component_shape_valid
judge
Rendered component uses brand design system tokens, correct layout, no console errors.

how it runs - the shared frame every skill uses 2/5 present

Every skill runs the same way. One part does the work, a separate part checks it, and a short loader hands the AI exactly what it needs for the job. Anything this skill doesn't use shows a one-line note saying why, on purpose, not by accident.

makes the work The worker
inferred
cp ~/projects/snappy-os/state/bin/shape-builder/ from a command
No worker named, so the first command in the skill is treated as the worker.
checks the work The reviewer
inferred
shape gate an automatic check
The check is an automatic pass or fail on the shape of the result, run separately from the work itself.
frame
learns Self-correction
not present

This skill doesn't fix its own gaps yet.

tidies up Background fixes
present
queued for rewrite runs in the background
Bigger fixes that can't be made on the spot get queued and rewritten in the background later.
remembers Run history
present
state/log/evals.ndjson shape runs
Every run is written down here, so the next time this skill is used it already knows how the last runs went.
Critical rules the things this skill must not get wrong
  1. (a) web/src/genui/<kebab>.tsx — TSX file with View + Component + Args
  2. (b) DISPATCH_REGISTRY entry in dispatch-card.tsx (before final };, NEVER inside another shape's parse/render)
  3. (c) KNOWN_COMPONENTS string + intent regex + emitTriple in server.ts (BOTH sub-steps)

what it has learned - fixes written back in over time sample

When a run hits something this skill didn't handle, the fix gets written back into the skill so it doesn't happen again. FIXED means it was corrected on the spot. LOGGED means it's queued for a bigger rewrite. Either way, the skill gets a little better and never makes the same mistake twice.

  1. Loading feedback rows…

how the work flows- step by step

1 generator
cp
cp ~/projects/snappy-os/state/bin/shape-builder/manifest-template.ts /tmp/my-shape.ts
2 auditor
npx
npx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts check /tmp/my-shape.ts
3 generator
npx
npx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts apply /tmp/my-shape.ts
4 check
npx
npx tsx ~/projects/snappy-os/state/lint/shape-both-library-registration.ts

SKILL.md- the skill, written out in plain English

shape-builder

Rare-path builder for a new custom defineComponent shape in Snappy OS. The default path is OpenUI Lang primitives composed through compose_inline / Lang, optionally persisted as artifact lang_body. Use this skill only when the needed experience cannot be composed from the existing Lang library, Query/Mutation, or a saved artifact.

Rubric

criteria:
  - name: primary_path_emits_shape
    kind: deterministic
    check: "DISPATCH_REGISTRY fires render for <Name>; TOOL_CALL_START/ARGS/END events emit (not text fallback)."
  - name: shape_renders_nonzero
    kind: deterministic
    check: "Rendered shape is visually present (not null-render, not blank card). Screenshot required."
  - name: all_three_legs_wired
    kind: deterministic
    check: "(a) TSX file, (b) DISPATCH_REGISTRY, (c) KNOWN_COMPONENTS in server.ts. Any missing = 0.0."
  - name: both_library_registration
    kind: deterministic
    check: "Component appears in BOTH genuiLibrary AND canvasLibrary components[] arrays."
  - name: no_name_collision
    kind: deterministic
    check: "Name does not collide with openuiChatLibrary exports. If it does, score = 0.0."
  - name: css_class_present
    kind: deterministic
    check: "web/src/styles.css has a .snappy-<kebab> class for the component."
  - name: typecheck_and_build_clean
    kind: deterministic
    check: "npx tsc --noEmit = 0 errors. bash scripts/build-app.sh --install exits 0."
  - name: component_shape_valid
    kind: judge
    check: "Rendered component uses brand design system tokens, correct layout, no console errors."

When to invoke

  • User asks for a reusable React component that many generated surfaces will reuse
  • A platform-faithful brand row (GmailRow, SlackMessageRow, etc.) is needed
  • A form input or interaction primitive is required that cannot be built from existing Lang primitives
  • The needed shape has a fixed schema that must be consistent across many surfaces

Steps

DEPRECATED - OLD MANUAL FLOW (kept until new flow has 5+ shipped components)

The manual 13-step flow below is superseded by the manifest flow. New components use the manifest flow. Old components wired via the manual flow continue to work.


NEW FLOW - manifest-driven (use this for all new shapes)

Step 1: Write a manifest

Copy state/bin/shape-builder/manifest-template.ts and fill in the fields.

cp ~/projects/snappy-os/state/bin/shape-builder/manifest-template.ts /tmp/my-shape.ts
# Edit /tmp/my-shape.ts

Key fields:

  • name: PascalCase. MUST NOT collide with openuiChatLibrary exports (Accordion, Button, Table, DatePicker, etc.). Prefix with brand or "Snappy" when unsure.
  • kind: "brand-row" | "form-input" | "data-display" | "preview" | "primitive"
  • brand: optional - one of gmail | slack | linear | calendar | github | notion | stripe | freshbooks | typefully | xano | krisp | openrouter. Sets brand color tokens from BRAND_DESIGN_SYSTEM.
  • propsSchema: typed props. Avoid "any" without a // SHAPE-ALLOW-ANY: <reason> comment - the shape-props-schema-strict lint will fail.
  • registerIn: { genui: true, canvas: true }: both required.

Step 2: Validate the manifest

npx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts check /tmp/my-shape.ts

Checks: name collision vs openuiChatLibrary, required fields, brand tokens available.

Step 3: Generate the 3 legs

npx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts apply /tmp/my-shape.ts

The generator:

  • Writes web/src/genui/<kebab-name>.tsx (TSX file with View + Component + Args)
  • Inserts the 3-line re-export stub into genui-library.tsx (before genuiLibrary)
  • Prints manual-apply snippets for dispatch-card.tsx and server.ts

Step 4: Apply the manual snippets

The generator prints snippets for:

  • web/src/dispatch-card.tsx: import + DISPATCH_REGISTRY entry (before final };)
  • state/bin/head-screen/server.ts: KNOWN_COMPONENTS string + intent regex + emitTriple
  • web/src/styles.css: CSS class using only var(--...) tokens

Apply each snippet. Critical anchors:

  • dispatch-card.tsx: new entry goes BEFORE the final }; of DISPATCH_REGISTRY. Never inside another shape's parse or render function.
  • server.ts: add name string to KNOWN_COMPONENTS Set AND add the regex + emitTriple block in the intent-matching section. Both sub-steps required or silent null-render.
  • genui-library.tsx: add ShapeNameComponent to BOTH genuiLibrary.components[] AND canvasLibrary.components[].

Step 5: Run pre-commit lint gates

npx tsx ~/projects/snappy-os/state/lint/shape-both-library-registration.ts
npx tsx ~/projects/snappy-os/state/lint/shape-name-collision.ts
npx tsx ~/projects/snappy-os/state/lint/shape-styles-css-class.ts
npx tsx ~/projects/snappy-os/state/lint/shape-props-schema-strict.ts

All must pass before proceeding.

Step 6: TypeScript gate (mandatory)

cd ~/projects/snappy-os-app/apps/snappy-os/web && npx tsc --noEmit 2>&1 | head -20

Fix all errors. Do NOT commit with type errors.

Step 7: Build and deploy

cd ~/projects/snappy-os-app/apps/snappy-os && bash scripts/build-app.sh --install 2>&1 | tail -10

Must exit 0.

Step 8: Auto-verify render

bash ~/projects/snappy-os/state/bin/shape-builder/verify.sh ShapeName

Takes a screenshot of the running app and checks for MountUiError. Pass required before commit.

Step 9: Commit (explicit pathspecs, two repos)

# Snappy OS app
cd ~/projects/snappy-os-app/apps/snappy-os
git add web/src/genui/<kebab-name>.tsx web/src/genui-library.tsx web/src/dispatch-card.tsx web/src/styles.css
git commit -m "shape-builder: add <Name> manifest-driven shape"

# snappy-os
cd ~/projects/snappy-os
git add state/bin/head-screen/server.ts
git commit -m "shape-builder: register <Name> in server.ts KNOWN_COMPONENTS + matcher"

Step 10: Eval row

# append to state/log/evals.ndjson
npx tsx state/lib/log.ts append evals '{"skill":"shape-builder","shape":"<Name>","score":1.0}'

Brand design system

All brand-row shapes use the BRAND_DESIGN_SYSTEM tokens from state/lib/shape-manifest.ts. These map to CSS vars that already exist in web/src/styles.css:

  • Accent: var(--channel-<brand>-accent) - primary brand color
  • Soft: var(--channel-<brand>-soft) - tinted background fill
  • Standard row: 52px height, 10px/16px padding, 6px brand dot indicator (not a side stripe)
  • Typography: 14px/500 primary, 13px/400 muted secondary, 14px/600 tabular-nums amount

No side-stripe borders. The impeccable absolute ban applies. Use brand dot indicators instead.

Lint gates (4 new gates, all in state/lint/)

GateWhat it checks
shape-both-library-registration.tsComponent in BOTH genuiLibrary AND canvasLibrary
shape-styles-css-class.ts.snappy-<kebab> CSS class exists in styles.css
shape-name-collision.tsName does not collide with openuiChatLibrary exports
shape-props-schema-strict.tsNo z.any() without SHAPE-ALLOW-ANY comment

AGENTS.md- what the AI loads when this skill comes up

shape-builder - loader

Per-turn rules. Full reference: state/skills/shape-builder/SKILL.md.

Critical Rules

  1. Check DISPATCH_REGISTRY first - grep -n "<Name>" ~/projects/snappy-os-app/apps/snappy-os/web/src/dispatch-card.tsx. If it exists, emit the existing shape.
  1. Name collision is a silent killer - run npx tsx ~/projects/snappy-os/state/lint/shape-name-collision.ts BEFORE writing code. DatePicker, Button, Table, Accordion, etc. all collide with openuiChatLibrary. Prefix with brand name or "Snappy" (e.g. SnappyDatePicker).
  1. All three legs or silent null-render:
  • (a) web/src/genui/<kebab>.tsx - TSX file with View + Component + Args
  • (b) DISPATCH_REGISTRY entry in dispatch-card.tsx (before final };, NEVER inside another shape's parse/render)
  • (c) KNOWN_COMPONENTS string + intent regex + emitTriple in server.ts (BOTH sub-steps)
  1. Both library registrations - add to genuiLibrary.components[] AND canvasLibrary.components[] in genui-library.tsx. Shape in only one library renders in one surface mode and breaks in the other. state/lint/shape-both-library-registration.ts catches this.
  1. 3-line re-export stub only (isolatedModules):
   export { NameView, NameComponent } from "./genui/<kebab>";
   export type { NameArgs } from "./genui/<kebab>";
   import { NameComponent } from "./genui/<kebab>";

Insertion point: after the last import { XyzComponent } from "./genui/xyz"; line, BEFORE export const genuiLibrary. Never inside the object literal.

  1. CSS vars only - var(--text), var(--surface), var(--accent), var(--accent-soft), var(--border), var(--text-secondary), channel tokens (var(--channel-<brand>-accent)). No hex. styles.css class required or shape-styles-css-class lint fails.
  1. Brand design system - brand-row shapes use BRAND_DESIGN_SYSTEM from state/lib/shape-manifest.ts. Height 52px, padding 10px/16px, 6px dot indicator (no side-stripe - impeccable absolute ban).
  1. No z.any() without guard - z.any().optional() for action props is fine (universal exempt). Any other z.any() needs // SHAPE-ALLOW-ANY: <reason> on the preceding line or shape-props-schema-strict fails.
  1. TypeScript gate before commit - cd ~/projects/snappy-os-app/apps/snappy-os/web && npx tsc --noEmit 2>&1 | head -20. Fix all errors first.
  1. Build must exit 0 - cd ~/projects/snappy-os-app/apps/snappy-os && bash scripts/build-app.sh --install 2>&1 | tail -10.
  1. server.ts doesn't hot-reload - after editing: pkill -f "head-screen/server" 2>/dev/null; sleep 1; cd ~/projects/snappy-os && bash state/bin/head-screen/launch.sh &.
  1. Explicit pathspecs, two repos - never git add -A. Stage: snappy-chat (web/src/genui/<file>.tsx web/src/genui-library.tsx web/src/dispatch-card.tsx web/src/styles.css), snappy-os (state/bin/head-screen/server.ts). Separate commits.
  1. Eval row mandatory - append to state/log/evals.ndjson: skill: "shape-builder", score: 1.0 (success) or 0.0 (build failed).

Manifest-driven flow

# 1. Write manifest (copy the template)
cp ~/projects/snappy-os/state/bin/shape-builder/manifest-template.ts /tmp/my-shape.ts
# edit /tmp/my-shape.ts

# 2. Validate
npx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts check /tmp/my-shape.ts

# 3. Generate leg A (TSX) + leg B (genui-library stub)
npx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts apply /tmp/my-shape.ts

# 4. Apply printed snippets for dispatch-card.tsx + server.ts + styles.css

# 5. Run 4 lint gates
npx tsx ~/projects/snappy-os/state/lint/shape-both-library-registration.ts
npx tsx ~/projects/snappy-os/state/lint/shape-name-collision.ts
npx tsx ~/projects/snappy-os/state/lint/shape-styles-css-class.ts
npx tsx ~/projects/snappy-os/state/lint/shape-props-schema-strict.ts

# 6. TypeScript gate
cd ~/projects/snappy-os-app/apps/snappy-os/web && npx tsc --noEmit 2>&1 | head -20

# 7. Build + deploy
cd ~/projects/snappy-os-app/apps/snappy-os && bash scripts/build-app.sh --install

# 8. Auto-verify
bash ~/projects/snappy-os/state/bin/shape-builder/verify.sh ShapeName

# 9. Commit (explicit pathspecs)
# 10. Eval row

Commands

actioncommand
check existinggrep -n "<Name>" ~/projects/snappy-os-app/apps/snappy-os/web/src/dispatch-card.tsx
collision checknpx tsx ~/projects/snappy-os/state/lint/shape-name-collision.ts
validate manifestnpx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts check /tmp/my-shape.ts
generate legsnpx tsx ~/projects/snappy-os/state/bin/shape-builder/apply.ts apply /tmp/my-shape.ts
lint both-librariesnpx tsx ~/projects/snappy-os/state/lint/shape-both-library-registration.ts
lint stylesnpx tsx ~/projects/snappy-os/state/lint/shape-styles-css-class.ts
lint collisionnpx tsx ~/projects/snappy-os/state/lint/shape-name-collision.ts
lint schema-strictnpx tsx ~/projects/snappy-os/state/lint/shape-props-schema-strict.ts
tsc check`cd ~/projects/snappy-os-app/apps/snappy-os/web && npx tsc --noEmit 2>&1head -20`
build + deploy`cd ~/projects/snappy-os-app/apps/snappy-os && bash scripts/build-app.sh --install 2>&1tail -10`
auto-verifybash ~/projects/snappy-os/state/bin/shape-builder/verify.sh <ShapeName>
restart serverpkill -f "head-screen/server" 2>/dev/null; sleep 1; cd ~/projects/snappy-os && bash state/bin/head-screen/launch.sh &
commit snappy-osgit add web/src/genui/<file>.tsx web/src/genui-library.tsx web/src/dispatch-card.tsx web/src/styles.css && git commit -m "shape-builder: add <Name>"
commit snappy-osgit add state/bin/head-screen/server.ts && git commit -m "shape-builder: register <Name>"
eval rowappend state/log/evals.ndjson: {"skill":"shape-builder","shape":"<Name>","score":1.0}

Self-Test

An agent reading this should correctly:

  1. [ ] Check DISPATCH_REGISTRY before generating anything
  2. [ ] Run shape-name-collision lint BEFORE writing code
  3. [ ] Write only CSS vars (no hex/rgb/named colors)
  4. [ ] Use BRAND_DESIGN_SYSTEM for brand-row kind (dot indicator, not side stripe)
  5. [ ] Insert genui-library.tsx stub BEFORE const genuiLibrary, not inside the object
  6. [ ] Insert DISPATCH_REGISTRY entry before final };, not inside another shape's function
  7. [ ] Add BOTH server.ts sub-steps: KNOWN_COMPONENTS string AND intent regex + emitTriple
  8. [ ] Register in BOTH genuiLibrary.components[] AND canvasLibrary.components[]
  9. [ ] Add CSS class to styles.css
  10. [ ] Run all 4 lint gates before TypeScript check
  11. [ ] Run tsc --noEmit and fix all errors before committing
  12. [ ] Run build-app.sh --install and confirm exit 0
  13. [ ] Run verify.sh and confirm PASS
  14. [ ] Commit with explicit pathspecs in two separate repos
  15. [ ] Append eval row to evals.ndjson

Found a gap? Edit this file. <!-- footer-injection-point -->

api.ts- the code it can call

⚠ no api.ts - this skill has no typed action surface

scripts- helper scripts it can run

prose-only skill - 10 inline code blocks live in SKILL.md above (no state/bin/ sidecar yet).

how we check it- the checks, plus the last 10 runs

rubric shape schema-shape check (no inline rubric)
recent no runs actor/auditor: unverifiable
deps none declared

no recent runs logged - the eval contract is declared but nothing has been graded yet