agentleFS
yannikzzyannikzz/ui-contract/skills/ui-contract-design/SKILL.md

ui-contract-design

Skill3 starsChanged 17 days agoMITView on GitHub

Align an existing visual spec (design.md) against the structural spec - add the division-of-labor statement, move structural content out leaving a pointer, replace old component-style names with allowlist names, and move literal values into the token file so design.md holds rules rather than values. Use when a project has visual conventions that need to become a spec with a clean boundary. Or originate one when there are none at all - choose a brand direction on attributes rather than colours, derive the values, tune them on a page. Chinese: 生成品牌/配色规范/token 命名/主题调校.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If the project already has a visual spec, do not rewrite it.

    line 82
  2. Very specific:

    Do not silently invent values back into design.md to make it self-contained.

    line 115

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Visual spec — design.md

Produces one artifact: design.md, plus references into the project's token file. Skeleton in design-md-outline.md. Read it.

Two branches, same artifact and same completion criteria — so this is one unit, not two:

What the project hasBranch
A visual spec, a token source, or mockupsalign — this file, below
None of thoseoriginate — originate.md. Read it before asking anything.

For the interview discipline, call the Skill tool with "decision-interview". For which document a thing belongs in, call the Skill tool with "ui-contract-glossary". For the deliverable's language and terminology, call the Skill tool with "deliverable-language". For handling change requests, call the Skill tool with "spec-before-code".

Preconditions

Artifact paths come from docs/ui-contract/config.md's paths table. If that file doesn't exist, the specs are at the repo root. Never assume a path the config contradicts.

ConditionAction
layout.md does not existStop. The allowlist is what region names get aligned against; without it this step produces a second vocabulary. Call the Skill tool with "ui-contract-layout" first
design.md exists but layout.md does notStop and say so. Aligning a boundary against a document that doesn't exist means inventing the other half
No visual conventions exist anywhere — no design.md, no token source, no mockups — and the visual half is authorised: docs/ui-contract/config.md says so, or the user asked for it in this sessionGo to originate.md. Do not start from this file's align procedure — there is nothing to align against
No visual conventions exist anywhere, and nothing authorises the visual halfStop, and say why. originate invents brand decisions out of nothing; entered without somebody answering for them, it produces a specification of decisions nobody made — and nothing in the output reveals that. Report what the structural half produced and what this unit would settle, and leave it there
Nothing exists and the user asks for "something that looks good, you pick"Still originate.md, still the interview. Do not hand over a default palette. A palette the user rubber-stamps is no longer their spec, which is the failure this whole method exists to prevent

The scope gate is on originate only, and that is deliberate

The two branches need different permissions, and giving them the same one breaks the other:

BranchWhat it does to the user's materialWhat authorises it
alignSlims a document they already have — structural content moves out, a pointer stays"May the existing visual spec be edited?" in config.md. It touches somebody's file; it invents no brand decision
originateProduces a brand direction, a scale and a set of values where none existedThe scope authorisation. These are decisions somebody has to answer for

Gating align on scope would block a boundary cleanup that the structural half needs anyway — an existing visual spec almost always has structural content mixed into it, and leaving it there gives the project two vocabularies. That is the failure align exists to prevent, and it has nothing to do with the one the handover exists to prevent.

Start by reading layout.md's ⏳ list

Structure and visuals are two dimensions of one interface, so a few numbers belong to neither alone. layout.md marks those ⏳ — a fixed panel width, a minimum usable width, a page size — and this step is where they get settled.

Read that list first. A type scale chosen without knowing that nine fields and five actions have to fit in 360px is a scale somebody will revisit.

Settling them is this unit's job, and it is done here whoever is answering. The ⏳ list is always brought in as a list — "these three are waiting on your scale" — never folded silently into the structural interview, because the two interviews sit in different halves. What config.md changes is only when this interview happens, not how it runs:

The handover wasWhen this runs
Soft — the same person answers for both halvesStraight after the hand-back, in the same sitting, with the ⏳ list on the table
Hard — somebody else, or nobody yetWhenever that person picks it up. The ⏳ list travelled to them as the note; they should not have to read the whole structural spec to find those three numbers

Answers go back into layout.md, by its own change process — this unit does not edit it directly.

Do not require the two people to be in a room together. That is often impossible, and a mechanism that assumes it simply fails in that half of the world. The marker travels between them precisely so the meeting is not the mechanism — this whole plugin exists because "somebody will remember to" is not one either.

A ⏳ line can come back refuted rather than filled. Building the projection can show that a marked number does not hold at all — nine fields and five actions do not fit in 360px, whatever the scale. That is a different fact from "waiting for a number", and it must not reuse the ⏳ marker: one says give me a value, the other says the direction you were going to give a value for is dead.

Mark it ⛔ in layout.md, in the number's own table cell, with what refuted it — the marker and its placement rule are defined in ui-contract-layout's outline, §3 "A third outcome". Note what that section records: ui-contract-audit's check 10 does not report ⛔ yet, so a refuted line is invisible to the health check. Name the refuted lines explicitly in the hand-back; do not rely on the check to carry them.

This step aligns; it does not rewrite

If the project already has a visual spec, do not rewrite it. Four things:

  1. Add the division-of-labor statement at the top, naming the cut ("does it change when the brand skin changes") and naming the token file as the value authority.
  2. Move structural content out: region trees, column widths, page archetypes go to layout.md. Leave a one-line "structure: see layout.md §X" behind, and rename the section if its title promised structure.
  3. Move literal values out to the token file. Hex codes, px sizes, radius literals become token references. If the project already has a token source (tailwind.config.*, tokens.css, a theme file), that is the token file — do not create a second one.
  4. Align region names with the allowlist. Old component-style names (camel-cased widget names) must be replaced with allowlist names, or an agent reading both docs gets two vocabularies — and the allowlist mechanism fails on the spot.

Token names are not part of that. Region names get aligned; token names do not. Record what the project already calls them in the declaration table, marked this project, and change nothing. Renaming tokens turns a boundary alignment into a repo-wide rename that touches every consumer — a change request, which goes through spec-before-code.

Appendices that record mockup reality (value-drift mapping tables and the like) stay untouched — they document the mockup, not the spec.

The document is the name authority

The token file holds the values; this document settles which names exist. Say so in the opening blockquote, and carry the declaration table (design-md-outline.md §Opening) with it.

This has to be written down for the same reason the value authority is: without it, a borrowed naming convention quietly becomes the authority instead, and nothing in the output shows it — a token file produced either way is byte-for-byte the same. The health check reads its whitelist from that table, so a missing table degrades the check to nothing.

The same applies to tokens.input.json when the originate branch produced one:

RecordsOn conflict
tokens.input.jsonwhere the user left the knobs (an input record)does not count
the token filethe values that are currently correctwins

Its keys are the names from the declaration table. Per-stack mapping changes the format, never the names.

When there is no token file yet

Say so in the document, not only in the report — the reader who never sees the report is the one this has to reach. Write the token references as they should be, and two things with them:

  • Name no path that is not on disk. Write "the token file is the value authority; this project does not have one yet" rather than pointing at src/tokens.css and hoping. Following a pointer to a missing file is how a reader concludes the whole spec is stale.
  • Say who closes the gap. On the align branch no unit generates the token file — the asset layer produces structural components only, so whoever builds it fills in the values under the names written here. On the originate branch this section does not apply: that branch derives the values and writes the token file itself, so a deliverable from it should never contain "there is no token file yet".

Do not silently invent values back into design.md to make it self-contained. A document that quietly re-absorbs its values is exactly the second value authority this rule exists to prevent.

Before you call this document done

  • Every ⏳ in layout.md was resolved, refuted, or is explicitly left open with a reason — and read before settling the scales, not after: a scale chosen without knowing what has to fit at it is a scale that will be revisited. "Resolved" and "refuted" are different endings; the line-level item near the bottom of this list says how each is marked
  • Resolving one means editing layout.md — the ⏳ becomes a plain number. Not the type size written into layout.md, not the width copied into design.md: both directions are the bleed the split exists to prevent
  • design.md contains no literal color or size values; the token file is the single value authority
  • Structural content has been moved out and only a one-line pointer remains
  • Every region name matches the allowlist; no old component-style naming survives in the normative body
  • Mockup-reality appendices were left alone
  • If no token file exists yet, design.md says so in its own body, and no path to a missing file is written anywhere in it
  • The declaration table is present in the opening section, one row per token, each row marked borrowed / this project / not used — those three keywords in ASCII even in a non-English deliverable, because the health check anchors on them and a translation silently turns the check off
  • Every row marked borrowed is actually in the borrowed set; no sidebar-* and no chart-* among them
  • Chapters the borrowed set does not cover say so, and their names follow the pairing rule
  • On the originate branch: the three directions differ on at least two axes, and each cost is a consequence in this product rather than an adjective
  • On the originate branch: every derived value traces to a coordinate, and the hue's basis is named in design.md §1 — one of the four in originate.md §The gap the axes do not close, or an explicit "none applies" that marks the hue as the weakest value in the set. The axes fix count and saturation but not hue, so it is the one slot with no source
  • On the originate branch: no value in tokens.input.json is a framework default (the list is in originate.md §Do not emit a framework default) — emitting one means the coordinates never reached the values
  • On the originate branch: the hue's basis is stated without a literal colour — not the chosen value, not the default being contrasted against. design.md carries no hex anywhere, and explaining a choice is not an exemption from that
  • On the originate branch: the token file itself was written — the real one, at the path and format the paths table gives, committed. Not described, not left for another unit: the old write-the-record-and-let-another-unit-land-it handoff landed 2 of 5 runs (2026-08-25)
  • On the originate branch: tokens.input.json was also written, at .ui-contract-local/tokens.input.json — pinned, not configurable, because the instrument and a grader both need one answer
  • On the originate branch: the user was not told to keep or commit the knobs record. It is not a deliverable; describing it as one invites somebody to maintain a file nothing reads
  • On the originate branch: the two are not confused in the deliverable (identity table above). Describing the record as where the values live is the second value authority this split exists to prevent
  • On the originate branch: the visual baseline was captured — wall frame, 480px copy, 200% crops, paths recorded in §1 — and the three-second sentences were written against it, not skipped
  • On the originate branch: the context-free review pass ran on the baseline and §1 records its verdict; when it was skipped, §1 says "not reviewed" in so many words
  • If the token file landed while the asset layer is still without one, ui-contract-assets was called again. It runs twice on a greenfield project and both runs are correct; pass 2 consumes the token file. This unit does not touch the asset layer itself — values are authored here, consumed there, and reversing that gives the project two value authorities
  • Every ⏳ line in layout.md was either settled, refuted, or explicitly left open with a reason — settled means it became a plain number; refuted means it carries ⛔ and what refuted it (definition: ui-contract-layout's outline §3); left open means the reason is written down. A ⏳ that is merely still there is none of the three. This is the same condition as the first item in this list, stated at the line level — refuted lines were also named in the hand-back, because check 10 cannot see them
  • Reported to the user: which sections were touched, how many names were replaced, what was deliberately left alone

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.