zz-meridian 0.10.0 → 0.12.0
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/README.md +9 -1
- package/dist/adopt.js +2 -1
- package/dist/cli.js +2 -0
- package/dist/create.js +3 -2
- package/dist/session.js +6 -2
- package/package.json +1 -1
- package/payload/CHANGELOG.md +51 -0
- package/payload/CONTRIBUTING.md +4 -3
- package/payload/README.md +12 -3
- package/payload/docs/benchmark.md +2 -0
- package/payload/docs/distribution.md +12 -3
- package/payload/docs/skill-evals.md +66 -0
- package/payload/docs/start-a-dashboard.md +1 -1
- package/payload/package.json +1 -1
- package/payload/scripts/assistant.ts +204 -169
- package/payload/scripts/audit.ts +56 -16
- package/payload/scripts/brand.ts +2 -1
- package/payload/scripts/check.ts +15 -2
- package/payload/scripts/gate.ts +6 -5
- package/payload/scripts/interactions.ts +37 -12
- package/payload/scripts/keyboard.ts +105 -24
- package/payload/scripts/lib/aliases.ts +28 -0
- package/payload/scripts/lib/coverage.ts +8 -0
- package/payload/scripts/lib/deep.ts +74 -0
- package/payload/scripts/lib/sample.ts +20 -0
- package/payload/scripts/navigate.ts +32 -8
- package/payload/scripts/shot.ts +43 -2
- package/payload/scripts/verify.config.ts +4 -0
- package/payload/scripts/verify.ts +29 -16
- package/payload/skills/zz-meridian/SKILL.md +126 -81
- package/payload/skills/zz-meridian/references/customize.md +40 -14
- package/payload/skills/zz-meridian/references/existing-project.md +67 -12
- package/payload/skills/zz-meridian/references/register.md +32 -0
- package/payload/skills/zz-meridian/references/standard.md +173 -0
- package/payload/skills/zz-meridian/references/update.md +13 -5
- package/payload/skills/zz-meridian/references/validation.md +46 -9
- package/payload/src/components/patterns/ask-about/preview.tsx +1 -1
- package/payload/src/components/patterns/data-table/index.tsx +4 -2
- package/payload/src/components/patterns/rail/README.md +1 -1
- package/payload/src/components/ui/button/preview.tsx +1 -1
- package/payload/src/components/ui/checkbox/preview.tsx +1 -1
- package/payload/src/components/ui/icon-button/preview.tsx +1 -1
- package/payload/src/components/ui/input/preview.tsx +1 -1
- package/payload/src/components/ui/switch/preview.tsx +1 -1
- package/payload/src/lib/format.ts +2 -2
- package/payload/src/lib/shared-context.ts +3 -1
- package/payload/src/system/sample-cells.tsx +1 -1
- package/payload/src/system/specimen.tsx +7 -3
- package/payload/src/views/console-chrome.tsx +17 -7
- package/payload/tests/check-aliases.test.ts +20 -0
- package/payload/tests/console-chrome.test.tsx +19 -0
- package/payload/tests/format.test.ts +3 -0
- package/payload/tests/shared-context.test.tsx +11 -0
- package/payload/tests/specimen-still.test.tsx +22 -0
- package/payload/tests/verify-sample-surfaces.test.ts +26 -0
- package/payload/tests/verify-suite-outcome.test.ts +11 -1
package/README.md
CHANGED
|
@@ -9,7 +9,15 @@ dashboard depends on it afterwards.
|
|
|
9
9
|
Give your coding agent (Codex, Claude Code, or any agent that can run a shell) this, with what you want in your own
|
|
10
10
|
words at the end:
|
|
11
11
|
|
|
12
|
-
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words].
|
|
12
|
+
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.
|
|
13
|
+
|
|
14
|
+
In Claude Code or Codex, send it as a goal (`/goal Run npx zz-meridian@latest skill --global, then …`): the agent keeps
|
|
15
|
+
working until the condition holds, and a separate model checks it after every turn against the hand-over, which quotes
|
|
16
|
+
its evidence. The sentence says what you want; the skill carries how good it has to be. It builds, renders every view
|
|
17
|
+
at phone and desktop width in both themes, scores each one on a scoreboard of floors (measured by `pnpm verify --full`)
|
|
18
|
+
and craft (judged on the renders), and improves it round by round until nothing is weak, deciding what it can find out
|
|
19
|
+
and recording each decision it made for you. You get the finished product, the renders, and the few questions only you
|
|
20
|
+
can answer.
|
|
13
21
|
|
|
14
22
|
The skill picks the command from what you said and what is in the folder, and names it before running anything:
|
|
15
23
|
`adopt` to change this Next.js App Router project in place ("make this admin panel look professional"), `create` for a
|
package/dist/adopt.js
CHANGED
|
@@ -324,7 +324,8 @@ Meridian ${VERSION} is in ${root}.
|
|
|
324
324
|
agent context: AGENTS.md has the managed block; docs/brief.md ${briefWritten ? 'is the empty brief to fill in' : 'was kept as it is'}
|
|
325
325
|
types: ${typed}${notes.length ? `\n notes:\n${notes.map((n) => ` - ${n}`).join('\n')}` : ''}
|
|
326
326
|
|
|
327
|
-
Next: follow .agents/skills/zz-meridian/references/existing-project.md, Route A, from step 2 (step 1 was this)
|
|
327
|
+
Next: follow .agents/skills/zz-meridian/references/existing-project.md, Route A, from step 2 (step 1 was this), to the
|
|
328
|
+
standard in references/standard.md. The
|
|
328
329
|
template to read from is https://github.com/zhixuan312/zz-meridian/tree/v${VERSION}. Import Meridian's components as
|
|
329
330
|
'@meridian/components/…'. Before the first ${pm} run verify, read step 5: verify presses every control, Delete included.`);
|
|
330
331
|
return 0;
|
package/dist/cli.js
CHANGED
|
@@ -103,7 +103,9 @@ function main() {
|
|
|
103
103
|
const roots = values.global ? [os.homedir()] : [process.cwd()];
|
|
104
104
|
for (const r of roots)
|
|
105
105
|
installSkill(r);
|
|
106
|
+
const skill = path.join(roots[0], '.claude/skills/zz-meridian/SKILL.md');
|
|
106
107
|
console.log(`The zz-meridian skill is in ${values.global ? path.join(os.homedir(), '.agents/skills') + ' and ' + path.join(os.homedir(), '.claude/skills') : '.agents/skills and .claude/skills'}. Codex may need a restart to list it.`);
|
|
108
|
+
console.log(`To follow it now, read ${skill} and the references beside it: it says how to build what was asked and when it is done.`);
|
|
107
109
|
return 0;
|
|
108
110
|
}
|
|
109
111
|
console.error(`zz-meridian: unknown command "${command}"\n\n${HELP}`);
|
package/dist/create.js
CHANGED
|
@@ -76,8 +76,9 @@ export function create(o) {
|
|
|
76
76
|
${name} is a new Meridian ${VERSION} dashboard in ${root}.
|
|
77
77
|
skill: .agents/skills/zz-meridian (Codex) and .claude/skills/zz-meridian (Claude Code)
|
|
78
78
|
|
|
79
|
-
Next: follow .agents/skills/zz-meridian/SKILL.md from step
|
|
80
|
-
the pages, then ${pm} run verify
|
|
79
|
+
Next: follow .agents/skills/zz-meridian/SKILL.md from step 3's brief (the template is fetched and branded): the brief,
|
|
80
|
+
step 4's colour check, then data and the pages, then the loop in references/standard.md until ${pm} run verify --full ends with "the project meets the
|
|
81
|
+
Meridian standard" and no view on the scoreboard is Weak.`);
|
|
81
82
|
return 0;
|
|
82
83
|
}
|
|
83
84
|
function fail(msg) {
|
package/dist/session.js
CHANGED
|
@@ -307,9 +307,13 @@ export function start(ctx, o) {
|
|
|
307
307
|
return refuse(`updates start from 0.3.0; this project is on ${manifest.version}`);
|
|
308
308
|
if (!/^\d+\.\d+\.\d+$/.test(ctx.version))
|
|
309
309
|
return refuse(`the running version ${JSON.stringify(ctx.version)} must look like 1.2.3`);
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
// Already current is not a refusal: there is nothing to do, and the run that asked has its answer.
|
|
311
|
+
if (manifest.version === ctx.version) {
|
|
312
|
+
log(`zz-meridian update: already at ${ctx.version}; nothing to update`);
|
|
313
|
+
return 0;
|
|
312
314
|
}
|
|
315
|
+
if (!isNewer(ctx.version, manifest.version))
|
|
316
|
+
return refuse(`this project is on ${manifest.version}, newer than this package (${ctx.version}); run npx zz-meridian@latest update`);
|
|
313
317
|
const git = spawn('git', ['status', '--porcelain'], root, true);
|
|
314
318
|
const dirty = git.status === 0 ? (git.stdout ?? '').split('\n').filter(Boolean).length : 0;
|
|
315
319
|
if (o.dryRun) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zz-meridian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Bring ZZ Meridian, a dashboard design system, into a Next.js project, or start a new dashboard on it. Copies the files in; nothing depends on this package at runtime.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/payload/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
Every release of ZZ Meridian, newest first. Versions follow semver: a removed or renamed token, prop or card is major; a new card, token or variant is minor; a corrected value is a patch. Each entry says what breaks and what to do instead.
|
|
4
4
|
|
|
5
|
+
## [0.12.0] · 2026-10-09
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **A project can bring its own look.** Meridian's register (dark first, the night-sky neutral, one accent with a job, the defaults that read as generated, and the look-dependent parts of Colour, Typography, Hierarchy and Originality) now lives in its own file, the skill's `references/register.md`. A project with its own design language writes `docs/register.md`, and the skill scores looks and takes brand guidance from it instead. A project register never changes a floor, a required state, accessibility, the loop or the budget policy. `docs/skill-evals.md` gains the scenario that probes it. How it is applied is stated once, in `standard.md`: a line that would lower a floor is not followed but recorded in `out/standard/questions.md`; Meridian's register fills any value the project's leaves unset; the project's anti-defaults and its own brand route replace Meridian's; and its face, radii and colours go through the token files, with any managed file changed for them listed in the keep register.
|
|
10
|
+
- **One way into open shadow roots for the browser checks.** `scripts/lib/deep.ts` walks the document and every open shadow root, finds the focused element through them, matches selectors inside them and steps from a slotted element or a root back to its host. Its fixtures live in `scripts/fixtures/deep/` and, with their tests, are not shipped.
|
|
11
|
+
- **The audit sees inside open shadow roots.** A product that uses web components had their text, names, targets, contrast and focus rings skipped without a word; the audit now measures them, composites a background through the host, and counts a focus ring only where focus changed the style, so an always-present border is no longer taken for one. A custom element it cannot measure (one with no open root, or one never defined) is reported as `unmeasured:` instead of passing.
|
|
12
|
+
- **The presses and the keyboard walk reach controls inside open shadow roots** and name them with their host (`Save (in x-card)`). The walk also presses Shift+Tab back through the stops and reports a reverse order that differs, or a control only Shift+Tab reaches.
|
|
13
|
+
- **A project's navigation selectors resolve inside open shadow roots.** `navigationChecks` ready, control and result selectors match elements inside open roots (a descendant combinator still does not cross a boundary), and a control selector that matches several elements prints a one-time `note:` naming the count; the first visible match is pressed, as before.
|
|
14
|
+
- **`State` in the Atlas takes `still`.** A specimen that depicts a state (the Focus specimens of Button, Checkbox, IconButton, Input, Switch and AskAbout) is drawn inert, so it is no longer an extra tab stop that never shows focus.
|
|
15
|
+
- **The browser checks are documented for web components.** `validation.md` explains `unmeasured:` (a custom element the audit cannot look inside: give it an open shadow root or light-DOM content, or define it) and `note:` (a `navigationChecks` selector that matched several elements: information, never a failure), and lists the keyboard walk's failures, including `reverse order differs` and `never reached … (Tab skips it; only Shift+Tab reaches it)`.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **A focus ring is a change on focus.** The audit and the keyboard walk count a ring only when focusing the control changes its outline, shadow or border (on the control or the frame around it, or anywhere up to its host inside a shadow root). A control whose outline or shadow is always there no longer passes as ringed: give it a ring that appears on focus.
|
|
20
|
+
|
|
21
|
+
## [0.11.0] · 2026-10-08
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **The standard the sentence never states.** The skill's `references/standard.md` holds what one sentence leaves out: the register a product UI answers to, the defaults that read as generated, and a scoreboard kept in `out/standard/` for every view. The scoreboard has floors measured by `pnpm verify --full`, and craft judged on renders at 1440 and 390px in both themes (fit, hierarchy, typography, whitespace, colour, motion, responsive, navigation, copy, states, agents, originality). The agent runs the loop until `--full` ends with `the project meets the Meridian standard` and no view is Weak. Mechanical questions it settles itself; judgment calls it records with a recommendation, proceeding when cheap to reverse. Push, release, deploy, production data and the feedback issue wait for a yes.
|
|
26
|
+
|
|
27
|
+
- **How the skill is evaluated.** `docs/skill-evals.md`: four levels by cost (static checks every change; decision probes, an agent reading the skill in a scenario's folder and stopping before the first write, for a change to the route, the decisions or the standard; planted defects for a change to the loop; end to end weekly), seven scenarios with what a right answer does, and how a finding is counted. Two fixture apps for them in `cli/test/`: `fixture-crumb-ops` (Next.js App Router over its own orders API, with server actions that delete) and `fixture-vite-rota` (Vite and React Router, one browser read); neither ships.
|
|
28
|
+
|
|
29
|
+
- **One protagonist is a rule, not only a judgement.** `check.ts` fails a file that renders a second `FeaturedMetric`. A planted second one went unscored when an agent judged the renders by eye.
|
|
30
|
+
- **The console's rail takes the request's data from the layout.** `ConsoleRail` passes its props through (`user`, `signOut`, `workspace`, `scopes`) and both it and `ConsolePalette` take `only`, the hrefs a person may see. A product filtered `nav` or set its session's person by editing `src/views/console-chrome.tsx`, a file Meridian manages; a console with no sign-in showed the sample person and a Sign out to nowhere. Now the team's own layout passes them.
|
|
31
|
+
- **`shot.ts --press "<name>"`** opens a dialog, sheet, menu or popover before the shot, with the mouse, as a person does; repeated, it presses in order. A view that only a press shows can now be rendered and scored.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **An update already on the running version has nothing to do, and says so.** `update` and its dry run print `already at <version>; nothing to update` and exit 0, where they refused with exit 1 as if something were wrong.
|
|
36
|
+
- **The sentence ends with its condition, and is meant for `/goal`.** `… to: [what you want]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.` The model a goal uses to check the work reads the sentence and the transcript, never the skill, so the hand-over quotes verify's last line, the coverage line, the scoreboard count, the decisions made, what did not run, and the commits.
|
|
37
|
+
- **The skill decides from its drafts instead of asking.** Step 2 turns the homework into recorded decisions; the one question left is the route, when two fit. A brand hue too near a status hue moves to the nearest safe hue, with the brand kept in the logo mark. A missing tool no longer stops the build: what cannot run is reported as not run, and the standard as not yet proven.
|
|
38
|
+
- **`skill` prints the path to read.** After installing, it names the `SKILL.md` to read now, since a running agent may not list a skill installed mid-session.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **What the agents are told about freshness names the right zone.** `freshnessOf` wrote the time in the product's reporting zone and labelled it "UTC", so a product in Asia/Singapore told both agents that 17:30 local was 17:30 UTC. It names `app.timezone`.
|
|
43
|
+
- **An amount keeps one precision.** `formatCost` gave two decimals under 1,000 and none above, so a column read "$997.00" over "$1,269"; it gives two at every size ("$1,269.40"). `formatCostCompact` stays for dense tiles.
|
|
44
|
+
- **The gate reads an adopted project's imports.** `check.ts` took `@/` to mean `src/`, so in an adopted project, where `@/` is the team's root and Meridian is `@meridian/`, every module imported the documented way read as dormant ("exports X, which nothing a product keeps imports"), and a project had to rewrite its imports as relative paths to pass. It now resolves imports through the project's tsconfig `paths` (`scripts/lib/aliases.ts`).
|
|
45
|
+
- **verify reports a bad configuration instead of crashing on it.** An early exit (a `navigationChecks` or `smokeRoutes` entry naming a route that is gone) threw `Cannot access 'suites' before initialization` and hid the reason; it now prints each configuration failure and the coverage line.
|
|
46
|
+
- **The coverage line says which suites failed.** A suite that ran and failed was listed under `not run`, as if skipped; it is now `failed: <suites>`, after `not run`.
|
|
47
|
+
- **A phone card's status and facts stay in their place.** The status badge took one of the card's six tracks, narrower than a badge at 390px, so it ran left over a long title and sat short of the card's edge; it takes two, as the layout meant. A long fact ends in an ellipsis instead of running over the fact beside it. The sample's customer column caps its width, so a long name no longer pushes the Requests table past its card at 1440px.
|
|
48
|
+
- **A product can reach "the project meets the Meridian standard".** The assistant walk-through and the live checks drove the template's own sample pages (Overview, Members, API keys, Settings), so a product that replaced them — every product the skill builds — failed the walk-through or ended `not run: live`, and `--full` could never print the outcome its stop condition asks for. The walk-through now checks what every product shares on its own rail: no agent control while off, on every rail route and embed view, 12 in the template where it was 8; the panel, a reply, the page the model was told, markdown, the thread across navigation, Clear, the layout, a refused key, the key never reaching the browser. It drives each sample page only while its files are there (`scripts/lib/sample.ts`), printing `n/a` with the reason otherwise; Meridian's own repository, which has every one, walks all of them. Without the sample Members page, verify prints `n/a live data` instead of running the live checks, and it no longer counts against the outcome; a product's own live pages prove themselves through `browserChecks`.
|
|
49
|
+
- **The skill names what its route needs, from what the probes met.** `create .` works in an empty folder; timezone, currency and the meaning of the request's own terms are recorded decisions; a view's verdict is its lowest criterion; the error state without a fake API is shown by making the read throw for one render. An update already on the running version stops there. The `optional:` and `example:` path prefixes are explained, a project's own copy of the skill is the one to follow, and Route A2 no longer names a `--product` flag `create` does not have. An existing product is learned first, its production addresses found before anything runs, its pages shot "before", and what must survive listed as a floor; Route B renders its "before" from a copy, and a read moved from the browser to the server carries neither cookies nor CORS. `create` and `adopt` end by pointing at the standard, not at `verify` passing. From the second round: the last round needs no round after it; originality comes from how asked-for content is shown, never from adding content; a view's states are scored under it and the shell is one row; the dev server is stopped by its own process id; the rail's signed-in person is never the sample's; an API address overrides `.env` through the environment and is not a `dataUrls` entry; a rebrand that lands near a status hue runs `brand` again with the nearest safe hue. From a built brownfield run and a planted-defect run: an adopted project turns on Cache Components and wraps its shell in `<Suspense>` when detail ids come at request time; a product formatter lives in a file of its own, and a Meridian file it must change goes in the keep register; the theme default is set through `brand --theme`; a navigation probe works at 390px; a request to evaluate only has a route of its own; a criterion not yet judged is not a pass. From the built greenfield run: `create` points at step 3's brief, not step 5; a page specification has a shape to start from; the shared context's 2,400-character budget is stated; the dev server is started as Next itself, so stopping its id stops it. From a third round of decision probes: the existing-project route starts with "Before you change anything", not with `adopt`; Cache Components means `partialPrefetching` too; a render server in a project with a fake API is started with its address; an npm project passes flags after `--`; a currency is evidence of the zone; a browser-fetching app's "before" needs a time budget and a fake API that allows its origin; Route B's new project takes Route A's verify steps.
|
|
50
|
+
- **The skill's screenshots reach the dev server.** Step 6 started `pnpm dev`, on port 3000, then ran `scripts/shot.ts`, which reads port 3100. It now starts `pnpm dev --port 3100`.
|
|
51
|
+
|
|
52
|
+
### Breaking
|
|
53
|
+
|
|
54
|
+
- **`formatCost` prints cents at every size.** An amount of 1,000 or more reads "$1,269.40" where it read "$1,269". A product that pinned the old string in a test, or laid a column out for the shorter figure, updates it; `formatCostCompact` is the short form.
|
|
55
|
+
|
|
5
56
|
## [0.10.0] · 2026-10-07
|
|
6
57
|
|
|
7
58
|
### Added
|
package/payload/CONTRIBUTING.md
CHANGED
|
@@ -87,9 +87,10 @@ Write the status on the line under the title: `Status: beta`.
|
|
|
87
87
|
| `node scripts/registry.ts` | Regenerates the Atlas registry from the card folders (`--check` only compares) | After adding or renaming a card |
|
|
88
88
|
| `node scripts/check.ts` | Every card has its README and preview, every README follows the anatomy, no literal colour in components, every token a spec names exists and is written with its own value, every embed view a document offers is a route, and an element that claims a control's role has a key handler | Gate |
|
|
89
89
|
| `pnpm typecheck`, `pnpm test` | TypeScript and the behaviour tests | Gate |
|
|
90
|
-
| `node scripts/audit.ts` | With the app running: every page and embed view at 2560, 1440, 1024, 768 and 390px in both themes (embeds at 720 and 420 on a simulated host ground). Fails on sideways scroll, text clipped without an ellipsis, a control with no accessible name, more than one page scroller, rendered text under its WCAG minimum, a Tab stop with no
|
|
90
|
+
| `node scripts/audit.ts` | With the app running: every page and embed view at 2560, 1440, 1024, 768 and 390px in both themes (embeds at 720 and 420 on a simulated host ground). It measures inside open shadow roots too. Fails on sideways scroll, text clipped without an ellipsis, a control with no accessible name, more than one page scroller, rendered text under its WCAG minimum, a Tab stop with no focus ring (a change of outline, shadow or border when focus arrives), a custom element it cannot look inside (`unmeasured:`), and any uncaught exception or console error. Prints the design metrics: type sizes, weights, radii and the hierarchy ratio | Before release |
|
|
91
91
|
| `node scripts/audit.ts --atlas` | With the app running: the same audit over the Design Atlas, every card's page and its bare preview, at 1440 and 390px in both themes, about ten minutes. Not part of `pnpm verify`, which stays fast: a card's preview is where a defect in its own box shows, so run it after changing a component | After changing a component |
|
|
92
|
-
| `node scripts/interactions.ts` | With the app running: presses every control on every page (mouse at 1440px, taps at 390px) and follows every link. Fails on a control that changes nothing, one something covers, and a link that answers 4xx | Before release |
|
|
92
|
+
| `node scripts/interactions.ts` | With the app running: presses every control on every page (mouse at 1440px, taps at 390px) and follows every link. Reaches controls inside open shadow roots. Fails on a control that changes nothing, one something covers, and a link that answers 4xx | Before release |
|
|
93
|
+
| `node scripts/keyboard.ts` | With the app running: Tab through each page until focus comes back round, then Shift+Tab back. Fails on a stop with no focus ring, a control hidden under the sticky bar, a visible control never reached, and a reverse order that differs | Before release |
|
|
93
94
|
| `pnpm verify` | The gate once, one production build, the route policy, the size checks and a smoke of up to three routes on desktop and the phone drawer; ends with a coverage line, and the report is in `out/verify.txt` | Before finishing any change |
|
|
94
95
|
| `pnpm verify --full` | The navigation of every rail route, then every exhaustive suite: the audit, every control pressed and link followed, the keyboard walk, the assistant, the live data and Web Vitals | After a change to shared components, the shell or data, and before release |
|
|
95
96
|
| `pnpm verify --perf` | The 20-sample navigation protocol; combine with `--full` to run both without repeating the gate or the build | When timing is what changed |
|
|
@@ -100,7 +101,7 @@ Write the status on the line under the title: `Status: beta`.
|
|
|
100
101
|
|
|
101
102
|
1. Add an entry to `CHANGELOG.md` under a new version. Semver: a removed or renamed token, prop or card is major; a new card, token or variant is minor; a corrected value is a patch. Say in one line what breaks and what to do instead.
|
|
102
103
|
2. `node cli/scripts/set-version.ts <v>`, then `pnpm gate` until it passes. Nothing else runs locally: the release workflow's gates are the proof.
|
|
103
|
-
3. Commit and push to `master`, then dispatch once: `gh workflow run release.yml -f version=<v>`. The workflow gates on the package's own tests (`tests/cli-*`), one timed default `verify` (whose gate leaves
|
|
104
|
+
3. Commit and push to `master`, then dispatch once: `gh workflow run release.yml -f version=<v>`. The workflow gates on the package's own tests (`tests/cli-*`) and the browser-fixture tests of the checks (`tests/deep-*`), one timed default `verify` (whose gate leaves both groups out) and the consumer smoke from the tarball, publishes with provenance, checks the registry's tarball is the tested one, and tags last. `verify --full --perf` runs weekly (`.github/workflows/weekly.yml`), not here.
|
|
104
105
|
|
|
105
106
|
The `/release` command (`.claude/commands/release.md`) is this procedure as a runbook.
|
|
106
107
|
|
package/payload/README.md
CHANGED
|
@@ -72,8 +72,8 @@ Dark is the default, written on `:root`; the light theme follows the operating s
|
|
|
72
72
|
| `docs/` | Guides: surfaces, agents, the assistant, starting a dashboard, data display, voice, the benchmark |
|
|
73
73
|
| `decisions/` | One record per lasting decision |
|
|
74
74
|
| `scripts/` | Generators, gates, `brand.ts` and `verify.ts` (see `CONTRIBUTING.md`) |
|
|
75
|
-
| `skills/zz-meridian/` | The agent skill (Claude Code, Codex) that builds dashboards on this template or brings it into yours |
|
|
76
|
-
| `cli/` | The `zz-meridian` npm package: `create`, `adopt`, `update`, `brand` and `skill`, its build, its smoke test and the fixture
|
|
75
|
+
| `skills/zz-meridian/` | The agent skill (Claude Code, Codex) that builds dashboards on this template or brings it into yours, to the standard in `references/standard.md`; how it is evaluated is `docs/skill-evals.md` |
|
|
76
|
+
| `cli/` | The `zz-meridian` npm package: `create`, `adopt`, `update`, `brand` and `skill`, its build, its smoke test and the fixture apps (`docs/distribution.md`) |
|
|
77
77
|
| `.github/workflows/release.yml` | The release, each check once: a timed default verify and the consumer path from the tarball (the release before updated; the last three weekly), then npm with provenance, the registry's bytes and provenance checked, then the tag (`.claude/commands/release.md`) |
|
|
78
78
|
| `.github/workflows/weekly.yml` | Weekly, never at release: `verify --full --perf` (perf a report) and the consumer smoke's recovery and failure cases; nothing waits on it |
|
|
79
79
|
| `Dockerfile`, `captain-definition` | The demo deployment: the template and the Atlas behind `DEMO_PASSWORD` (`proxy.ts`, `app/sign-in/README.md`), deployed to CapRover from this repository; never in the package |
|
|
@@ -83,7 +83,15 @@ Dark is the default, written on `:root`; the light theme follows the operating s
|
|
|
83
83
|
Give your coding agent (Codex, Claude Code, or any agent that can run a shell) this, with what you want in your own
|
|
84
84
|
words at the end:
|
|
85
85
|
|
|
86
|
-
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words].
|
|
86
|
+
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.
|
|
87
|
+
|
|
88
|
+
In Claude Code or Codex, send it as a goal (`/goal Run npx zz-meridian@latest skill --global, then …`): the agent keeps
|
|
89
|
+
working until the condition holds, and a separate model checks it after every turn against the hand-over, which quotes
|
|
90
|
+
its evidence. The sentence says what you want; the skill carries how good it has to be. It builds, renders every view
|
|
91
|
+
at phone and desktop width in both themes, scores each one on a scoreboard of floors (measured by `pnpm verify --full`)
|
|
92
|
+
and craft (judged on the renders), and improves it round by round until nothing is weak, deciding what it can find out
|
|
93
|
+
and recording each decision it made for you. You get the finished product, the renders, and the few questions only you
|
|
94
|
+
can answer.
|
|
87
95
|
|
|
88
96
|
You do not choose between the package's commands; the skill does, from what you said and what is in the folder, and
|
|
89
97
|
names the route before it runs anything:
|
|
@@ -127,6 +135,7 @@ pnpm dev # the template at /, the Design Atlas at /system
|
|
|
127
135
|
pnpm gate # tokens fresh, registry fresh, specs consistent, contrast in every theme and accent, types, tests
|
|
128
136
|
pnpm verify # the gate once, one production build, the size checks and a smoke of up to three routes
|
|
129
137
|
pnpm verify --full # every route, every control and link, the keyboard walk, the assistant and the live data
|
|
138
|
+
# (the browser suites look inside open shadow roots; validation.md says what each line means)
|
|
130
139
|
pnpm brand --name "Acme" --hue 25 --chroma 0.16 # rename and rebrand in place
|
|
131
140
|
```
|
|
132
141
|
|
|
@@ -33,6 +33,8 @@ The same bar, held for the second operator. An agent judges a view by what it is
|
|
|
33
33
|
|
|
34
34
|
With no assistant configured, or switched off, and outside any host, no agent control appears: on a build with no `ASSISTANT_*` variables the audit found 0 issues on 22 routes, 327 controls and 56 links pressed with 0 issues, the keyboard walk 0, and none of 8 pages and views showed a launcher, a panel or an Ask.
|
|
35
35
|
|
|
36
|
+
Those figures were measured before the suites looked inside open shadow roots. A product that uses web components is now measured there too, and a custom element the audit cannot look inside is reported as `unmeasured:` rather than passed (`skills/zz-meridian/references/validation.md`).
|
|
37
|
+
|
|
36
38
|
## What changed because of the benchmark
|
|
37
39
|
|
|
38
40
|
- **The register** (decision 0002). The first render, a neutral light canvas with 28px titles and four equal tiles, was rejected as dated. Meridian adopted that register: dark first, a lit ground, a dramatic type scale, one featured card.
|
|
@@ -6,7 +6,7 @@ Status: v1 (`create`, `adopt`, `skill`) shipped in 0.2.0 (decision 0009). v2 (`u
|
|
|
6
6
|
|
|
7
7
|
A team gives its coding agent this, with what it wants in its own words at the end:
|
|
8
8
|
|
|
9
|
-
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words].
|
|
9
|
+
> Run `npx zz-meridian@latest skill --global`, then follow the zz-meridian skill it installs to: [what you want, in your own words]. Done when its hand-over says the Meridian standard is met, or names what only I can decide or provide.
|
|
10
10
|
|
|
11
11
|
The sentence names no command, because people do not: "change this product into our dashboard", "a new one based on
|
|
12
12
|
this folder, in another folder" and "build an orders console" all ask for a dashboard on Meridian and differ only in
|
|
@@ -15,6 +15,14 @@ which folder holds it. The skill's "Choose the route" table maps what was said,
|
|
|
15
15
|
written) or `update` and `brand` (a project that already has Meridian), and says the route before the first command.
|
|
16
16
|
An earlier sentence named `adopt`, the wrong command for every request for a new dashboard.
|
|
17
17
|
|
|
18
|
+
The sentence is written to be sent as a goal (`/goal` in Claude Code and Codex), which keeps the agent working until a
|
|
19
|
+
separate model, reading the conversation after every turn, finds the condition met. That model sees the sentence, not
|
|
20
|
+
the skill, so the sentence ends with a condition the transcript can show: the hand-over (SKILL.md, step 7) quotes
|
|
21
|
+
`pnpm verify --full`'s last line and the scoreboard's count, or names what only the person can decide or provide. The
|
|
22
|
+
degree lives in the skill, never in the sentence: `skills/zz-meridian/references/standard.md` holds the register, the
|
|
23
|
+
scoreboard of floors and craft kept for every view, the loop run until nothing is weak, and which decisions the agent
|
|
24
|
+
makes and records and which wait for the person. People do not say how good it has to be, so the skill does not ask.
|
|
25
|
+
|
|
18
26
|
The split follows what each part is good at. The package does the settled work, the same way every time, and proves it
|
|
19
27
|
built: what to copy, which dependencies to merge, the alias, the stylesheet, the brand. The agent does the judgement:
|
|
20
28
|
rebuilding each page on Meridian's components, the fake API, and reading what `pnpm verify` finds.
|
|
@@ -205,8 +213,9 @@ Modelled on the release pipeline of the owner's earlier packages, one package in
|
|
|
205
213
|
|
|
206
214
|
1. **Dispatch**: `gh workflow run release.yml -f version=<v> [-f dry_run=true]`, from `master`. The version must equal
|
|
207
215
|
`cli/package.json`'s and the tag must be unused.
|
|
208
|
-
2. **Gates** (ubuntu-24.04, 4 CPUs, the reference profile), each run once: the package's own tests (`tests/cli
|
|
209
|
-
no adopted or created project has
|
|
216
|
+
2. **Gates** (ubuntu-24.04, 4 CPUs, the reference profile), each run once: the package's own tests (`tests/cli-*`) and the
|
|
217
|
+
browser-fixture tests of the checks (`tests/deep-*`), which no adopted or created project has and the timed default
|
|
218
|
+
`verify` leaves out; the template's default `verify` from a clean `.next` through
|
|
210
219
|
`cli/scripts/release-check.ts`, within 180 s on the shared runner (whose CPU varies: one commit measured 111 s on one
|
|
211
220
|
and 152 s on another) and with its browser smoke (the gate and the template's unit tests run
|
|
212
221
|
inside it); and the consumer smoke from the built tarball (step 4). The full, perf and recovery suites are never
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Evaluating the skill
|
|
2
|
+
|
|
3
|
+
A person gives their agent one sentence (`docs/distribution.md`), and the skill carries everything the sentence leaves
|
|
4
|
+
out: the standard, the definition of done, and how the agent evaluates its own work
|
|
5
|
+
(`skills/zz-meridian/references/standard.md`). When those three are right, an agent that follows the skill reaches the
|
|
6
|
+
standard on the person's project. So a change to the skill is judged by whether an agent reading it chooses the right
|
|
7
|
+
route, decides instead of asking, knows what done means and how it will know, and finds the defects that keep a product
|
|
8
|
+
from it. Rebuilding a whole dashboard to judge a change in wording is not needed.
|
|
9
|
+
|
|
10
|
+
## Four levels
|
|
11
|
+
|
|
12
|
+
| Level | What it shows | Cost | When |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| L0 static | Every path, command and flag the skill names exists (`node scripts/check.ts`); the text has no dated or contradictory instruction (a prompt audit, `/claude-api prompt-audit`) | seconds | every change to the skill |
|
|
15
|
+
| L1 decisions | An agent reads the skill in a scenario's folder and stops before the first command that writes: its route, its announcement, its decisions, its brief, the views it will score, its definition of done and how it will evaluate | 2 to 5 minutes each, run side by side | a change to the route, the decisions, the brief or the standard |
|
|
16
|
+
| L2 planted defects | An agent runs the loop on a built Meridian project with known defects planted (a clipped name, a missing empty state, a literal colour, a wrong total, a page with no protagonist, a stale `verify.config.ts` route): which it finds, which it fixes, and whether it stops only when `--full` prints the outcome | about 15 minutes | a change to the standard or the loop |
|
|
17
|
+
| L3 end to end | The sentence, a fresh agent and a real request, from nothing (greenfield) or an existing app (brownfield) to the hand-over | 1 to 2 hours each | weekly, never per change |
|
|
18
|
+
|
|
19
|
+
## L1 scenarios
|
|
20
|
+
|
|
21
|
+
Each runs in a scratch folder. A scenario that starts from an existing app copies its fixture there, renames
|
|
22
|
+
`fixture.env` to `.env` (an address on a reserved domain that stands for production), and commits it, so the folder is
|
|
23
|
+
the clean repository a team would have.
|
|
24
|
+
|
|
25
|
+
| Scenario | Folder | The request after "to:" | What a right answer does |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Greenfield | empty | build an orders console for our bakery chain, three shops; today's orders, late pickups, which cakes sell best | `create .`; pages that answer the three questions; timezone, currency and "late" recorded as decisions; deletes the sample pages it does not need |
|
|
28
|
+
| Next.js brownfield | `cli/test/fixture-crumb-ops` | make our ops console look and work like a professional product, and let the shop leads see late pickups at a glance | `adopt` in place; finds `API_URL` is production before running anything; fake API first, committed, with a request log; "before" renders; lists every route and action that must survive; keeps `lib/api.ts` |
|
|
29
|
+
| Vite brownfield | `cli/test/fixture-vite-rota` | turn our rota app into a proper dashboard for the ward managers | `create` beside it, never in it; ports both routes and the one request; "before" from a copy; names the cookie and CORS change of a read moved to the server; switching over is the person's |
|
|
30
|
+
| Update | a project made with `create --no-install`, committed | update Meridian to the latest | `update --dry-run` first; already current means it says so and stops |
|
|
31
|
+
| Rebrand | the same | change our brand colour to #D97706 | `brand` with the manifest's version; sees the amber is 10° from the warning hue; nearest safe hue as the accent, the exact colour in the logo, recorded, no question |
|
|
32
|
+
| Ambiguous | `cli/test/fixture-crumb-ops` | build me a dashboard for this | one question at most, the route, with the recommendation first; without an answer it takes the recommendation and says so |
|
|
33
|
+
| Based on | `cli/test/fixture-crumb-ops` | based on this folder, make a new dashboard in ../crumb-v2 | `create ../crumb-v2`; reads the source and never writes it; ports its data layer and its contract |
|
|
34
|
+
| A project with its own register | a Meridian project with a `docs/register.md` for a fictional company with a light-first design language of its own (its theme default, signature elements, anti-defaults and a brand route), committed | restyle the settings page and add a billing page | reads `docs/register.md` before building; scores Colour, Typography, Hierarchy and Originality against it, and names it on the scoreboard's "Register:" line; keeps every floor, required state and accessibility check unchanged; follows its brand route instead of `brand`'s accent rules; refuses a register line that lowers a floor (a looser contrast, a skipped state) and records the refusal as a decision |
|
|
35
|
+
|
|
36
|
+
Every scenario is also held to what is true of all of them: the agent reads `standard.md` before building, asks nothing
|
|
37
|
+
but the route, says the route before the first command, records decisions with their reasons, lists every view it will
|
|
38
|
+
score, and states the definition of done as the commands and lines that will prove it.
|
|
39
|
+
|
|
40
|
+
The probe is given the sentence, told where the skill and the local CLI are, told to write nothing, and asked for, in
|
|
41
|
+
order: its announcement, the route and first commands, its decisions, the brief, the views, the definition of done and
|
|
42
|
+
how it will know, how it will evaluate each view, its questions, and what in the skill was unclear, contradictory or
|
|
43
|
+
missing, with `file:line`. Run at least one scenario on a smaller model than the one the skill is written with: the
|
|
44
|
+
skill is for anyone's agent.
|
|
45
|
+
|
|
46
|
+
## Reading the results
|
|
47
|
+
|
|
48
|
+
Write what a right answer does before the probes run, and grade against it. A finding counts when the skill caused it:
|
|
49
|
+
a contradiction, a path that does not resolve, a case it does not cover, a step that would stop an unattended run, a
|
|
50
|
+
definition of done that cannot be reached. A finding that comes from the probe's own context (a memory or rule of the
|
|
51
|
+
machine it ran on) is not the skill's. Fix each counted finding in the skill or in Meridian's code, and run the
|
|
52
|
+
scenarios it touched again.
|
|
53
|
+
|
|
54
|
+
## What each level finds
|
|
55
|
+
|
|
56
|
+
Each level finds what the ones below it cannot, which is why none replaces another:
|
|
57
|
+
|
|
58
|
+
- **L1** finds what reading the skill against the code shows: a definition of done the scripts make unreachable (the
|
|
59
|
+
first round found that the walk-throughs drove the template's own sample pages, so no product could pass), a step
|
|
60
|
+
that would stop an unattended run, a contradiction between two files, a case no route covers.
|
|
61
|
+
- **L2** finds where judging by eye is not enough. Of six planted defects an agent found five; the one it missed, a
|
|
62
|
+
second featured metric, became a rule in `scripts/check.ts`. A rule the code can check is checked there, not left to
|
|
63
|
+
the scoreboard.
|
|
64
|
+
- **L3** finds what only building shows: the gate misreading an adopted project's imports, a phone card's badge over
|
|
65
|
+
a long name, a verify that crashed on its own early exit. Each became a fix with a test, so the weekly run that
|
|
66
|
+
found it does not have to find it again.
|
|
@@ -73,4 +73,4 @@ pnpm verify # the gate once, one production build, the size checks and
|
|
|
73
73
|
pnpm verify --full # every route, every control pressed and link followed, the keyboard walk, the assistant and the live data
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
`pnpm verify` is the check to run before you finish. Run `--full` after a change to shared components, the shell or data. Every run ends with a coverage line, such as `coverage: default; browser ran; 3 routes; data configured 3/3; interaction configured 3/3; not run: audit, presses, keyboard, assistant, live, vitals`, which says what ran and what did not. Nothing that did not run is reported as passed. `pnpm verify --perf` adds the 20-sample navigation protocol and reports it; a p95 over its budget is a `warn`, never a failure. The default is built to finish within two minutes; `--full` and `--perf` are what a team schedules, weekly for instance.
|
|
76
|
+
`pnpm verify` is the check to run before you finish. Run `--full` after a change to shared components, the shell or data. Every run ends with a coverage line, such as `coverage: default; browser ran; 3 routes; data configured 3/3; interaction configured 3/3; not run: audit, presses, keyboard, assistant, live, vitals`, which says what ran and what did not. Nothing that did not run is reported as passed. `pnpm verify --perf` adds the 20-sample navigation protocol and reports it; a p95 over its budget is a `warn`, never a failure. The browser suites look inside open shadow roots, so a web component's content is measured, pressed and walked like any other; a custom element they cannot look inside is reported as `unmeasured:`, and a selector in `navigationChecks` that matches several elements prints a `note:`. `skills/zz-meridian/references/validation.md` says what each line means and what to do about it. The default is built to finish within two minutes; `--full` and `--perf` are what a team schedules, weekly for instance.
|
package/payload/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zz-meridian-template",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "ZZ Meridian: a dashboard design system and starter. DTCG tokens, five layers of React components and a Design Atlas, in a light and a dark theme.",
|