ui-verification
Original:🇺🇸 English
Translated
Verify whether a live web app matches its design specification using deterministic CSS checks against the DOM, AND verify user flows by executing Gherkin scenarios via Nova Act. Translates design claims into rules and runs them via verify_* MCP tools; executes flows via act() and act_get(). Produces a combined visual + flow report with annotated screenshots and per-flow detail. Use when checking visual style, component rules, accessibility, project conventions, platform patterns, or end-to-end user journeys against a live site.
143installs
Added on
NPX Install
npx skill4agent add amazon-agi-labs/nova-act-agent-skills ui-verificationTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Overview
UI Verification covers two parallel modes against a live web app:
- Visual verification — checks whether the page matches its design specification. Translates design claims into CSS rule checks, runs them against the live DOM via . Deterministic; the browser's computed styles are the source of truth.
getComputedStyle() - Flow verification — checks whether user journeys complete correctly. Executes Gherkin scenarios from files via Nova Act's
.feature(actions) andact()(assertions). Non-deterministic; results vary run-to-run with network timing and live UI shifts.act_get()
Both modes share the skill, the MCP server, and the browser session. A single run can produce both kinds of output, combined into one report. Or either mode can run alone; the other section is omitted from the combined report.
Each run produces:
- Structured artifacts — per-category JSON for visual; per-flow execution data for flows
- Annotated screenshots — red bounding boxes highlighting visual failures on the page
- Verification report — markdown combining a visual summary, a flow summary (per-flow status table), and links to per-flow detail reports
The verify_* tools are deterministic — no vision model, browser's computed styles are the source of truth. The compile and audit passes for visual are LLM-driven (best-effort), reconciling design intent against the app's actual structure. Flow steps are interpreted by Nova Act each run; flow runs are inherently non-deterministic.
Reconciliation inputs
Visual verification. The 5 compiled category files () are reconciled from up to three inputs:
.ui-verification/specs/*.md| Input | What it provides | Required? |
|---|---|---|
| Free-form design intent — tokens, prose, design language, component definitions | Required |
| The running app | Live DOM observed via | Required for verification (informs selectors and validates rules) |
| App source code | Components, theme/tokens, CSS files — implementation truth | Optional. When accessible, makes selectors deterministic and divergence classification more precise |
Flow verification. Flows are authored or generated as files at :
.feature.ui-verification/flows/| Input | What it provides | Required? |
|---|---|---|
| Gherkin scenarios with metadata header (flow ID, type, app URL, optional auth and cleanup) | Required for flow verification |
| The running app | Target of the scenarios; Nova Act executes against the live URL | Required |
| Auth credentials | Provided when a flow's | Conditional |
When source code is accessible (the user is a developer working on their own app), the agent should detect it and use it during compile, audit, and spec generation. Source can live at the project root ( + at ) OR one level deeper (e.g. — a workspace layout where the verifier opens at the workspace root and one or more app packages live as subdirs). Sniff both. When source is not available (verifying an external site, black-box check), the skill operates in DOM-only mode — selectors are best-effort, audit relies on design.md + DOM only.
package.jsonsrc/output_diroutput_dir/<package-name>/package.jsonThe 5 category files grow as the app develops:
- design.md grows via Scribe (user expressing design intent in chat → design.md edits)
- 5 mds grow as the Compiler discovers more verifiable surfaces in the app and source
Both layers can grow, but only via their own author paths. The 5 mds are NEVER edited to record observations or freeze divergent live-site values — see hard rules below.
Three names — don't conflate them
| Name | What it identifies |
|---|---|
| This skill (the agent's playbook) |
| The MCP server providing browser + verify_* tools |
| The artifact directory at the project root (compiled specs, assertion JSON, reports) |
These are unrelated despite words overlapping. The skill does NOT live inside the artifact dir; the artifact dir is at the project root, not inside the skill.
Capabilities
| Capability | Tool | Source File | What It Checks |
|---|---|---|---|
| Visual Style | | | Colors, typography, spacing, radii, shadows |
| Components | | | Component presence, variants, props |
| Accessibility | | | Aria roles, landmarks, heading hierarchy |
| Project Rules | | | Layout structure, spacing system, conventions |
| Platform Conventions | | | Navigation patterns, page structure |
| User Flows | | | End-to-end user journeys, functional correctness |
Visual rules can be route-scoped: each category file may contain (default) and sections. See . Flow scenarios target the URL declared in their metadata; route scoping is per-flow rather than per-rule.
## Scope: any## Scope: route=<glob>references/spec_authoring.md# app:Available MCP Tools (19 total)
Session Management
- — open a URL, get a
start_browse(url, intent, browser_mode). Usesession_idfor verification.browser_mode="local" - — terminate browser session
session_close(session_id) - — list active sessions
session_list()
Verification — Visual only (all require session_id
and rules
JSON; ALWAYS pass output_dir
= absolute path to project root)
session_idrulesoutput_dirverify_visual_style(session_id, rules, output_dir)verify_components(session_id, rules, output_dir)verify_accessibility(session_id, rules, output_dir)verify_project_rules(session_id, rules, output_dir)verify_platform_conventions(session_id, rules, output_dir)
These are the visual-mode verification tools. For flow verification, and (below) are the primary drivers — doesn't apply to Gherkin steps.
act()act_get()verify_*If is omitted, the server writes assertions to a temp dir and downstream report/annotation steps can't find them.
output_dir/tmp/Browser Interaction (all require session_id
)
session_id- — go to URL
navigate(session_id, url) - — click element
click(session_id, selector) - — scroll up/down
scroll(session_id, direction, selector?) - — hover element
hover(session_id, selector) - — keyboard input
press_key(session_id, key) - — type into input
type_text(session_id, selector, text, clear_first?)
Content & Capture (all require session_id
)
session_id- — run JavaScript in page context
evaluate_js(session_id, script) - — page as
get_page_content(session_id, format?)or"text""html" - — capture viewport to file path
screenshot(session_id, destination?)
Natural Language (all require session_id
)
session_id- — instruct browser actions (scroll, click, navigate, fill forms). For flow verification, this is the primary driver of
act(session_id, prompt)andGivensteps. For visual verification, do NOT useWhenfor CSS checks — useact()instead.verify_* - — structured data extraction or state verification. For flow verification, this is the primary driver of
act_get(session_id, prompt, schema?)andThen(afterAnd) assertions; supplement withThenfor deterministic checks. For visual verification, do NOT useevaluate_jsfor CSS checks — perception/reasoning over the page is the agent's job usingact_get()+screenshot, and CSS verdicts come fromget_page_content.verify_*
Artifact Structure
<project_root>/
visual/design.md ← visual source spec (or .ui-verification/design.md)
.ui-verification/
.integrity.json ← compile-state ledger (visual only — see spec_sync.md)
specs/ ← compiled visual category files (INPUT to verify_*)
visual-style.md (clean markdown — integrity tracked in .integrity.json)
component-rules.md
accessibility.md
project-rules.md
platform-conventions.md
flows/ ← flow .feature files (INPUT to act() / act_get())
<flow-name>.feature
sessions/ ← per-session output (MCP-owned)
<session_id>/
<category>_assertions.json (visual assertion JSON, write-once)
reports/ ← per-run output (skill-owned)
<YYYYMMDD-HHmmssZ>/ ← UTC run-timestamp (a run can span multiple sessions)
report.md ← combined visual + flow summary
screenshots/ ← visual annotated failures
flow-reports/ ← per-flow reports
<flow-name>.report.md
sessions.json ← manifest of session IDs in this runHard rules every run obeys
Default mode is "both" unless user narrows scope
When the user says "verify [url]", "run verification on [url]", or any unqualified verification request, the run MUST include BOTH visual and flow verification. Do NOT default to visual-only. Only narrow to one mode when the user explicitly requests it ("check styles only", "run flows only") or when the disambiguation table clearly matches a single-mode pattern.
If no files exist, generate them (see ). If no exists, generate it (see ). Missing artifacts trigger generation, not scope narrowing.
.featurereferences/flow_generation.mddesign.mdreferences/spec_generation.mdAudit when the integrity ledger triggers
Before calling any tool, check the integrity ledger (see § "The integrity ledger covers the clean case" below for the trigger conditions). When the audit runs, reconcile each in-scope rule against the inputs (design.md, app source if accessible, running app DOM). This is a best-effort LLM check — not a substring match — because the Compiler is itself LLM-driven and rules can legitimately encode information that isn't a literal substring of design.md.
verify_*For each rule (), answer three questions:
{Name, Selector, Property, Constraint, Scope}- Intent traceable — does the rule's claim (what's being asserted: a token value, a property/value pair, an element's presence) correspond to something stated or implied by design.md, OR a component definition / theme token in source code, OR an idiom present in the running app?
- Constraint reconciles — does the constraint value match what design.md assigns to this element/property combination, OR what source code's theme/token files assign, OR what the running app's component renders at rest? Constraints lifted from the live site WITHOUT a design.md or source backing are contamination.
- Selector plausible — does the selector target the element that design.md (or source) describes? Selectors can come from the app (more specific than design.md alone could specify), but the target must match the described element.
Classify each rule as:
- PASS — all three questions reconcile against at least one input
- ORPHAN — the rule's claim has no source. design.md doesn't make this assertion; source doesn't define this assignment; the only "evidence" is what the live site happens to render. This is the contamination case.
- DIVERGENT — the claim IS in design.md (token defined, component referenced) but the rule's constraint contradicts design.md's assignment. E.g. design.md says component X uses token Y, but the rule asserts component X has the value of token Z.
Skip ORPHAN and DIVERGENT rules in the current run; surface them in the report's Audit Findings section (see ). Verifying them would either pass (silently confirming contamination) or fail (without the right reason). Continue verifying the PASS rules. The user resolves contamination on their own time with three options: drop the rule, upstream the claim into design.md and recompile, or recompile from scratch.
references/verification_report.mdWhen to write the integrity ledger. Single rule: write it when the category files on disk equal what the Compiler would emit from the current right now.
design.md- Compile finished cleanly, no skipped rules → write.
- Selector repair or constraint syntax fix completed → write (those repairs ARE what the Compiler would emit now that the original was known to fail).
- Audit skipped any rules (ORPHAN/DIVERGENT) → don't write. Those rules are still in the file but they're NOT what a fresh compile would emit. Leave the ledger missing/stale so the next run re-audits.
- Verify-only run, files unchanged → no-op; don't touch the existing ledger.
The origin of selectors (DOM observation in heuristic mode, source code in source-aware mode) does NOT determine ledger eligibility. As long as rules' claims and constraints trace to design.md (the audit verifies this), the ledger reflects a valid Compiler-approved state. See Compilation step 7 for the full case table.
references/spec_sync.mdThe integrity ledger () covers the clean case. If the ledger says all hashes match — and every category file — the file state is provably what the Compiler last wrote, no audit needed. See § Integrity Ledger.
.integrity.jsondesign.mdreferences/spec_sync.mdAudit runs when:
- Any category file's hash mismatches the ledger (file edited outside Compiler — prior buggy run, hand-edit, partial-write)
- Ledger is missing (no integrity baseline, run conservatively)
- User explicitly requests re-audit (manual correctness check; hashes can be stale even when valid if a Compiler bug wrote bad rules and updated its own hash)
Skip-audit when hashes match is a real efficiency improvement for repeat runs. But periodic manual re-audit ("re-audit visual-style") is recommended after any large compile or after suspicious changes.
Audit cost. This is one LLM reasoning pass per scoped category file (or per rule batch — agent's choice). Not free, but bounded: proportional to the rules being verified, no MCP calls. The same kind of reasoning the Compiler used to write the rules; the audit just checks "would I write this rule if I compiled fresh now?"
Assertion JSON is immutable
Files at are write-once OUTPUT of . NEVER edit them. No exceptions.
<output_dir>/.ui-verification/sessions/<session_id>/*_assertions.jsonverify_*The JSON records what saw against the live DOM. Don't rewrite values, change pass/fail, add scope, "annotate" findings, or add commentary. If a field seems missing (e.g. scope), the report layer joins it in from the source it came from (e.g. the category file) — assertion JSON itself stays exactly as the MCP server wrote it.
verify_*If you find yourself opening assertion JSON to fix something, stop — that's the report's job. The agent reads the JSON; the JSON does not change after writes it.
verify_*The 5 category files are reflections of design.md
The 5 compiled files are derived from . They are NOT a scratch pad, working memory, or place to record observations.
.ui-verification/specs/*.mddesign.mdVerification mode (design.md exists):
Edit a category file ONLY when:
- changed (or chat became a design.md edit) → recompile the affected rules
design.md - Selector repair: an existing rule's selector returned "selector not found" and you found a working replacement (selector update only — name/property/constraint stay)
Do NOT edit category files to:
- Capture an observation about the live site (that's the report's job)
- Add a rule that "documents a divergence" with a constraint that matches the divergent live-site value (this silently encodes site bugs as truth and prevents future detection)
- Make a failing rule pass by relaxing the constraint
- Record findings, notes, or context
For partial / scoped verification, pick existing rules from the right category files — don't author new ones unless they're traceable back to a design.md claim that was missed during the prior compile (which is a Compiler bug to surface, not a routine action).
Generation mode (cold-compile from a live site, no yet):
design.mdThe above rule is RELAXED during generation, because the 5 mds are being seeded for the first time. Generation observes the running app and writes both and the 5 mds in one pass. The constraints in the 5 mds at end-of-generation match the observed DOM values — that is the reverse-engineering contract, not contamination.
design.mdThe "no recording observations" guard kicks in after generation completes and the user has reviewed . From that point forward, the verification-mode rules above apply: edits go through + recompile, never directly to the 5 mds.
design.mddesign.mdSee § Phase 5 for the generation-mode rules. Source code, when accessible during generation, informs names (token names, component names) but NOT values — the DOM is authoritative for values. There is no "source vs DOM divergence" during generation: the DOM is the cascade-resolved outcome of all source CSS, and any apparent disagreement is between one source file the agent read and the same source compiled by the browser.
references/spec_generation.mdEach run is independent
Do NOT read prior assertion JSON or from earlier or directories. The only state carried across runs is the compiled files plus the ledger (re-compile is skipped if all ledger hashes match current files). Prior assertions and reports are historical artifacts; they don't inform the current run.
report.mdsessions/<session_id>/reports/<run-timestamp>/specs/*.md.integrity.jsonIf you find yourself reading a prior session's assertions to "compare," stop — that's cross-session warm-start, which is deferred. Run fresh, write a fresh report.
Flow files at flows/
are the only flow input
flows/The files at are the only input to flow verification. Never compose flows ad-hoc from chat input mid-run; never modify files mid-run. If the user wants to change a scenario, the change goes through the Scribe (see ) before the next run.
.feature<output_dir>/.ui-verification/flows/.featurereferences/flow_sync.mdFlow runs are non-deterministic
Do NOT carry forward prior flow session results across runs. Nova Act re-interprets steps each run, network timing varies, the live UI shifts. Carrying forward "passed" verdicts would mask real flakiness or environmental drift. Every flow runs every time. Flow-side regressions surface via the per-flow status table in the combined report, not a warm-start mechanism.
Every run produces a report
This rule has no exceptions. Whether the user asks to verify a whole site or a single line of , the run isn't done until:
design.md- Rules persist on disk — every rule passed to verify_* at verification time (step 6) must already exist in a category file under the right section. (Compile-time selector validation is a separate use of verify_*; see verification.md step 4.)
## Scope: - Scope is joined at report-time, not stamped onto assertions — the report reads BOTH the assertion JSON (for verdicts) and the category file (for scope) and joins them on rule name. Assertion JSON stays exactly as the MCP server wrote it. See for the join.
references/verification_report.md - A report is written — , with the failure table and any annotated screenshots. See
<output_dir>/.ui-verification/reports/<run-timestamp>/report.mdfor format. Even an all-pass run produces a report.references/verification_report.md - The user-facing summary links the report, not the assertion JSON. The JSON is intermediate output; the report is the deliverable.
A "quick check" of one or two claims is still a verification run. The same four rules apply.
Workflow
For visual verification tasks, load . For flow verification tasks, load . Both reference docs have a complete decision flow for their mode.
references/verification.mdreferences/flow_verification.md| User intent | Reference |
|---|---|
| Verify a live site against a design spec (visual) | |
| Run user flows against a live site | |
| Generate spec from live site (no design.md exists) | |
| Generate flows from a live site (no .feature files exist) | |
| Compile design.md → category files; sync chat edits | |
Sync user intent → | |
| Set up MCP server + browser session | |
| Write/edit design spec files | |
Write | |
| Generate verification report (visual + flow) | |
| Annotate failures visually on the page | |
| Constraint syntax reference | |
| Per-category translation patterns | |
| Cross-session warm-start (deferred — not in scope) | |
All references live at relative to this SKILL.md file. The absolute path depends on where the skill is installed:
./references/<name>.md- Global install:
~/.<agent>/skills/ui-verification/references/<name>.md - Workspace install:
<project_root>/.<agent>/skills/ui-verification/references/<name>.md
To resolve references, use the directory containing this SKILL.md as the base — NOT the workspace root. If your skill loader's progressive disclosure hasn't surfaced them mid-session, read them directly with the Read tool using the appropriate absolute path — never search the filesystem with .
findDisambiguation: visual vs flow vs both
Match the user's request to the right mode:
| Phrase pattern | Mode | Action |
|---|---|---|
| "verify design", "check styles", "match the spec", "is it on-brand" | Visual only | Load |
| "run flows", "test the user journey", "verify login works" | Flow only | Load |
| "verify [url]", "run verification on [url]" with no further qualifier | Both | Visual first, then flow, into one combined report |
User names a specific | Flow only | Load |
User selects text from | Visual only | Load |
When in doubt, ask the user once: "Run visual verification, flow verification, or both?" Don't guess at scope when the request is genuinely ambiguous.
Where this skill lives
This skill is at for workspace-local installs, OR at for global installs — wherever the skill loader picked it up from is its installed location. Do NOT search the filesystem for it. No , no . Activation is the runtime's job; if you've reached this SKILL.md, the runtime already knows where you are.
<output_dir>/.<agent>/skills/ui-verification/~/.<agent>/skills/ui-verification/find ~/.<agent>find /Resolving the references directory
The folder is always co-located with this SKILL.md file, not with the workspace or output directory. Use the path that the runtime used to load this file as the base:
references/| Install type | SKILL.md location | References at |
|---|---|---|
| Global | | |
| Workspace | | |
When reading a reference, construct the absolute path from the skill's install location. Example for a global install:
~/.<agent>/skills/ui-verification/references/verification.md
~/.<agent>/skills/ui-verification/references/spec_sync.mdDo NOT assume references are at when the skill was loaded from the global location — the workspace may not have a copy.
<output_dir>/.<agent>/skills/ui-verification/references/If you're a fresh agent on a new turn and you don't immediately have a tool from available, the MCP server may still be starting — wait for the runtime to surface it on the next user turn rather than searching the filesystem to "find" the skill yourself. The skill is already loaded; the tools are not always synchronously available with skill activation.
nova-act-mcpDon't search for tool implementations
Never for the MCP server source code, the constraint engine source, or any other tool implementation. The behavior of , the constraint syntax, the selector matching algorithm — all of this is documented in and the per-category deep-dives. If a constraint or property behaves unexpectedly during a run, read the reference, not the implementation. The references are the agent-facing documentation of record; reaching for to spelunk the engine is a sign the reference needs an update, which the user can address — but in-session, work from documented behavior.
findverify_*references/constraint_reference.mdfind