Skip to content

feat(aidd-ui): lay a platform-agnostic design system and carry a change through its impact - #1137

Draft
blafourcade wants to merge 71 commits into
nextfrom
feat/aidd-ui-system
Draft

blafourcade wants to merge 71 commits into
nextfrom
feat/aidd-ui-system

Conversation

@blafourcade

@blafourcade blafourcade commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

🎯 What & why

Second PR of the aidd-ui rework. The 01-system skill lays a design system on a blank or existing project, whatever its platforms. It extracts the norm from the code and carries a token or component change to its new versions. 01-hello goes away.

🛠️ How it works

  • One norm, platform agnostic. aidd_docs/ui/ is the project's norm. An existing design system in the code is matter for extraction, then only an implementation the norm is checked against.

    • system.md ties each code root to a platform: code-roots: [web=apps/web/src, mobile=apps/mobile/src].
    • A record lists its platforms, all of them when absent.
    • code is one link per platform with the version it implements: [apps/web/Button.tsx#Button@2, apps/mobile/Button.tsx#Button@1]. implemented-version is gone.
  • Responsibilities.

    • Engine hooks/aidd-ui.cjs: every rule and every deterministic write.
    • Hook hooks/ui-hook.cjs: an adapter only.
    • Skill: decides, passes inputs, reads outputs, judges.

    The engine stays in hooks/ because the CLI ships only that folder at plugin level, and later skills call it too.

  • Engine commands.

    • validate.
    • tokens writes aidd_docs/ui/tokens.css.
    • extract reads the code's token files (CSS custom properties of :root, [data-theme] and @media, JS or TS literal objects) and writes tokens.json and the theme, breakpoint and platform files. It keeps every CSS name, lists what it leaves, and writes the same bytes on every run.
    • impact reports what a change reaches, plus the tokens holding the same value without aliasing it.
    • bump applies the version rules to what impact reaches, once per task.
  • Themes, breakpoints and platforms are DTCG Resolver modifiers, combined by resolutionOrder.

    • A render sets data-theme and data-platform on <html> only, which V9 checks.
    • Every custom property therefore lives on the root, so each var() computes against the final values.
    • The generator writes one block per combination.
  • Version guard (H8). A validated element whose text, render or token values differ from HEAD must raise its version.

  • Colour literals (C4). They are found in any text file under a code root, except documents, data and images; a techno with no reader is read in its strings.

    • In a file identical to HEAD, a literal is a warning: existing debt.
    • In a changed or new file, it is an error.
  • Skill in the lean format. Three phase actions, prepare, write, conclude, a single sequence for setup and change. What the model needs lives in five references, as tables.

Choices worth a veto:

  • C4's severity by file state.
  • Components validated by hand until the review page exists (PR 3).
  • A value-only token change raising every validated element it reaches.
  • Theme and platform set on <html> only.

🧪 How to verify

  • node scripts/check-tests-leave-git-alone.js -- node --test 'scripts/__tests__/**/*.test.js': 1384 pass, 0 fail.
  • Rules and limits: plugins/aidd-ui/README.md. Skill: SKILL.md.

Evidence:

Check Result
Stylesheet in headless Chrome, against an independent Resolver 200 seeds × 6 resolution orders × 3 widths × 8 theme and platform combinations: 0 mismatch in 230,400 comparisons; the old generator gave 1661 mismatches on 50 seeds
Real Codex, flat install, and Haiku in Claude Code, on a web plus mobile project with a responsive web type scale, a dark theme and mobile values extraction then a token change, 0 errors for both; their tokens.json, theme and platform files are identical
Real Codex, blank web project setup and token change end VALID, about 30k tokens each
Gouvernail and Kairos copies, earlier skill text 0 errors (Kairos: 153 committed colour literals as warnings); impact matches a transitive grep

⚠️ Heads-up

  • Gouvernail and Kairos ran an earlier skill text. They used the six-action text and had no extract or bump. Only the synthetic web plus mobile project ran the final text.
  • Hook feedback on Codex is not proven. Codex writes through shell commands, which the hook does not see. No host was run on Copilot, Cursor, Kilo or OpenCode: only their flat layout was checked.
  • Screens, journeys and reviews are proven by scripted tests only.
  • H8 and C4 read HEAD. Committing an unraised edit or a new literal hides it from a later validate.
  • Overlapping breakpoint queries stay a limit, and so does a native-only behaviour such as haptics, which no render shows.
  • The other limits are written in the README.

✅ I certify

  • I DO CERTIFY I READ EACH LINE OF THE PULL REQUEST BECAUSE I AM A SOFTWARE ENGINEER, NOT A AI PUPPY.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD

blafourcade and others added 30 commits October 31, 2026 21:22
The engine gains a tokens command that writes aidd_docs/ui/tokens.css from
tokens.json and each theme file, one custom property per token. T10 names a
stylesheet that is missing or out of date, and a composite token without raw
CSS; V8 names a render that does not load ../tokens.css.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mDvAh1xZvZGAKEVhJn
The engine gains an impact command that prints the tokens, elements, screens,
journeys, renders and code files a change to tokens or elements reaches, from
the graph the hook already uses. H8 names a validated or deprecated element
edited since its committed version without a new one; it reads git through the
command line and stays silent without git, a repository or a committed record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mDvAh1xZvZGAKEVhJn
01-system lays a web design system from nothing or extracted from the code,
then carries a token or component change from its impact report to its new
versions, calling the engine's validate, tokens and impact commands. It ships
the record templates and a render skeleton that loads the generated
stylesheet, and stops saying a review is expected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mDvAh1xZvZGAKEVhJn
…e token file

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mDvAh1xZvZGAKEVhJn
…s of what it uses

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mDvAh1xZvZGAKEVhJn
…d read Astro files

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mDvAh1xZvZGAKEVhJn
…and leave deprecated ones alone

H8's token-value part reads the same token set as V7 through one helper, and applies to validated
elements only. The change flow names a deprecated element and leaves it untouched, so keeping it
deprecated no longer forces a false breaking row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
… what it redefines

A var() computes where it is declared, so a theme set on a nested element left a semantic token at
its base value when the theme redefined only its primitive. Each block now redeclares every base
token depending on one it redefines, through an alias or raw CSS, transitively, in tree order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
Silence now covers only git not installed, no repository, no commit and a file not committed. Any
other failure, such as a repository git refuses to read or the timeout, is one H8 problem on
aidd_docs/ui naming it, and the other rules still run. git's messages are read under LC_ALL=C.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…, and tidy small leftovers

A deleted tokens.css is now T10's one problem instead of two. The guard keeping a package path out
of the bare Astro link is gone: such a link stays an error under C1. The usage text has one
definition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…een's version

For a reached screen a review names, the change flow adds one pending verdict row per state at the
new version. A test on the fixture walks the whole sequence, from the impact report to a design
system that validates with no error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…its a review found

The skill finds the engine in a flat install and says a person validates a component by hand until
the review page exists. An Astro component links by bare path, tokens.css stays committed, and the
README and spec carry the remaining limits and the token set a render may use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…action criterion

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
… repository

git diff falls back to comparing two paths when it cannot use a repository, so a repository refused
for its owner kept H8 silent. diff-index needs a repository and says why it has none. A test runs
the real git under a different owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…p, and tighten three statements

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…ersion guard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…olor attributes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…the theme axis

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
An existing app's committed literals made the end-of-turn check impossible to pass, since the
skill never edits code. A literal stays an error in a file changed or untracked since HEAD, or
when git cannot answer. Blob ids decide, so a file only touched since still counts as unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
A monorepo's apps each hold their own token file, so the rule rejecting a list is reversed. Every
listed file is left out of literals and coverage, must exist, and joins impact's code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
The @media order decides which value wins, so swapping two contexts changed desktop values while
the check said VALID. T6 now names it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
A C4 error sat behind C3 warnings and the 20-line cap would cut it. Each keeps its relative order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
A redefinition printed "undefined" when the base token has no type, and R8 printed "a asset".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
States the expected errors, what extraction leaves in code, the token forms an existing app needs,
the coverage a render owes and what a change must check by hand. The breakpoint list is now the
order the media queries cascade in, so it no longer assumes mobile-first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…nd new limits

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
blafourcade and others added 18 commits November 2, 2026 23:10
Transversal rules keep only what holds for every step. The stylesheet,
validation and History rules move to the references their step opens,
implemented-version follows the record's version instead of a literal 1,
and each write step states when it runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
A code link is path[#Export]@<version>, one or a list, at most one per
platform, its platform that of the code root holding it. implemented-version
leaves the format. Components and screens take an optional platforms.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
A platform is an optional modifier of the Resolver, its contexts named after the
platforms of system.md and read like the theme ones. tokens.css writes each
platform that changes a value as a [data-platform] block after the themes, with
the same redeclaration of dependents. A token a theme and a platform both set,
or a platform and a breakpoint, is named.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
Under a code root, documents, data, images, fonts and any file holding a NUL
byte are neither covered nor scanned. Known stylesheets keep their reader; any
other text file is read for colour literals inside its string literals.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
The 01-system skill no longer stops at web: it extracts any design system in
the code, links each platform with its version and writes platform token
contexts. The README gives the new forms and limits, the spec its built state.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…ls read twice

A Haiku run wrote the design system into the plugin's own repository,
reading aidd_docs/ui/ from the skill's folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
From a Haiku run on a web and mobile project.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…exception

From a Codex run on a web and mobile project.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…kill's judgement

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
blafourcade and others added 8 commits November 3, 2026 11:22
…by the resolver order

Remove the three T6 rules forbidding a token set by two modifiers. tokens.css
resolves each pair of a theme and a platform, and each breakpoint over those
selectors, by resolutionOrder and writes only what the cascade would not give.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…path

A token file outside every code root now extracts with its platform, as a code
root does. A bare item stays valid with one platform or under a root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
A deprecated element follows only a token it cites, directly or through what it
uses. bump keeps a record's own line ends, and same-value drops the targets a
reached token cites.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…d type

A Codex run added $type to every context entry by hand, reading the
reference's example; Haiku kept extract's output. Both validate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…d platform on html only

A var() computes on the element that declares it, so a value citing a token another theme or
platform redefines was inherited stale, and html[data-theme] lost to the later @media :root.
tokens.css now holds the base in :root, then :root[data-theme], :root[data-platform] and the
pair of both, then each breakpoint as one @media repeating them. A block holds what the
Resolver gives its combination and the blocks before it do not. The dependent redeclaration
and the nested-region machinery are gone, and V9 names data-theme or data-platform on any
element but html. H8 and impact read the roots a stylesheet can be asked about, a theme at
a breakpoint included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
…ange in the task breaks

Within one task an element is raised once. A later --breaking change to it now turns that
History row to yes and appends the change text, instead of leaving it only in left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeK3mD4irAZumku9bknHhD
Comment thread plugins/aidd-ui/hooks/lib/css.cjs Fixed
Comment thread plugins/aidd-ui/hooks/lib/css.cjs Fixed
@blafourcade blafourcade changed the title feat(aidd-ui): lay a design system and carry a change through its impact feat(aidd-ui): lay a platform-agnostic design system and carry a change through its impact Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants