Skip to content

docs(specs): interactive prototype skill, decoupled from any one design system - #91

Merged
matgren merged 3 commits into
mainfrom
spec/interactive-prototype-skill
Sep 1, 2026
Merged

matgren merged 3 commits into
mainfrom
spec/interactive-prototype-skill

Conversation

@matgren

@matgren matgren commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

🎯 Goal

Give the designer role the step it is missing: a screen a reviewer can click through and comment on before implementation starts. Today the role covers static mockups on a spec PR (om-auto-write-spec), a design review of running UI (om-ux-review-pr), contract extraction (om-ux-setup) and direction-setting (om-ux-shape) — but nothing between the last two produces an artifact a non-developer can operate.

📝 What this PR contains

A spec only. No skill code lands here yet — .ai/specs/2026-08-26-interactive-prototype-skill.md.

An interactive prototype skill with an anchored-comment engine already exists upstream (click-through with visited-screen history, presentation mode, comment pins on elements, localStorage persistence, append-only operation log with tombstones, re-anchoring for orphaned comments, export back into the repo). It is stranded on a branch whose two PRs were closed unmerged, and it is bound to one design system. This spec generalizes it in three layers.

Layer 1 — base tokens: consume what shipped. The sync script stops being a parser for one stylesheet (block reader, declaration parser, group assertions, hard thresholds, required token names) and reads a committed token snapshot instead: 124 tokens, each carrying light and dark in one record. The theme split arrives as data rather than being reconstructed from a file's block structure.

Layer 2 — theming contract: substitute, seam at a file boundary. Each prototype carries a theme.css with eight identity tokens (primary + hover + foreground, two brand accents, radius, two font stacks); everything else is a semantic contract stated in the file header. Radius cascades through calc() to the whole scale, so one value re-rounds every surface. This is what makes a prototype directory self-contained: rebranding is editing eight values in one file, with no build step and no network.

Layer 3 — visual primitives: keep, drop the claim. The bundled stylesheets stay but stop asserting they mirror a specific component library. Measured example of why: the real button renders 2.25rem tall with 1rem horizontal padding, the prototype 2.25rem with 0.75rem, because the icon-bearing variant was transcribed as the default. That is the steady state of a hand-maintained copy, not a one-time slip.

Each layer names the seam where an upstream artifact replaces it, so the eventual swap is a file change rather than a rewrite.

🔍 Gates checked against the current tree

Gate State
bash scripts/lint.sh Lint OK on this branch
Frontmatter budget Imported skill already inside limits (description 428/500, body 6,353/20,000)
Roster sync One name to add in om-setup-agent-pipeline/references/skill-coverage.md (Phase 2)
Reference resolution Three standard files to add; one dangling cross-skill pointer to drop (Phase 2)
Tracker abstraction Not applicable — the skill performs no tracker operations
Layout convention Imported assets/ folds under references/assets/, following the nested-directory precedent

