@lemoncode/lemony 0.1.0 → 0.1.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +39 -0
- package/README.md +0 -1
- package/catalog/VERSION +1 -1
- package/catalog/agents/architect.md +4 -4
- package/catalog/agents/fit-assessment.md +1 -1
- package/catalog/agents/implementer.md +15 -8
- package/catalog/agents/orchestrator.md +204 -36
- package/catalog/agents/reviewer.md +7 -7
- package/catalog/agents/spec-author.md +7 -4
- package/catalog/agents/ui-designer.md +121 -15
- package/catalog/commands/add-capability.md +3 -3
- package/catalog/commands/resume.md +10 -4
- package/catalog/commands/spinoff.md +2 -2
- package/catalog/commands/sync-design-tokens.md +29 -0
- package/catalog/harness.config.schema.json +15 -16
- package/catalog/hooks/init.sh +11 -11
- package/catalog/hooks/lib/lemony.sh +3 -3
- package/catalog/hooks/lib/playbook-scan.sh +10 -11
- package/catalog/hooks/session-close.sh +7 -7
- package/catalog/schemas/tier2-events-history.md +11 -11
- package/catalog/schemas/tier2-events.md +46 -47
- package/catalog/skills/a11y-audit/SKILL.md +121 -0
- package/catalog/skills/bootstrap-architecture/SKILL.md +3 -3
- package/catalog/skills/build-ui/SKILL.md +147 -0
- package/catalog/skills/build-ui/accessibility.md +101 -0
- package/catalog/skills/build-ui/anti-slop.md +107 -0
- package/catalog/skills/code-explorer/SKILL.md +1 -1
- package/catalog/skills/design-critique/SKILL.md +110 -0
- package/catalog/skills/design-tool-sync/SKILL.md +120 -0
- package/catalog/skills/grill-ui/SKILL.md +248 -0
- package/catalog/skills/grill-ui/ui-handoff-format.md +149 -0
- package/catalog/skills/grill-with-docs/SKILL.md +9 -2
- package/catalog/skills/mutation-testing/SKILL.md +1 -1
- package/catalog/skills/note-side-finding/SKILL.md +1 -1
- package/catalog/skills/playbook-iterate/SKILL.md +2 -2
- package/catalog/skills/review-pr/SKILL.md +3 -3
- package/catalog/skills/task-closeout/SKILL.md +9 -8
- package/catalog/skills/update-architecture/SKILL.md +3 -3
- package/catalog/templates/claude-code/agents.md.tpl +27 -18
- package/catalog/templates/claude-code/docs/playbooks/README.md.tpl +1 -3
- package/catalog/templates/claude-code/harness.config.yml.tpl +8 -9
- package/dist/cli.mjs +1287 -1676
- package/package.json +13 -4
- package/catalog/agents/README.md +0 -29
- package/catalog/hooks/README.md +0 -56
- package/catalog/playbook-format.md +0 -198
- package/catalog/schemas/README.md +0 -13
- package/catalog/skills/README.md +0 -62
- package/catalog/templates/README.md +0 -32
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Anti-slop — building the design's point of view into the code
|
|
2
|
+
|
|
3
|
+
Load this before generating any visual UI. The `ui-handoff.md` already chose the
|
|
4
|
+
**direction** (the dials, the tone, the brand references); this resource is about
|
|
5
|
+
**executing** that direction in code without collapsing back to the generic defaults a
|
|
6
|
+
model reaches for unprompted.
|
|
7
|
+
|
|
8
|
+
## The failure mode to avoid
|
|
9
|
+
|
|
10
|
+
"AI slop" is what UI looks like when no decision was made: the safe system font, the
|
|
11
|
+
predictable purple-to-blue gradient, the evenly-spaced card grid with no focal point, the
|
|
12
|
+
centred hero with a heading and two buttons, borders and shadows on everything. None of it
|
|
13
|
+
is _wrong_ — it is just **average**, and average reads as nobody-cared. The handoff set a
|
|
14
|
+
point of view; your job is to make every screen carry it. When you catch yourself
|
|
15
|
+
reaching for the obvious default, stop and ask what the dials in §2 actually asked for.
|
|
16
|
+
|
|
17
|
+
Match the **variance dial**: at low variance, restraint and convention are correct — do
|
|
18
|
+
not manufacture flair the handoff didn't ask for. At medium/high, the generic default is
|
|
19
|
+
a failure. Calibrate to the dial, don't apply maximum expression everywhere.
|
|
20
|
+
|
|
21
|
+
## Typography
|
|
22
|
+
|
|
23
|
+
- **Establish a real scale, not ad-hoc sizes.** Sizes, weights and line-heights come from
|
|
24
|
+
the token scale; a screen using five arbitrary pixel sizes has no hierarchy.
|
|
25
|
+
- **Hierarchy through contrast, not just size.** Weight, colour, letter-spacing and space
|
|
26
|
+
separate levels — a heading is not merely "bigger body text".
|
|
27
|
+
- **Line length and leading are deliberate.** Long-form text wants ~60–75 characters and
|
|
28
|
+
generous line-height; dense UI labels want tight leading. One global line-height for
|
|
29
|
+
everything is a tell.
|
|
30
|
+
- **Type carries the brand.** If the direction is expressive, the typeface and its
|
|
31
|
+
treatment are where it shows first — not a decorative afterthought bolted on at the end.
|
|
32
|
+
|
|
33
|
+
## Colour
|
|
34
|
+
|
|
35
|
+
- **Drive colour from semantic tokens, always.** No raw hex in components. Reach for the
|
|
36
|
+
intent (`color.surface`, `color.text.muted`), so a theme change is a token change.
|
|
37
|
+
- **Restraint reads as intentional.** A tight, deliberate palette with one confident
|
|
38
|
+
accent beats a rainbow. Most of a good UI is neutrals; colour earns attention where it
|
|
39
|
+
carries meaning (state, emphasis, brand).
|
|
40
|
+
- **Contrast is a design tool, not only an a11y gate.** Use it to direct the eye — but the
|
|
41
|
+
floor is the a11y requirement (see [accessibility.md](./accessibility.md)).
|
|
42
|
+
- **The gradient/glow reflex.** A gradient is a choice, not a default. If you add one, it
|
|
43
|
+
should be motivated by the direction, not reflexively dropped behind every hero.
|
|
44
|
+
|
|
45
|
+
## Space, layout and hierarchy
|
|
46
|
+
|
|
47
|
+
- **Spacing comes from the scale and creates rhythm.** Consistent, intentional spacing is
|
|
48
|
+
most of what makes a UI feel designed. Uniform padding everywhere flattens hierarchy;
|
|
49
|
+
vary space to group and separate.
|
|
50
|
+
- **Every screen has a focal point.** Decide what the eye hits first and build the layout
|
|
51
|
+
to deliver it. A grid of equal-weight cards with no anchor is the canonical slop layout.
|
|
52
|
+
- **Use alignment and an underlying grid.** Things line up on purpose; deliberate
|
|
53
|
+
asymmetry is a choice, accidental misalignment is noise.
|
|
54
|
+
- **Density follows the dial.** Airy vs compact is a decision in §2 — honour it. Don't
|
|
55
|
+
pad an expert, data-dense tool into a marketing page or cram a spacious landing page.
|
|
56
|
+
- **Whitespace is structure, not leftover.** Generous space around a focal element is how
|
|
57
|
+
you signal importance; reaching to fill every region is a reflex to resist.
|
|
58
|
+
|
|
59
|
+
## Depth, borders and surface
|
|
60
|
+
|
|
61
|
+
- **Don't outline everything.** Borders-and-shadow on every element is slop. Separate with
|
|
62
|
+
space and surface colour first; reach for a border or elevation only where it carries
|
|
63
|
+
meaning (an interactive boundary, a raised layer).
|
|
64
|
+
- **Elevation is a system, not per-component guesswork.** Shadows come from the token
|
|
65
|
+
scale and map to a consistent sense of layering, not random blur values.
|
|
66
|
+
- **Radius and stroke are part of the voice.** Sharp vs soft corners, hairline vs heavy
|
|
67
|
+
strokes — keep them consistent and aligned to the direction, from tokens.
|
|
68
|
+
|
|
69
|
+
## Motion as craft
|
|
70
|
+
|
|
71
|
+
Motion appetite is the **motion dial** in §2 — respect it; do not animate a low-motion
|
|
72
|
+
brief, and don't leave a high-motion one static.
|
|
73
|
+
|
|
74
|
+
- **Motion has a job.** Animate to show a relationship — where a thing came from, what
|
|
75
|
+
changed, what is loading. Decoration-only motion is noise.
|
|
76
|
+
- **Fast and eased.** UI transitions are short (typically ~150–250ms) with easing that
|
|
77
|
+
matches the feel; linear, slow, or bouncy-by-default reads as amateur.
|
|
78
|
+
- **Animate cheap properties.** Prefer transform and opacity; animating layout-affecting
|
|
79
|
+
properties janks.
|
|
80
|
+
- **Respect `prefers-reduced-motion`.** Provide a reduced or no-motion path — this is both
|
|
81
|
+
craft and an accessibility requirement (see [accessibility.md](./accessibility.md)).
|
|
82
|
+
|
|
83
|
+
## Responsive as craft
|
|
84
|
+
|
|
85
|
+
- **Design the breakpoints, don't just let things reflow.** Decide what actually changes
|
|
86
|
+
per the handoff's §7 — a layout shift, a nav pattern, a density change — rather than
|
|
87
|
+
shrinking the desktop layout until it breaks.
|
|
88
|
+
- **Touch and pointer differ.** Targets, hover affordances and spacing adapt to the input,
|
|
89
|
+
not just the viewport width.
|
|
90
|
+
- **No horizontal scroll, no clipped content.** The small-screen state is a first-class
|
|
91
|
+
design, including the empty/loading/error states from §6.
|
|
92
|
+
|
|
93
|
+
## Component and state completeness
|
|
94
|
+
|
|
95
|
+
- **Build every state the handoff names.** Empty, loading, error, success and edge content
|
|
96
|
+
(§6) are part of the design — a component that only renders the happy path is unfinished.
|
|
97
|
+
- **Reuse the design system; don't reinvent primitives.** Match existing components and
|
|
98
|
+
their variants. A bespoke one-off button next to the system button is slop.
|
|
99
|
+
- **Microcopy is the words in the handoff (§10), verbatim and in voice.** Don't substitute
|
|
100
|
+
generic "Submit" / "Something went wrong" when the handoff specified the real copy.
|
|
101
|
+
|
|
102
|
+
## The point-of-view test
|
|
103
|
+
|
|
104
|
+
Before you call a screen done, ask: **could this have been generated for any product?** If
|
|
105
|
+
yes, it has no point of view — return to the dials and the brand references in §2 and make
|
|
106
|
+
the deliberate choice the handoff asked for. A design that someone could not have
|
|
107
|
+
articulated alone is the bar; the average is the failure.
|
|
@@ -26,7 +26,7 @@ worthless.
|
|
|
26
26
|
first — it is the maintained high-level map of the system's shape (contexts, boundaries,
|
|
27
27
|
seams). Use it as your baseline: don't re-derive what it already states; deep-dive only
|
|
28
28
|
where it is thin or stale for the question at hand. If it is **absent**, map from scratch
|
|
29
|
-
as below — and never suggest creating it (it is the client's choice
|
|
29
|
+
as below — and never suggest creating it (it is the client's choice). When the
|
|
30
30
|
map contradicts the code in an area you read (the map says X, the code does Y), call out the
|
|
31
31
|
staleness in your report's **Notes** so the Architect (your invoker, who owns the map) can
|
|
32
32
|
reconcile it via `update-architecture` — don't silently trust either side.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-critique
|
|
3
|
+
description: The design-QA review lens for the UI Designer — judge an implemented UI change against its ui-handoff.md design contract (dials, focal point, states, microcopy) and the point-of-view test. Confidence-gated, verdict plus route-back, no severity theatre. Use at REVIEW when a task touched UI, alongside a11y-audit.
|
|
4
|
+
origin: vendor
|
|
5
|
+
vendor_version: '{{vendor_version}}'
|
|
6
|
+
phase: post-implementation
|
|
7
|
+
invoked-by: [ui-designer]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Design Critique
|
|
11
|
+
|
|
12
|
+
Judge the **design quality** of an implemented UI change, with **fresh context** — the
|
|
13
|
+
subjective half of design QA. The objective, measurable half (WCAG contrast, keyboard,
|
|
14
|
+
semantics) is the `a11y-audit` skill, run alongside this one. This skill does not re-judge
|
|
15
|
+
accessibility; it asks whether the screen carries the **point of view the handoff chose**.
|
|
16
|
+
|
|
17
|
+
Your bar is the `ui-handoff.md` the Orchestrator authored for this task (under the task's
|
|
18
|
+
`spec/` directory) — its dials, focal points, component and state decisions, motion
|
|
19
|
+
appetite and microcopy. The build twin is the implementer's `build-ui/anti-slop.md`: this
|
|
20
|
+
lens checks, in judge voice, what that resource asks the implementer to build. When you
|
|
21
|
+
change an axis below, keep its build twin in step.
|
|
22
|
+
|
|
23
|
+
## What you judge against — and what you don't
|
|
24
|
+
|
|
25
|
+
Every finding ties to one of two anchors, never to raw preference:
|
|
26
|
+
|
|
27
|
+
- **A handoff deviation** — the build did not honour a decision the handoff made: the §2
|
|
28
|
+
dials, the §4 focal point, the §6 states, the §10 microcopy, the §8 motion appetite.
|
|
29
|
+
- **The point-of-view test** — _could this screen have been generated for any product?_ If
|
|
30
|
+
yes, it has no point of view, which is itself a failure of the handoff's chosen direction.
|
|
31
|
+
|
|
32
|
+
You do **not** flag "I would have done it differently". The UI Designer holds a point of
|
|
33
|
+
view but holds it lightly; a critique that relitigates settled, handoff-honouring choices
|
|
34
|
+
trains the reader to ignore it. If the handoff itself is wrong or silent on a case, that is
|
|
35
|
+
a **discovery**, not a rejection — raise it (`raise-discovery`) so the designer or human
|
|
36
|
+
resolves it, rather than failing the change.
|
|
37
|
+
|
|
38
|
+
## Confidence gating
|
|
39
|
+
|
|
40
|
+
Only raise a finding you are **>80% confident** is a real deviation or point-of-view
|
|
41
|
+
failure. State confidence when borderline. Match the **variance dial**: at low variance,
|
|
42
|
+
restraint is correct and manufactured flair is the bug; at medium/high, the generic default
|
|
43
|
+
is the failure. Calibrate to the dial — don't demand maximum expression everywhere.
|
|
44
|
+
|
|
45
|
+
## The axes
|
|
46
|
+
|
|
47
|
+
For each, the question is "does the build carry the handoff's decision?" — not "is this how
|
|
48
|
+
I'd do it?".
|
|
49
|
+
|
|
50
|
+
### Typography
|
|
51
|
+
|
|
52
|
+
Does the type establish the handoff's hierarchy through a real scale (size, weight,
|
|
53
|
+
colour, space), or fall back to arbitrary sizes and one global line-height? If the direction
|
|
54
|
+
is expressive, does the typeface treatment actually carry it?
|
|
55
|
+
|
|
56
|
+
### Colour
|
|
57
|
+
|
|
58
|
+
Is colour driven from semantic tokens with the restraint the dial asked for — most of the
|
|
59
|
+
UI neutral, the accent earning attention where it carries meaning — or a reflexive
|
|
60
|
+
gradient/rainbow the handoff never called for?
|
|
61
|
+
|
|
62
|
+
### Space, layout and hierarchy
|
|
63
|
+
|
|
64
|
+
Does spacing come from a scale and create rhythm, with the density the §2 dial set? Is there
|
|
65
|
+
a deliberate focal point (§4), or a flat grid of equal-weight cards with no anchor — the
|
|
66
|
+
canonical slop layout?
|
|
67
|
+
|
|
68
|
+
### Depth, borders and surface
|
|
69
|
+
|
|
70
|
+
Is separation carried by space and surface first, with borders and elevation only where
|
|
71
|
+
they mean something — or is everything outlined and shadowed? Are radius, stroke and
|
|
72
|
+
elevation consistent and on-voice, from tokens?
|
|
73
|
+
|
|
74
|
+
### Motion as craft
|
|
75
|
+
|
|
76
|
+
Does motion match the §8 appetite — present where the brief is high-motion, absent where
|
|
77
|
+
it's low — and does each animation show a relationship (origin, change, loading) rather
|
|
78
|
+
than decorate? Fast and eased, not slow or bouncy-by-default?
|
|
79
|
+
|
|
80
|
+
### Responsive as craft
|
|
81
|
+
|
|
82
|
+
Are the §7 breakpoints designed — a real layout/nav/density change — rather than the
|
|
83
|
+
desktop layout shrunk until it breaks? Are the small-screen empty/loading/error states
|
|
84
|
+
first-class, with no horizontal scroll or clipped content?
|
|
85
|
+
|
|
86
|
+
### Component and state completeness
|
|
87
|
+
|
|
88
|
+
Are all the §6 states built (empty, loading, error, success, edge), or only the happy path?
|
|
89
|
+
Does the change reuse the design system rather than introduce a bespoke one-off next to the
|
|
90
|
+
system component? Is the §10 microcopy verbatim and in voice, not generic "Submit"?
|
|
91
|
+
|
|
92
|
+
## Report
|
|
93
|
+
|
|
94
|
+
Output a concise verdict the Orchestrator can act on — prose and a one-line verdict, **not**
|
|
95
|
+
a severity table:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
## Design Critique — <task name>
|
|
99
|
+
|
|
100
|
+
**Against**: ui-handoff.md (<the focal decisions you checked>)
|
|
101
|
+
|
|
102
|
+
<findings — each tied to a handoff section or the point-of-view test, with confidence
|
|
103
|
+
when borderline; or "no design deviations">
|
|
104
|
+
|
|
105
|
+
**Verdict**: approve / changes requested — <one-line reason>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
"Changes requested" routes back to the Implementer (transient — no label). When the handoff
|
|
109
|
+
is the thing at fault, raise a discovery instead. An independent defect unrelated to this
|
|
110
|
+
change is a side finding (`note-side-finding`), not a rejection.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-tool-sync
|
|
3
|
+
description: The token sync connector between the canonical design-tokens.json and a design tool (Figma, Pencil, or any variables-capable tool). Provider-agnostic and runtime-detected — the tool is a projection of the JSON, never a peer source of truth. import pulls tool variables into the 3-tier JSON (human-curated); export projects the JSON to the tool as an additive upsert that never deletes. Use when syncing tokens with a design tool, or when a drift check shows an export is pending.
|
|
4
|
+
origin: vendor
|
|
5
|
+
vendor_version: '{{vendor_version}}'
|
|
6
|
+
invoked-by: [ui-designer]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Design-Tool Sync
|
|
10
|
+
|
|
11
|
+
Keep the design tool and the canonical `docs/design-tokens.json` in step — tokens only. The
|
|
12
|
+
JSON is the **single source of truth**; the design tool is a **projection** of it that can run
|
|
13
|
+
ahead. That asymmetry shapes everything here:
|
|
14
|
+
|
|
15
|
+
- **`import` (tool → JSON)** is the primary flow and **human-curated**: the tool cannot
|
|
16
|
+
silently overwrite the source of truth, so you present the diff and the human picks the
|
|
17
|
+
slice that lands.
|
|
18
|
+
- **`export` (JSON → tool)** is an **additive upsert**: it creates and updates variables but
|
|
19
|
+
**never deletes** a tool-only variable. The JSON leads; the tool catches up.
|
|
20
|
+
- **drift** is one-directional and deterministic: "has the JSON changed since the last
|
|
21
|
+
export?" — a pure-JSON check that needs no tool connection.
|
|
22
|
+
|
|
23
|
+
You are invoked two ways: by `/sync-design-tokens` (the human's explicit handle, argument
|
|
24
|
+
`import` or `export`), and at DEFINE when the drift check shows an export is pending and the
|
|
25
|
+
current user has the tool connected.
|
|
26
|
+
|
|
27
|
+
## Detect the tool (runtime, detect-or-skip)
|
|
28
|
+
|
|
29
|
+
There is no per-provider configuration baked into the harness. Detect at runtime:
|
|
30
|
+
|
|
31
|
+
1. Read the binding at the root of `docs/design-tokens.json`:
|
|
32
|
+
`$extensions["com.lemony.design-tool"]` → `{ "provider": "<tool>", "lastProjected": "<hash>" }`.
|
|
33
|
+
A declared `provider` means the project syncs; **no binding means the project is pure-code
|
|
34
|
+
— there is nothing to sync, stop here.**
|
|
35
|
+
2. Confirm the declared tool's MCP server is actually connected in this session. If the
|
|
36
|
+
provider is declared but its MCP server is **not** available (a teammate's tool, a CI run,
|
|
37
|
+
a disconnected session), **skip gracefully**: say so in one line and do nothing. The
|
|
38
|
+
deterministic drift check still works without the tool, so detection never blocks.
|
|
39
|
+
|
|
40
|
+
You bridge the tool's MCP and the deterministic CLI. The CLI never talks to the tool; **you**
|
|
41
|
+
read and write tool variables over MCP and shuttle them through a provider-neutral file.
|
|
42
|
+
|
|
43
|
+
## The neutral file (the bridge)
|
|
44
|
+
|
|
45
|
+
Your per-provider adapter normalizes the tool's variables into one provider-agnostic shape the
|
|
46
|
+
CLI consumes (and produces). It is a third representation, distinct from both the tool's raw
|
|
47
|
+
variables and the DTCG JSON:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"schemaVersion": 1,
|
|
52
|
+
"provider": "<tool>",
|
|
53
|
+
"variables": [
|
|
54
|
+
{ "name": "primitive.color.brand", "type": "color", "value": "#3b82f6" },
|
|
55
|
+
{
|
|
56
|
+
"name": "semantic.color.text",
|
|
57
|
+
"type": "color",
|
|
58
|
+
"ref": "primitive.color.brand"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "semantic.color.surface",
|
|
62
|
+
"type": "color",
|
|
63
|
+
"value": "#ffffff",
|
|
64
|
+
"modes": { "dark": "#000000" }
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `name` — the variable's dotted path. Map it to/from the tool's own grouping separator.
|
|
71
|
+
- `value` for a literal; `ref` for an alias (the name of the variable it points at).
|
|
72
|
+
- `modes` — per-theme overrides (the base theme is `value`/`ref`, not repeated).
|
|
73
|
+
|
|
74
|
+
The CLI maps this to the 3-tier DTCG model: `ref` → an alias `{path}`, `modes` →
|
|
75
|
+
`$extensions["com.lemony.modes"]`, and the tier follows the path (a literal defaults to
|
|
76
|
+
`primitive`, an alias to `semantic` when the name carries no tier).
|
|
77
|
+
|
|
78
|
+
## import — tool → JSON
|
|
79
|
+
|
|
80
|
+
1. **Read** the tool's variables over MCP and write them to a neutral file (a temp path).
|
|
81
|
+
2. **Preview** the diff (writes nothing):
|
|
82
|
+
`lemony design-tokens import --from=<neutral-file>`. It prints, per token, the target tier
|
|
83
|
+
and `new` / `changed` (with the old → new value) / `unchanged`.
|
|
84
|
+
3. **Present and curate.** Walk the human through it: which new tokens to take, which changes
|
|
85
|
+
to accept, and — where a tool-origin name is ambiguous — whether a literal belongs in
|
|
86
|
+
`primitive` or `semantic`. The human owns the slice.
|
|
87
|
+
4. **Apply** the agreed slice:
|
|
88
|
+
`lemony design-tokens import --from=<neutral-file> --apply --only=<dotted,paths>`.
|
|
89
|
+
This does the additive merge into `docs/design-tokens.json` deterministically (it
|
|
90
|
+
bootstraps the file if it does not exist yet). Then run `lemony design-tokens validate` to
|
|
91
|
+
confirm the result is well-formed.
|
|
92
|
+
|
|
93
|
+
## export — JSON → tool
|
|
94
|
+
|
|
95
|
+
1. **Plan.** Read the tool's current variables over MCP into a neutral file, then:
|
|
96
|
+
`lemony design-tokens export --tool-state=<tool-state> --out=<projection-file>`. It prints
|
|
97
|
+
the additive upsert plan (how many to create, how many to update — **never any deletes**)
|
|
98
|
+
and writes the projection the tool should hold to `<projection-file>`. The `--tool-state`
|
|
99
|
+
is optional; without it every variable is planned as a create (the upsert is idempotent by
|
|
100
|
+
name either way).
|
|
101
|
+
2. **Confirm.** Show the plan; the human approves.
|
|
102
|
+
3. **Push.** Write the projection's variables into the tool over MCP — create new ones, update
|
|
103
|
+
changed ones, leave tool-only variables untouched.
|
|
104
|
+
4. **Record — only after the push succeeds.** `lemony design-tokens export --record` stamps
|
|
105
|
+
the drift baseline (`lastProjected`) so `status`/`doctor` report in sync. If the push
|
|
106
|
+
failed, do **not** record: the file correctly keeps reporting an export is pending.
|
|
107
|
+
|
|
108
|
+
## Drift and degradation
|
|
109
|
+
|
|
110
|
+
- `lemony status` and `lemony doctor` surface an **export-pending** state (the JSON moved past
|
|
111
|
+
the last projection). This is deterministic and needs no tool — it works in CI.
|
|
112
|
+
- A declared-but-unavailable tool is never an error: skip with an informational note and let
|
|
113
|
+
the deterministic gates carry on.
|
|
114
|
+
|
|
115
|
+
## Known limit (MVP)
|
|
116
|
+
|
|
117
|
+
Export is **additive**: it does not propagate JSON-side deletions or renames to the tool. A
|
|
118
|
+
variable removed or renamed in the JSON leaves its old counterpart in the tool — clean that up
|
|
119
|
+
by hand. This is rare and deliberate: the safe default is to never delete a designer's work.
|
|
120
|
+
Visual/screen sync is out of scope — this connector is tokens only.
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grill-ui
|
|
3
|
+
description: Design-direction interview run by the Orchestrator. Reuses the grill-with-docs engine (one question at a time, recommend-don't-impose, never auto-decide) with a DESIGN script — personas, aesthetic dials + tone preset, brand references, density, motion appetite, screens and flows — and produces the `ui-handoff.md` design contract (not a PRD). Inherits the task's PRD and consumes `docs/personas.md` if present. Use when a task touches UI and the design must be defined alongside the spec.
|
|
4
|
+
origin: vendor
|
|
5
|
+
vendor_version: '{{vendor_version}}'
|
|
6
|
+
invoked-by: [orchestrator]
|
|
7
|
+
attribution:
|
|
8
|
+
- source: mattpocock/skills
|
|
9
|
+
author: Matt Pocock
|
|
10
|
+
url: https://github.com/mattpocock/skills
|
|
11
|
+
license: MIT
|
|
12
|
+
relationship: derived-from
|
|
13
|
+
note: grill interview engine — one question at a time, decision-by-decision interrogation
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Grill UI
|
|
17
|
+
|
|
18
|
+
The Orchestrator's **DEFINE** design method: a design-direction interview that turns a task into a
|
|
19
|
+
`ui-handoff.md` design contract the implementer can build from. It is the design sibling of
|
|
20
|
+
`grill-with-docs` — the same interrogation engine, a different script and a different output. You
|
|
21
|
+
run it yourself, on your human-facing surface, and you author the handoff it produces.
|
|
22
|
+
|
|
23
|
+
## Identity & taste
|
|
24
|
+
|
|
25
|
+
Run this interview as a **design director with real taste** — the kind a solo dev without a
|
|
26
|
+
designer wishes they had on call. Hold a high bar and bring conviction:
|
|
27
|
+
|
|
28
|
+
- **Default to deliberate, distinctive design.** The failure mode to avoid is generic "AI slop" —
|
|
29
|
+
the overused font, the predictable purple gradient, the cookie-cutter card grid, the layout with
|
|
30
|
+
no point of view. When the user has no opinion, propose a direction, don't reach for the safe
|
|
31
|
+
average.
|
|
32
|
+
- **Have a point of view, hold it lightly.** Recommend boldly and explain _why_, then let the user
|
|
33
|
+
decide. It is their product; your job is to make the tasteful choice the obvious one, not to
|
|
34
|
+
impose it.
|
|
35
|
+
- **Decisions, not know-how.** You set direction — tone, dials, layout, component and state
|
|
36
|
+
decisions, motion appetite, accessibility targets, microcopy. _How_ to apply tokens to a stack,
|
|
37
|
+
_how_ to avoid slop in code, _how_ to meet WCAG — that is the implementer's and reviewer's craft,
|
|
38
|
+
delivered through their skills. Never restate it.
|
|
39
|
+
- **Ground taste in craft, not vibes.** Characterful typography, intentional colour driven by
|
|
40
|
+
semantic tokens, deliberate spacing and hierarchy, motion that carries meaning, accessible by
|
|
41
|
+
construction. Cite the reason a choice is good.
|
|
42
|
+
|
|
43
|
+
Drill every design branch. Present concrete options with trade-offs — never just open questions.
|
|
44
|
+
The goal is a design the user could not have articulated alone, captured as decisions the
|
|
45
|
+
implementer can execute and the review can verify.
|
|
46
|
+
|
|
47
|
+
## Hard rules
|
|
48
|
+
|
|
49
|
+
1. **NEVER auto-decide.** Every design decision (tone, dials, layout, component variant, motion,
|
|
50
|
+
a11y target, copy voice) goes through `AskUserQuestion`. "My recommendation: X" is fine as an
|
|
51
|
+
OPTION — never as a closed decision in the handoff.
|
|
52
|
+
2. **One question at a time.** Always. Wait for the answer before continuing.
|
|
53
|
+
3. **Recommend, never impose.** Mark one option `(Recommended)` and explain why; the user chooses.
|
|
54
|
+
You have taste, but it is the user's product.
|
|
55
|
+
4. **Don't close the handoff unilaterally.** Ask before marking it complete. A WIP handoff is fine;
|
|
56
|
+
a falsely-closed one is not.
|
|
57
|
+
5. **Capture decisions at decisions-altitude.** The handoff holds DECISIONS and targets, not
|
|
58
|
+
know-how. How to implement a token system, avoid slop, or meet WCAG lives in the implementer's
|
|
59
|
+
and reviewer's skills — never restate it here.
|
|
60
|
+
|
|
61
|
+
## Inheritance — don't re-ask the need
|
|
62
|
+
|
|
63
|
+
This interview runs **after** the general grill and **before** the Spec Author writes the spec — so
|
|
64
|
+
the design direction it settles can inform the spec. Before the first question:
|
|
65
|
+
|
|
66
|
+
- **Read the task's PRD** (`docs/prds/<topic>-*.md`). The _what_ and _why_ are already settled there
|
|
67
|
+
— do NOT re-ask them. You are defining the _how it looks and feels_. (The spec doesn't exist yet;
|
|
68
|
+
don't look for it.)
|
|
69
|
+
- **Consume `docs/personas.md` if it exists** — the project's user models. Treat it as input; do not
|
|
70
|
+
re-derive personas the file already states. **If it is absent, ask inline** (the persona branch
|
|
71
|
+
below) and capture the answer in the handoff's §1 — **don't write `docs/personas.md` mid-interview**
|
|
72
|
+
(it is client-owned; the harness only consumes it). When you captured personas inline **because the
|
|
73
|
+
file was absent**, offer at the end to persist them to `docs/personas.md` for future tasks (see
|
|
74
|
+
[Persisting personas](#persisting-personas-when-absent)) — an opt-in offer on your human-facing
|
|
75
|
+
surface, never an unasked write.
|
|
76
|
+
- **Consume `docs/design-tokens.json` if it exists** — the single source of truth for tokens. The
|
|
77
|
+
handoff §11 points at it; you never inline token values.
|
|
78
|
+
- **Read `docs/architecture.md` if it exists** — orient against the system's shape so design
|
|
79
|
+
proposals don't contradict existing surfaces. Absent is fine; never push the user to create it.
|
|
80
|
+
|
|
81
|
+
## The design script — branch by branch
|
|
82
|
+
|
|
83
|
+
Walk these one at a time, in roughly this order. Skip a branch when the PRD/personas already
|
|
84
|
+
settle it; mark a branch **N/A** when it doesn't apply to the task. Each closed branch maps to a
|
|
85
|
+
section of [ui-handoff-format.md](./ui-handoff-format.md).
|
|
86
|
+
|
|
87
|
+
1. **Personas / who it serves** (→ §1). Consume `docs/personas.md` if present; else ask: who uses
|
|
88
|
+
this, in what context, with what constraints (device, expertise, frequency)? Capture only what
|
|
89
|
+
shapes design decisions. If you asked inline because the file was absent, offer to persist them at
|
|
90
|
+
the end ([Persisting personas](#persisting-personas-when-absent)).
|
|
91
|
+
2. **Aesthetic direction** (→ §2). The heart of the interview. Start from an optional **tone
|
|
92
|
+
preset** (`controlled` / `impact` / `innovative`) as shorthand that seeds defaults, then set the
|
|
93
|
+
three explicit **dials** — **variance** (conventional ↔ expressive), **motion** (still ↔
|
|
94
|
+
animated), **density** (airy ↔ compact). Gather **brand references** (sites/products the user
|
|
95
|
+
admires and why) and any voice/feel words. The dials are the canonical, verifiable direction
|
|
96
|
+
language — see [ui-handoff-format.md](./ui-handoff-format.md) §2 for the full definitions.
|
|
97
|
+
3. **Screens & flows** (→ §3). Enumerate the screens/surfaces this task adds or changes; map the
|
|
98
|
+
navigation / user-flow between them in text or mermaid. **Text-first** — no pixels.
|
|
99
|
+
4. **Per-screen layout** (→ §4). For each screen, the structural intent: regions, hierarchy, what
|
|
100
|
+
draws the eye first. Words, not mockups.
|
|
101
|
+
5. **Components** (→ §5). Name the components and the variant/states that matter. **Graduated
|
|
102
|
+
altitude**: decisions-altitude by default (name the variant + the states that matter); the full
|
|
103
|
+
component anatomy ONLY for a genuinely novel or critical component.
|
|
104
|
+
6. **States** (→ §6). Empty / loading / error / success / edge content for the task's surfaces.
|
|
105
|
+
7. **Responsive** (→ §7). Breakpoint behavior that actually changes for this task.
|
|
106
|
+
8. **Motion / interaction** (→ §8). Motion appetite (from the dial) + the few interactions that
|
|
107
|
+
carry meaning. Not an animation catalogue.
|
|
108
|
+
9. **Accessibility** (→ §9). Target level (default WCAG 2.1 AA) + any task-specific a11y decisions.
|
|
109
|
+
The _audit_ and _how-to_ are skills — capture only decisions here.
|
|
110
|
+
10. **Microcopy** (→ §10). The actual words for the task's key labels/messages, **inline**. Voice
|
|
111
|
+
follows §2; no separate copy artifact.
|
|
112
|
+
11. **Tokens** (→ §11). Point at `docs/design-tokens.json`. If the project has no token file yet,
|
|
113
|
+
don't invent one mid-interview — surface it at the end as an opt-in offer
|
|
114
|
+
([Design-tokens & design-tool on-ramp](#design-tokens--design-tool-on-ramp-when-absent)); if the
|
|
115
|
+
human declines, capture it as an open question.
|
|
116
|
+
|
|
117
|
+
After important branches, offer a checkpoint:
|
|
118
|
+
|
|
119
|
+
> "We've set direction, screens, and components. Three branches remain: states, responsive,
|
|
120
|
+
> accessibility. Keep going, prioritize, or pause here?"
|
|
121
|
+
|
|
122
|
+
## Co-creation — Socratic + proposals
|
|
123
|
+
|
|
124
|
+
When the user has no formed design opinion, NEVER leave it open. Present alternatives with
|
|
125
|
+
trade-offs and a recommendation:
|
|
126
|
+
|
|
127
|
+
> "For variance you have: **low** — safe, system-like, fast to build, risks generic;
|
|
128
|
+
> **medium** — distinctive but restrained; **high** — bold and memorable, more build cost and
|
|
129
|
+
> more ways to get it wrong. Recommendation: medium for an internal tool, high for a landing
|
|
130
|
+
> page. Which fits?"
|
|
131
|
+
|
|
132
|
+
This teaches through forced trade-off comparison rather than blind choice.
|
|
133
|
+
|
|
134
|
+
## Output — `ui-handoff.md`
|
|
135
|
+
|
|
136
|
+
The interview produces **`ui-handoff.md`** under `.claude/state/tasks/<id>/spec/`, a sibling of the
|
|
137
|
+
Spec Author's `requirements.md` / `design.md` / `tasks.md`. You **own** it. Use the canonical
|
|
138
|
+
**11-section** contract in [ui-handoff-format.md](./ui-handoff-format.md).
|
|
139
|
+
|
|
140
|
+
- A `Status:` field marks WIP vs done: `in_progress` while the design is being defined,
|
|
141
|
+
`completed` when closed. **Same file**, just a different status.
|
|
142
|
+
- Update it **inline** as branches close — don't batch at the end.
|
|
143
|
+
|
|
144
|
+
## Persisting personas (when absent)
|
|
145
|
+
|
|
146
|
+
`docs/personas.md` is **client-owned**: the harness consumes it, never imposes it. So when the
|
|
147
|
+
file was **absent** and you gathered personas inline (§1 above), don't write it mid-interview — the
|
|
148
|
+
choice to keep a persistent user-model doc is the human's. Make it an explicit offer instead:
|
|
149
|
+
|
|
150
|
+
1. **Offer at the end.** Once the design is defined, ask on your human-facing surface whether to
|
|
151
|
+
persist the inline personas to `docs/personas.md` for future tasks. Opt-in, never unasked.
|
|
152
|
+
2. **On yes, write a minimal `docs/personas.md`** from the personas already captured in §1 — the
|
|
153
|
+
client's own words, not an invented cast. Keep it a skeleton the client can grow: one short block
|
|
154
|
+
per persona (who they are, their context/device, expertise, frequency, the goals and constraints
|
|
155
|
+
that shape design). Create `docs/` if absent. This is the client's real content, surfaced from
|
|
156
|
+
their own answers — never a vendor template, never personas the harness guessed.
|
|
157
|
+
3. **On no, write nothing:** the inline personas live on in the handoff's §1 for this task, and the
|
|
158
|
+
next UI task will simply ask again.
|
|
159
|
+
|
|
160
|
+
## Design-tokens & design-tool on-ramp (when absent)
|
|
161
|
+
|
|
162
|
+
`docs/design-tokens.json` and a design-tool connection are **client-owned inputs** — the harness
|
|
163
|
+
consumes them if present and otherwise leaves them alone, the same regime as personas. For a repo
|
|
164
|
+
adopting the harness fresh, that silence is a dead end: no tokens, no way in. So when either is
|
|
165
|
+
**absent**, don't dead-end at a silent open question — make an explicit, opt-in offer at the end, on
|
|
166
|
+
your human-facing surface. Never scaffold or connect unasked.
|
|
167
|
+
|
|
168
|
+
### Tokens absent → offer to scaffold
|
|
169
|
+
|
|
170
|
+
When the project has **no `docs/design-tokens.json`**, offer once, after the design is defined:
|
|
171
|
+
|
|
172
|
+
1. **Offer at the end.** Ask whether to scaffold a starter `docs/design-tokens.json` from the
|
|
173
|
+
direction just defined, or keep it as an open question in §11.
|
|
174
|
+
2. **On yes, derive from the answers.** Build a minimal 3-tier DTCG file (`primitive` → `semantic`
|
|
175
|
+
→ `component`) from what the human actually stated — the colours, type, spacing and radii that
|
|
176
|
+
came out of the aesthetic-direction branch (§2) and the components branch (§5). This is the
|
|
177
|
+
client's own direction, surfaced as tokens — **never a vendor template**, never a palette the
|
|
178
|
+
harness guessed.
|
|
179
|
+
3. **Offer to cover the gaps too.** The interview rarely names every token. Ask a follow-up: for the
|
|
180
|
+
aspects the conversation **did not cover**, do they want a sensible **starter** set generated (a
|
|
181
|
+
neutral scale, default spacing and radii) so the file is usable from day one, or only the tokens
|
|
182
|
+
the answers implied? Opt-in — the human chooses how far to go, and you never pad the file unasked.
|
|
183
|
+
4. **Validate before closing.** After writing, run `lemony design-tokens validate` and fix anything
|
|
184
|
+
it flags, so the scaffolded file is well-formed (3-tier, aliases resolve) — a scaffold that fails
|
|
185
|
+
the validator is worse than none.
|
|
186
|
+
5. **On no, write nothing:** capture the missing token file as an open question in §11, exactly as
|
|
187
|
+
before. The next UI task simply asks again.
|
|
188
|
+
|
|
189
|
+
### No design tool → offer to connect
|
|
190
|
+
|
|
191
|
+
When `docs/design-tokens.json` carries no `com.lemony.design-tool` binding — or there is no tokens
|
|
192
|
+
file at all — offer to **connect a design tool** (e.g. a Figma or Pencil bridge) so tokens can
|
|
193
|
+
round-trip between the repo and the tool:
|
|
194
|
+
|
|
195
|
+
1. **Offer, opt-in.** Ask whether to connect a design tool now, or **stay pure-code** (tokens live
|
|
196
|
+
only in the repo). Most repos are happy pure-code — recommend that unless the human wants a
|
|
197
|
+
visual tool in the loop.
|
|
198
|
+
2. **On yes,** write the `com.lemony.design-tool` binding (the provider) into `docs/design-tokens.json`
|
|
199
|
+
and run the first import to bootstrap tokens from the tool. The `design-tool-sync` skill and the
|
|
200
|
+
`sync-design-tokens` command own the mechanics — you point the human at them; you don't
|
|
201
|
+
re-implement the bridge here.
|
|
202
|
+
3. **Skip gracefully.** If the tool's MCP bridge isn't connected, say so and fall back to the open
|
|
203
|
+
question — never block the interview on an unavailable tool.
|
|
204
|
+
4. **On no, stay pure-code:** write no binding. The design tool is only ever a projection of
|
|
205
|
+
`docs/design-tokens.json`, never a peer source of truth — declining costs nothing.
|
|
206
|
+
|
|
207
|
+
## Pause & Resume
|
|
208
|
+
|
|
209
|
+
Design definition is part of completing the spec, not a separate state. Pausing and resuming use
|
|
210
|
+
the lifecycle you already own — don't invent a parallel mechanism:
|
|
211
|
+
|
|
212
|
+
- **Pausing**: write `ui-handoff.md` with `Status: in_progress` and the sections closed so far,
|
|
213
|
+
record the sub-state `awaiting design definition` in the task's `progress.md`, and park the task.
|
|
214
|
+
Confirm with the user before ending the turn.
|
|
215
|
+
- **Resuming**: `/resume <id>` re-enters via that sub-state. Read the in-progress `ui-handoff.md`,
|
|
216
|
+
confirm which sections are closed and which branch comes next, then continue.
|
|
217
|
+
- **Completing**: flip `Status: in_progress` → `Status: completed`, then remove the
|
|
218
|
+
`harness:needs-design` flag at/before `spec-ready`.
|
|
219
|
+
|
|
220
|
+
## Tone
|
|
221
|
+
|
|
222
|
+
**Adaptive**, like the general grill. Start curious-collaborative; escalate when answers are shallow
|
|
223
|
+
("I don't know", "whatever looks good"); never go beyond constructive provocation. You bring taste
|
|
224
|
+
and conviction — push for a real direction, but the user decides.
|
|
225
|
+
|
|
226
|
+
## When the design is underspecified
|
|
227
|
+
|
|
228
|
+
If a design decision needs input the PRD left open with more than one valid answer and the user
|
|
229
|
+
can't resolve it in the interview, **capture it as an open question** in the handoff rather than
|
|
230
|
+
guess, and mark the handoff `Status: in_progress` until it is settled — never close a design on a
|
|
231
|
+
guessed fork.
|
|
232
|
+
|
|
233
|
+
## Cross-references
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
grill-ui → ui-handoff.md → implementer (build-ui) → REVIEW (design-critique + a11y-audit) → merge gate
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The implementer reads `ui-handoff.md` as its obligatory design input; the REVIEW design lens checks
|
|
240
|
+
the built UI against it. The `build-ui`, `design-critique`, and `a11y-audit` skills carry the
|
|
241
|
+
know-how and the audits — this skill only defines the contract.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
See also:
|
|
246
|
+
|
|
247
|
+
- [ui-handoff-format.md](./ui-handoff-format.md) — the canonical 11-section `ui-handoff.md` contract,
|
|
248
|
+
the dials + tone-preset definitions (§2), and the graduated component anatomy.
|