Make a coding agent design like a designer who did the research:
learn the field, design from cited principles, then walk the journey in real Chrome before it says done.
Paste this to your agent:
Install the
uxcliskill (npx skills add junixlabs/uxcli -g), runnpx -y @junixlabs/uxcli doctor, and from now on readuxcli context show <journey>before you design a screen, draw its variants and runuxcli mockupsbefore you build, and runuxcli runon the final files before you say done.
Or see it work first, in under a minute, on a product with a defect planted on purpose:
npx -y @junixlabs/uxcli demo ./uxcli-demoA coding agent designs from what it assumes. uxcli gives it what a designer who did the research would have, and an instrument to prove the result works for the person using it:
- Knowledge — a library the agent can cite: 187 rules from named designers, design systems and
studies, each with its author, page and exact words, packaged by kind of UI (
marketing,content,data,workspace,shop,transaction) and by topic (colour, writing, data display, forms, navigation, motion and feedback); and templates for kinds of product (workspace,shop,landing) that name the screens, the lens for each, the journeys to walk first and the questions research must answer. - Process — research the field from sources, write insights with evidence and open questions as
unknowns, read
uxcli context showbefore designing, draw variants to the lens, build the one a person picks. - Evidence and versions — every walk of a journey leaves
run.json, screenshots and the trace; picks and revisions are hashed to the drawing they speak of;uxcli maplays the journey out step by step. - Experience validation —
uxcli runwalks the journey in real Chrome and checks what the person goes through, not only how the page is built. Checks proven able to fail may block; designer rules and walkthroughs are reported as findings with their source, never as a pass.
uxcli writes no claim about your users. Every sentence on a card was authored by the project, quoted from a cited source, or measured by the browser.
uxcli studio --serve # http://127.0.0.1:4317 — the project as a canvas, refreshed as the agent worksThe project as the screens a person sees. Each journey is a filmstrip on a canvas: device frames with the
pictures the last walk took, the action and its seconds on the arrow between them, what is wrong pinned
on the picture of the screen it was measured on and said in a sentence. "Fix first" and a to-do bar say
what to do next and take you to it. Layers switch the frames between what was built, what was drawn,
and named versions side by side. Screens, Runs, People (who it is for, what is still a question) and
Library are a tab away. Served, it is also where a person decides — choose a drawing, ask for a redraw,
or leave a note on a screen that becomes a redesign proposal — through the same parsers the files are
read with. One HTML file, free, local, no account; uxcli studio --shot=FILE gives an agent the picture.
uxcli dashboard . ../other-app --serve (http://127.0.0.1:4319) is the studio's page for several folders
at once, switched from the header, another one added from the page. Without --serve it is written to
.uxcli/dashboard/index.html; the card it prints is the coverage matrix — every screen against
understood, drawn, picked, reviewed, walked, verdict, estimate and walkthrough, a gap never a pass.
| Agent | Skill | Instrument |
|---|---|---|
| Claude Code | npx skills add junixlabs/uxcli -g or uxcli init --apply (copies .claude/skills/uxcli/ and a rule file) |
npx -y @junixlabs/uxcli |
| Codex | npx skills add junixlabs/uxcli -g --agent codex |
same |
| opencode | npx skills add junixlabs/uxcli -g --agent opencode |
same |
| Cursor | npx skills add junixlabs/uxcli -g --agent cursor |
same |
npm install -g @junixlabs/uxcli
npx playwright-core install chromium-headless-shell # once, or set UXCLI_CHROME
uxcli doctor # node, Chromium, project, policy — and the fix for eachNode 20+. npx -y @junixlabs/uxcli <command> works without installing.
uxcli init --apply --origin=http://localhost:3000 # a rule file, the skill, .uxcli/ with the floor policy
uxcli template show workspace # the kind of product: screens, lens per screen, what to research
uxcli context show handle-inbound-lead # read before you design
uxcli designer propose P1 # the designer: a catalog formula or preset becomes a kit — library, tokens, component per region
uxcli mockups # the screens drawn as the journey's flow; a person picks
uxcli lens show workspace # named designers' viewpoints for this kind of UI
uxcli review check # every lens review complete, fresh, not contradicted by a probe
uxcli run .uxcli/journeys/handle-inbound-lead.json # measure after
uxcli run http://localhost:3000/leads/1 --prove # one screen: five probes, each pass made to earn it
uxcli experience --page # what the person goes through on each journey, pinned on the screenshots
uxcli map # the journey as screens: declared, observed, the difference, the verdictscontext show prints, in this order: the actor's unknowns[] (so a gap is never turned into a
fact), who the actor is, each insight at the confidence its evidence allows, the states the screen
must be able to hold with the data-uxcli hooks each needs, the commitments already signed over it,
and what the last run saw. It gives no advice.
mockups photographs every variant the agent drew under .uxcli/mockups/<state>/ and writes one
page: each journey as a flow of the picked variants, connected from the element the next step acts
on, and each screen's variants side by side — green picked, amber part of a pick, grey not taken.
A person picks in pick.json; the agent never picks for them. Ticking a variant on the page fills in the
pick.json to write, hash included; the page itself writes nothing. The picked variant is what gets built.
A palette shared in mockups/_shared/tokens.css is covered by the pick's hash, and each variant's
receipt names the colours it paints off that palette. Further viewports (--viewport=1440x900,390x844)
are photographed beside the first, and an element carrying data-uxcli-note gets a numbered pin on the frame.
Each lane plays as a prototype: the hotspot leads to the next picked frame, arrow keys step, Escape closes;
a journey with several lanes plays whole. A variant opens large with its pins and the journey's hooks
outlined where the browser found them (the hooks toggle shows them on the thumbnails too); two variants ticked compare sit side by side;
the journey tabs filter the page to what one journey names. A picture someone made of a screen goes in
refs/ under that screen and is shown as a reference, never as a variant.
lens is a library of viewpoints from named designers and design systems, 187 of them: four schools — usability
(Nielsen, Norman, Krug, Baymard, Wroblewski, GOV.UK), practitioner craft (Wathan & Schoger, Kennedy),
the classic canon (Rams, Vignelli, Müller-Brockmann, Bringhurst, Butterick, Tufte, Gestalt via NN/g) and
modern product craft (Rauno Freiberg, Emil Kowalski, Linear, Vercel, Apple, Material, Ström, Brignull) —
and six topic pools drawn from public design systems and WCAG (colour, writing and microcopy, data
display, forms, navigation, motion and feedback: GOV.UK, USWDS, Carbon, Primer, Polaris, Mailchimp, W3C) —
each with its author, work, page and words, packaged by the kind of UI it is read against: marketing,
content, data, workspace, shop, transaction. Viewpoints that several schools state as one rule
are one line of the checklist. The lenses live inside the skill (skills/uxcli/lenses/<kind>.md, installed
into the project by init), so an agent reads the checklist for its kind of UI before it draws. uxcli review <state>/<variant> --lens=<kind> --write puts an empty review
beside a drawing; the agent answers every viewpoint (holds with where, breaks with where and why, n/a with
why) looking at the photograph, and uxcli review check refuses a review that skips one, is older than the
drawing, or says holds where a probe the viewpoint names counted a break. The mockups page shows each
review on its variant as the reviewer's claim. uxcli holds the library and checks the form; the rules are the
designers', and a review is never a verdict. Every lens is on; .uxcli/lenses.json turns one off, with a name.
map writes one page for the whole project: each journey as a strip of steps on a canvas, with
four views — MODEL (the picked mockups), RUN (the last run's screenshots, each state held or not),
DIFF (declared beside observed) and IMPACT (what the commitments decided) — a side panel per step
(before/after, API, state, evidence, commitment, run) and a findings list. A step is marked drift
only when the run said a state did not hold or a commitment failed there.
run reads each state's signals in the browser — URL, DOM, text, network, accessibility tree,
storage — walks the journey's workflows, provisions identity and fixtures only as far as the policy
allows, and decides every commitment whose scope it reached. Every run leaves
.uxcli/runs/R-<when>-<six>/run.json and its artifacts/; nothing is ever overwritten.
Every line answers the same four questions.
| what | the measurement, with numbers — not "improve contrast" |
| where | the step, the state, the selector |
| rule | the commitment being enforced, its owner, and whether its method is proven |
| check | what you do to see it yourself |
Exit 0 no fail · 2 at least one fail · 1 the run could not be carried out (blocked
by policy, identity or reach — not a UX verdict). Seven verdicts, and five of them are ways of not
blocking: pass · finding · not-applicable · not-committed · unmeasurable · suppressed ·
fail. A finding is a would-be fail from a method not yet validated; it is never a pass.
One directory, five kinds of thing, and the kind decides who writes it and whether git keeps it:
| Kind | Where | Written by | Tracked |
|---|---|---|---|
| authored | understanding/, journeys/, commitments/, profiles/, policy/, project.json |
a person, or an agent with the person's say-so | yes |
| derived, persistent | proposals/ |
an agent or uxcli propose; a commitment cites the proposal it came from |
yes |
| derived, rebuildable | index.json |
uxcli init; delete it and it is rebuilt |
no |
| observed, immutable | runs/R-…/ |
uxcli run; made once, never edited, pruned to seven per target unless anchored |
no |
| runtime only | identity, fixtures | the project's provisioner, under policy | never on disk |
The shape of every file: examples/crm/.uxcli/ and
schemas/. Take the shape, not the facts.
- No commitment, no verdict. A threshold needs a named owner and a written source. W3C is a named owner, so WCAG runs by default; nobody signed taste, so taste never runs.
- A probe that cannot be made to fail on demand may not say
fail. Each ships a fixture where it must fail and a twin where it must pass.uxcli gateenforces it on every push, along with every rule in this README that can be stated as a pair. - A fail is read twice. A page still moving gives a coin flip; a fail stands only if the second
read names the same elements — otherwise
unmeasurable. --provemakes each pass earn it. It plants the defect the probe exists to catch and re-measures.- An unvalidated method may not block. Until a method is validated on unseen pages with 0 false
fails, it reports
findingand cannot change the exit code. - The skill is measured, not asserted. Each load-bearing paragraph in
skills/uxcli/has a record inskills/pair.jsonof what fresh sessions did with it and without it;gatechecks the paragraph is still there by hash. A paragraph without a record says so.
| Scope | Probe | Criterion | Provenance | Method |
|---|---|---|---|---|
| screen | focus-visible |
WCAG 2.4.7 | spec | ✅ 20 unseen pages, 0 false fails |
| screen | contrast |
WCAG 1.4.3 | spec | ✅ 80 unseen pages, 0 false fails |
| screen | text-spacing |
WCAG 1.4.12 | spec | ✅ 80 unseen pages, 0 false fails |
| screen | text-overlap |
text painted over text | opinion | ⏳ unproven → finding |
| screen | nesting |
a box inside a box inside a box (Refactoring UI, Tufte, NN/g) | research | ⏳ unproven → finding |
| journey | every signal in a declared state | the project's own journey | project | decided by the run |
| journey | every measurement in a signed commitment | the project's own commitment | project | method-validated may fail; method-unproven may only find |
uxcli doctor [dir] # is the instrument here; the one command that fixes each missing thing
uxcli demo <empty dir> # a real product with a planted defect, measured end to end
uxcli guide "<what you are about to do>" # which command and which file, for a situation
uxcli init [dir] [--apply --origin=URL] # where the project stands and the first undone thing; --apply creates, never edits
uxcli context show [journey] # what to read before designing
uxcli mockups [dir] [--viewport=WxH[,WxH…]] # every screen's variants photographed; the picked ones as each journey's flow
uxcli lens [show <kind>] # the shipped lenses: named designers' viewpoints by kind of UI
uxcli designer [show | init | check | learn | propose "<formula>"] # the agent as a designer: profile, argued decisions, learned taste, a kit per formula
uxcli template [show <id> | apply <id>] # where to start for a kind of product: screens, lenses, journeys, research questions
uxcli review <state>/<variant> --lens=<kind> --write # an empty review beside a drawing (a URL with --name reviews a screen)
uxcli review check # every review complete, fresh, and not contradicted by a probe
uxcli walkthrough <journey> [--as=<actor>] | check # the four cognitive-walkthrough questions at every step, answered from the screenshots; held to the walk
uxcli version [save <journey> <name>] # name a walk so it is kept; experience --journey=<id> --from=<a> --to=<b> compares two
uxcli experience [dir] [--page] # what the person goes through: steps, typing, scrolls, waits, an estimate in seconds; findings pinned on screenshots
uxcli dashboard [dir …] [--serve] # the management view: coverage matrix, runs, design, understanding; served, several folders
uxcli studio [dir] [--serve] [--shot=FILE] # the board: every journey's screens drawn, built and per version, pan and zoom like a design file; served, a person picks there
uxcli map [dir] # the journey map page: MODEL · RUN · DIFF · IMPACT, step by step, with the evidence
uxcli run <journey.json> # measure a journey --env --origin --viewport --json --out
uxcli run <url> # measure one screen --prove --state=FILE --src=DIR
uxcli sheet [--src=DIR] # design-token commitments in uxcli.commitments.json, no browser
uxcli propose <run dir> # one skeleton commitment per place the run reached that nobody committed to
uxcli migrate [dir] [--apply] # move an older .uxcli/ to the layout this uxcli reads
uxcli diff <a.json> <b.json> # drift between two runs --gate exits 2 on a new fail
uxcli gate # every falsification pair must hold
uxcli why <rule> # a probe's definitionEvery run leaves run.json and its artifacts/ in a directory of its own. That packet is the whole
argument — "it looks fine" is not evidence; a screenshot of the same state is. Two forms at
issues/new/choose: a wrong verdict or a miss,
and an offer of a flow for the unseen list. A confirmed false fail becomes a must-pass case and a
spec revision; a confirmed miss becomes a must-fail case. The outcome is written back on the issue.
Generating UX insight · conformance certification · visual regression · scores · design critique.
Where it is going: ROADMAP.md. The reasoning: VISION.md. Contributing: CONTRIBUTING.md. MIT — see LICENSE.