The spec is written product-agnostically throughout: zero occurrences of the upstream product name, scoped package name, or monorepo paths, even though .ai/specs/** sits outside the lint's scope.

⚠️ One open question, deliberately not decided here

The upstream composer specification limits this skill to backend/backoffice journeys and routes portal, storefront and public frontend elsewhere. Inside that monorepo the routing resolves; in this collection it does not, because the composer depends on a product module and its component registry, and "backoffice" has no referent in an arbitrary repository.

The spec proposes restating the boundary in terms of the question rather than the surface — this skill answers "does this flow make sense", a design-system composer answers "is this screen faithful to the system" — and explicitly leaves the call to the design-system track owner. The storage split and division of labour are unaffected either way.

🚀 Rollout

The original extraction plan had three phases across two repositories: upstream decoupling, an additive collection PR, and upstream consumption. Its Phase 1 → Phase 2 merge ordering is historical for #106, subject to the confirmation below. Both new config keys remain optional with working defaults.

2026-09-15 amendment for #106: @matgren accepted replacing the upstream-first prerequisite with a verified import from pinned upstream commit 9ea83205be7447867c042bbcfd3caaa9b4cadfb5. After the rename to om-ux-design and its detailed-design changes, this collection is the source going forward.

The amended specification and import verification record require:

  1. The pinned source and complete source-to-destination mapping: all 13 files are accounted for under skills/om-ux-design/.
  2. All intentional differences explained; four CSS files are byte-identical and all 124 token records are unchanged apart from provenance metadata.
  3. Retained browser/upstream evidence and the collection's configured validation on the current feat(skills): add om-ux-design for detailed prototypes and review #106 head. Later implementation changes require updated comparison and relevant checks.
  4. @pkarw's explicit confirmation of the revised condition and fresh review of the current feat(skills): add om-ux-design for detailed prototypes and review #106 head before blocked is removed.

Once that condition is confirmed and the evidence accepted, upstream open-mercato/open-mercato#5832 merging is no longer a prerequisite for #106. Upstream consumption remains a separate follow-up. The amendment itself does not clear blocked or authorize merging.

🤖 Generated with Claude Code

https://claude.ai/code/session_015epM2Y2bFvMz7VC679NMs1

…gn system

The designer role can attach static mockups to a spec, walk a PR's UI in a
browser, extract the design contract and decide a direction, but nothing hands
a reviewer a screen they can click through and comment on before implementation
starts. An upstream skill with that engine exists and is stranded on a branch
whose PRs were closed unmerged, bound to one design system.

Three layers, each with an explicit seam. Base tokens come from a committed
snapshot rather than a parser for one stylesheet. Branding sits behind a
theme.css carrying eight identity tokens, so a prototype directory renders with
no build step, no network and no installed design system, and rebranding is one
file. The hand-written component layer stays but drops its claim to mirror any
specific component library.

Leaves the surface-boundary question to the upstream design-system track owner
rather than deciding it here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015epM2Y2bFvMz7VC679NMs1
@matgren matgren added documentation Improvements or additions to documentation priority-medium Ordinary bug or feature review Ready for code review risk-low Isolated, low blast radius skip-qa Low risk, QA not required labels Aug 26, 2026
@zielivia

Copy link
Copy Markdown
Contributor

Review — spec verified against both repositories, plus a hands-on test of the upstream skill

I reviewed the spec against the current state of this repo and the upstream monorepo, and additionally ran the upstream om-mockup-prototype end-to-end (real requirements doc → story-gated init → 6 screens → browser walkthrough of the engine) to judge whether the skill this spec wants to import actually earns its place. It does — the import is worth doing, and most of the spec's claims check out exactly. Three things need fixing before merge, one scope gap is worth stating explicitly.

What I verified as accurate

  • The three couplings are real, verbatim: sync-tokens.mjs hard-codes the application stylesheet path and asserts block structure with the ≥40-tokens-in-dark threshold; the repo root is resolve(SKILL_DIR, '../../..'); the bundled stylesheets reference ~62–64 custom properties with no fallbacks. Feeding the sync a differently-structured stylesheet fails immediately (Could not find the .dark block), as the spec predicts.
  • The committed token snapshot exists as described: 124 tokens, light+dark in one record, with kind / theme-invariance / framework alias. Layer 1 has a real artifact to consume.
  • The gate inventory matches scripts/lint.sh exactly; frontmatter numbers are correct (body 6,353 chars — I recounted); bash scripts/lint.sh prints Lint OK on this branch.
  • The Layer 2 mechanism works today: the radius scale already cascades via calc() in the generated tokens.css, so I dropped an eight-token theme.css (different primary, accents, radius, font stacks) after the base and the whole prototype rebranded in both themes — no build step, semantic status colors untouched. The spec's central bet is technically sound on the current base.
  • Layer 3's diagnosis is empirically right: authoring screens against the bundled CSS, I hit an unstyled gap within minutes (.dt-search has no icon sizing rule — screens.css:207 — so the search icon renders unconstrained). That is the "steady state of a hand-maintained copy" the spec describes.

1. The "stranded" narrative contradicts the upstream state (blocking)

The Problem Statement rests on: "It is stranded. It lives on a branch whose two pull requests were closed without merging, 50 commits ahead of and 50 behind." But the skill — with the complete engine this spec praises (re-anchoring, tombstones, presentation mode, visited-screen history) — merged upstream in #4353 on 2026-08-02 and lives on the default branch at .ai/skills/om-mockup-prototype, unchanged since. That branch produced exactly one PR (the merged one) and was deleted. I could not find any closed-unmerged PR pair or a 50/50 branch.

Either the claim refers to something not publicly visible — then the spec must name the branch and PR numbers, because Phase 1 never says what the import source is (the merged copy vs. that branch), and if post-merge improvements exist, rescuing them is an unstated Phase 0 — or the narrative is stale and should be rewritten. The coupling argument alone carries the spec; the strandedness argument, as written, is false.

2. Add a "Concrete pointers" appendix (blocking)

The spec applies product-agnostic writing to itself even though it acknowledges .ai/specs/** is outside the lint's scope. The cost: I had to reverse-engineer that "the committed token snapshot" = .ai/ds/ds-tokens.json, "an open upstream change" (theming) = #4306, "the composer draft carrying requested changes" = #4319. Phase 1's implementer will repeat that archaeology, and the trails will be colder. One short appendix with repo names, PR numbers, branch names, and file paths makes the plan executable.

3. Phase 2 needs an explicit seam for repo-local screen anatomy (requested change)

Half of the skill's review value sits in references/screen-patterns.md — the real AppShell/DataTable/CrudForm anatomy with the "four easy mistakes". The spec correctly moves product anatomy into the consuming repo's override, but says nothing about what a repository without such a file gets: a neutral skeleton, which still answers "does this flow make sense" but loses the "looks like our product" fidelity that makes stakeholders engage. Phase 2 should either require the repo-local override to provide a screen-anatomy reference or scaffold a template for one (om-ux-setup's extracted contract is a natural source). Otherwise the portable version quietly ships with half the value.

4. State the viewport scope (worth a sentence)

The bundled screens are desktop backoffice anatomy: at a 375px viewport the 240px sidebar crushes the content — there is no mobile shell, by design, since upstream routes portal/storefront elsewhere. The engine itself is viewport-agnostic. The spec should say explicitly that prototypes review desktop flows, and that mobile-first journeys are out of scope until someone contributes mobile screen patterns — right now a reader could reasonably assume otherwise.

Minor

  • Contract-inventory table: "all 36 skills carry only references/" is not quite true — om-ux-shape also ships agents/. The nested-directory conclusion still holds.
  • Re-anchoring can be silently wrong: when I restructured a commented button row, the thread stayed matched via its positional selector to the replacement button. Fine here, but the orphan state only triggers on outright selector failure — worth one line in the eventual skill's verification checklist.

Verdict

The gap is real (nothing between om-ux-shape and om-ux-review-pr produces an operable artifact), the engine is genuinely good — comment threads anchored to elements survived reload in my test, storage is namespaced per prototype, the story-gate forces unhappy-path coverage (4 of my 6 screens were empty/error/permission states) — and the three-layer decoupling preserves what carries the value. Approve once items 1–2 are fixed and item 3 is addressed in the plan.

…inters, anatomy seam

Review items from PR #91: rewrite the problem statement around the coupling
argument (the skill merged upstream and is stable, the stranded claim was
stale), add a concrete-pointers appendix so Phase 1 needs no archaeology,
give Phase 2 an explicit screen-anatomy seam (shipped template scaffolded
into a missing override, pre-filled from the om-ux-setup contract), state
the desktop-only viewport scope, correct the contract-inventory row for
om-ux-shape's agents/, and extend the engine checklist with the silent
re-anchoring mismatch case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RQCTKTh9VrTnLqSQHCS8rH
@matgren

matgren commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the hands-on review — all items addressed in 18c468e.

  1. Stranded narrative: you're right, it was stale. I re-verified against upstream: the skill merged via #4353 (commit f9b7fbae4, 2026-08-02) and sits unchanged on main; I also swept every remote branch for post-merge changes to .ai/skills/om-mockup-prototype and found none, so there is no Phase 0 to rescue and the import source is unambiguous. The problem statement now rests on the coupling argument alone and states this.
  2. Concrete pointers: added as an appendix — repo, import source with commit, .ai/ds/ds-tokens.json, #4306, #4319 (with the boundary-decision changelog), the coupled script paths, screen-patterns source, the deferred sibling, and the feat(skills): om-ux-shape, om-ux-setup, om-ux-review-pr — the UX judgment layer #57 precedent.
  3. Screen-anatomy seam: Phase 2 gains step 13 — the skill ships a product-stripped anatomy template and, when initialization finds no repo-local override, scaffolds it into the override path, pre-filled from the om-ux-setup contract when the repo has one, guided prompts otherwise; the hand-off names the anatomy source. Architecture and the edge-case table state what a repo without an override gets.
  4. Viewport scope: stated in non-goals — desktop backoffice flows only, engine viewport-agnostic, mobile patterns a contribution seam.

Minor: inventory row corrected (35 of 36; om-ux-shape ships agents/), and the engine checklist now requires the restructured-screen case — verifying a surviving pin still points at the element its thread discusses, not just that no orphan state fired.

bash scripts/lint.sh still prints Lint OK.

@zielivia

Copy link
Copy Markdown
Contributor

Re-checked 18c468e against both repositories — all four items land, and I verified the claims rather than taking them at face value.

Origin story. The appendix is precise where it needs to be: main is the upstream default branch, the skill is there, f9b7fbae4 is reachable from it, and the skill tree is byte-identical on main and develop (9ea2805…). My own branch sweep also found nothing carrying post-merge changes. The import source is now unambiguous.

Appendix pointers. All nine resolve: the snapshot and its README, both DS specs, #4306, #4319 (open, stacked on the merged #4301), the coupled scripts, screen-patterns.md, the deferred sibling, and #57. The cited 2026-08-02 changelog entry in the composer spec does hold the storage-split boundary decision.

Anatomy seam. This goes further than I asked — shipping the template and scaffolding it into a missing override, pre-filled from the om-ux-setup contract, with the hand-off naming the source, closes the "portable version ships with half the value" gap rather than just documenting it.

Viewport scope and both minors are in, and the re-anchoring criterion now names the failure mode precisely: a positional selector silently matching a replacement element, verified per surviving pin rather than by absence of an orphan state.

bash scripts/lint.sh prints Lint OK on the new head.

One small tension, noted rather than blocking: step 13 introduces behavior the upstream skill does not have (scaffolding the override), so it lands in Phase 2 without the Phase 1 proof against a real design system that D5 asks for. It carries its own verification and is exercisable by running the initialization script in any repository, so this is a sequencing observation, not an objection — worth a sentence in the step if you want D5 to stay airtight.

Both blocking items are resolved from my side.

The override scaffolding is new behavior, not decoupled behavior: it
touches no design-system surface and verifies in any repository, so it
does not require the upstream Phase 1 proof.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RQCTKTh9VrTnLqSQHCS8rH
@matgren

matgren commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Good catch on the sequencing — addressed in d62306d. Step 13 now states its relation to the D5 gate directly: the scaffolding is new behavior rather than decoupled behavior, it touches no design-system surface, and its verification runs in any repository, so it sits outside what D5 gates. Lint still prints Lint OK.

With both blocking items resolved on your side, this is ready for your formal approve whenever convenient.

@matgren

matgren commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

@zielivia one more thing worth settling now rather than at Phase 1 review: the spec's open question is addressed to you as the DS track owner, and your re-check didn't touch it.

Your composer decision says the prototype skill must not claim portal/storefront/public frontend. Inside the monorepo that routing resolves; in this collection it doesn't — the composer can't travel and "backoffice" has no referent in an arbitrary repository. The spec proposes restating the boundary by question rather than surface: this skill answers "does this flow make sense", a design-system composer answers "is this screen faithful to the system". A generic "mock this screen" request still routes to the composer where one exists, and the storage split is unaffected.

Two concrete asks:

  1. Do you accept the question-based formulation for the collection, with the surface-based rule preserved verbatim in the upstream repo-local override (Phase 3)?
  2. If yes, should the Phase 1 PR update the boundary wording in the composer spec's routing section, or does that stay untouched and only the override carries it?

Either answer unblocks the Phase 1 PR without a second round.

@zielivia

Copy link
Copy Markdown
Contributor

1. Yes — adopt the question-based formulation for the collection. This skill answers "does this flow make sense"; a design-system composer answers "is this screen faithful to the system". It holds in any repository, needs no notion of "backoffice", and preserves the original intent: a generic "mock this screen" request still routes to the composer wherever one exists. The storage split and the division of labour stay exactly as decided on 2026-08-02. The surface-based rule is preserved verbatim in the upstream repo-local override in Phase 3 — inside the monorepo, where portal and storefront have their own paths, that restriction still earns its place.

2. Phase 1 updates the composer spec's routing section. One sentence: the question-based formulation is canonical, and the surface-based rule is its application inside this monorepo. Leaving the spec untouched would have two documents describing the same boundary differently, and the composer spec is the DS track's source of truth — anyone reading "the prototype skill must not claim those surfaces" would reasonably conclude the collection is breaking the rule.

One thing worth fixing in the same edit. The current wording routes portal, storefront, and public frontend requests to "their surface-specific workflows", but no such skills exist upstream — .ai/skills/ has om-backend-ui-design, om-ds-guardian, and om-figma-design-with-ds, and nothing for those three surfaces. om-ds-mockup is also still the unmerged draft in #4319. So today the surface-based rule routes to targets that do not exist even inside the monorepo, which is an independent argument for the question-based formulation. While you are in that section, either name real destinations or state that the surface routing is aspirational until those workflows land.

Nothing else blocks Phase 1 from my side.

@matgren
matgren merged commit c32ba50 into main Sep 1, 2026
2 checks passed
@matgren

matgren commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Tracking implementation in #104 (blocked on upstream Phase 1 in open-mercato/open-mercato).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation priority-medium Ordinary bug or feature review Ready for code review risk-low Isolated, low blast radius skip-qa Low risk, QA not required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants