yannikzz/ui-contract/ui-contract-enforce

Claude Code and agent skill by yannikzz/ui-contract

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Install the enforcement that stops a coding agent putting a new feature in the wrong place - an entry clause in the repo-root CLAUDE.md, a directory-level clause, the region-name allowlist compiled into a union type, and an asset boundary forbidding hardcoded token values and locally-declared structural containers. Use once the structural spec exists.

Install

npx vskill@latest install yannikzz/ui-contract/ui-contract-enforce

SKILL.md

Enforcement

Produces edits to the repo-root CLAUDE.md and to the type layer. No new document.

For pushing rules into the type system, call the Skill tool with "constraint-by-types". For the interview discipline, call the Skill tool with "decision-interview". For the deliverable's language and terminology, call the Skill tool with "deliverable-language".

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. There is nothing to enforce
layout.md §2 has no "must not hold" columnStop, and say why that column is required. It is the only part of the allowlist that becomes a compile-time constraint. Without it, enforcement degrades to "please read the document"
A RegionId-like type exists in code but layout.md does notStop and say so. Enforcing a type that was derived from the code locks in whatever the code already does

There is no wireframe precondition. Enforcement depends on the allowlist, not on anything being drawn — it runs fine in a repo that has never had a wireframe.

The one question this unit asks

How hard should enforcement be?

OptionYou getYou lose
Decision tree up front + CLAUDE.md hard constraint + allowlist as a union type (recommended)Zero extra tooling, and one layer is compile-time—
Plus a validation script or lint ruleHardestWith only a wireframe existing there isn't much to validate yet — easy to build too early
Documentation onlyLightestAgents don't read a document nobody told them to read — least of all when the task sounds small

Two passes, not one

The four layers below do not become installable at the same moment, so this unit runs twice.

PassWhenInstallsWhy it cannot wait / cannot come earlier
1Inside the structural halfEntry and DirectoryBoth depend on layout.md alone. The gap before the visual half can last weeks; during it, anything that touches the interface needs something telling it to read layout.md first, and an unwritten entry clause tells it nothing
2After the asset layer has moved into the production treeCompile time and Asset boundaryBoth are installed on the production source tree. Before the move there is no production tree to install on

Do not install the compile-time layer on a staged asset layer. A union that lives outside the product constrains only what lives beside it. Measured (2026-08-25): in the admin-console example, PageWithInspector, TableColumnKind, InspectorKind and PageKind are all declared in wireframe/src/wire.tsx; every one of them is a layout.md clause, and none of them reaches a line of production code. ui-contract-assets records the same measurement from the other side — kept word-for-word on both sides on purpose, so the two can be compared. It type-checks, it goes green, and it guards a directory that gets deleted.

The layers

Documents alone don't get read — least of all when the task sounds small ("just adding a button"). Miss a layer and things leak through.

LayerHow
EntryA section in the repo-root CLAUDE.md: before changing any interface structure, walk layout.md §1; stop and use the change process if it doesn't land; every region name must be in the allowlist
DirectoryA CLAUDE.md inside the wireframe (if there is one): what to read before touching anything, the deliberate-tradeoffs list, which file is the single source for structural parameters
Compile timeAllowlist → union type, installed on the product source tree and covered by the project's own typecheck. Writing a name that isn't in the table fails type-checking. See below — where this runs is part of the layer, not a detail
Asset boundaryToken values must not be hardcoded in feature code — they come from the token file. Structural containers must be imported from the asset layer, never re-declared locally
The compile-time layer has to sit on code that ships

A union type only fires where something type-checks against it. So "the allowlist is a union type" is half a mechanism; the other half is which typecheck it is part of, and that half has been left implicit.

A wireframe's typecheck does not count. The wireframe is a throwaway reference implementation — constraining it constrains nothing that ships, and if the project keeps its wireframe out of the repository, that typecheck does not run in CI at all. Either way the layer reports nothing and looks no different from one that is working.

Two things have to be true, and both are checkable:

  1. The union type lives in the asset layer, inside the product source tree, and the command a contributor or CI actually runs (tsc --noEmit, pnpm typecheck, whatever the project uses) covers that path.
  2. Something fails even when no product code happens to use a given region name yet. On a young project most of the allowlist has no call sites, so an empty product tree type-checks clean against any union at all — including one somebody weakened. The assertion file in constraint-by-types §2 is what closes this; without it, the layer's strength is proportional to how much code already exists, which is backwards.

Verify it by breaking it. Put an off-allowlist name into a product file, run the project's typecheck, and paste the error. A layer nobody has seen fail is a layer nobody has seen.

The asset boundary is the newest layer and the least obvious. Layering the specs into production code created a new drift surface: the asset layer is real production code, so business pressure pushes changes into it directly — someone adds a slot to a container to ship a feature, and the spec never hears about it. The boundary clause is what makes that visible at review time.

The three forms of the allowlist

FormWhereFor
Table (responsibility / must hold / must not hold)layout.md §2Humans and agents reading
Union typeThe asset layerThe compiler
Metadata (label + description)The asset layerThe annotation layer

Put a line at the top of layout.md §2 saying that changing the table requires changing both of the others.

Before you call this done

  • [ ] Region names are identical across the document, the type definition, and the code — grep every allowlist name and find it in all three
  • [ ] The repo-root CLAUDE.md entry clause exists and names the decision tree by section
  • [ ] Every "must not hold" entry that can be expressed as a type omission has been, with a comment marking the omission deliberate
  • [ ] Each of those omissions also has a line in the assertion file (constraint-by-types §2), so deleting the prohibition breaks the build instead of going silent
  • [ ] The union type is in the product source tree, and the project's own typecheck command covers it — name the command. A wireframe's typecheck does not satisfy this
  • [ ] The assertion file is inside that same typecheck's `include`. Nothing imports it, so a narrow include drops it silently
  • [ ] Enforcement was verified by breaking it: an off-allowlist name was written into a product file, the project's typecheck was run, and the real error is pasted
  • [ ] The asset boundary clause is written, and it names both halves (no hardcoded token values; no locally-declared structural containers)

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/yannikzz/ui-contract/ui-contract-enforce/badge)](https://verified-skill.com/skills/yannikzz/ui-contract/ui-contract-enforce)

Something wrong with this skill or its page? Tell us.