Commands & flags
Every invocation is real-a11y <command> [url...] [flags]. Nine commands ship — audit, inspect, tree, outline, tabs, list, snapshot, diff, and login. Run real-a11y <command> --help for a command's own flags.
Findings and reports go to stdout; progress, warnings, and errors go to stderr — so -o / a pipe never mixes the two.
Exit codes are frozen:
| Code | Meaning |
|---|---|
0 | Clean — no findings at or above --fail-on. |
1 | Findings at or above the threshold (the CI gate). |
2 | Usage or navigation error. |
View commands (tree, outline, tabs, list) aren't gates — they exit 0 unless something actually failed.
Environment variables:
A11Y_PAGES— a JSON[{ "name": …, "url": … }]array, the page set forauditandsnapshotwhen no URL is passed.A11Y_SNAPSHOT_OUT— default output path forsnapshotwhen-ois omitted.
Human (pretty) output is English-only and may be reworded between releases. The machine formats — json, sarif, junit, jsonl, and the v1: fingerprints — are a frozen contract: within 0.x, changes are additive-only. Never rely on the wording of a pretty line; key on the JSON.
Commands
Each command below lists the flag groups it accepts. Shared flags are documented once, in Flags — the per-command list only links to them, plus any command-specific flags.
audit <url...>
The flagship gate. Audits one or more pages against the semantic-tree rules and prints violations grouped by rule — each with a CSS locator and severity. Exits 1 on errors with no extra flags. A failed page becomes an error entry (exit 2) while the others still report. Under GitHub Actions it also emits grouped ::error annotations and a job summary.
With no URL, it audits every entry in A11Y_PAGES or the config's urls.
real-a11y audit http://localhost:3000
real-a11y audit https://stage.example.com --device "iPhone 13" --fail-on warning
real-a11y audit ./dist/index.html --format json -o report.jsonFlags: Browser & page · Output · Config · --rules · --fail-on (default error) · --no-annotate.
inspect <url>
Findings plus the semantic tree, heading outline, and tab order — all from one extraction, so the views can never disagree. Views print first; the gate outcome is the last thing on screen. Single URL.
real-a11y inspect http://localhost:3000Flags: Browser & page · Output · Config · --rules · --fail-on (default error) · --no-annotate · --include-generic.
tree <url>
Print the semantic tree — what a screen reader perceives, role by role. Single URL; always exits 0.
real-a11y tree https://example.comFlags: Browser & page · Output (pretty | json) · Config · --include-generic.
outline <url>
Print the heading outline (h1–h6) in document order. Single URL; always exits 0.
real-a11y outline https://example.comFlags: Browser & page · Output (pretty | json) · Config.
tabs <url>
Print every focusable element in keyboard Tab order. Single URL; always exits 0.
real-a11y tabs https://example.comFlags: Browser & page · Output (pretty | json) · Config.
list <category> <url>
List every element in one category — as role, accessible name, and locator. The category is the first positional; the URL follows. Single URL; always exits 0.
Categories: heading, link, button, form, landmark, image.
real-a11y list image https://example.comFlags: Browser & page · Output (pretty | json) · Config.
snapshot [url...]
Audit a page set and write one JSON artifact — fingerprinted findings plus the tree/outline/tabs views per page. That artifact is the input to diff.
Pages, in precedence order: positional URLs, else A11Y_PAGES, else the config's urls (--config or auto-discovered). Output goes to -o, else A11Y_SNAPSHOT_OUT, else stdout. Unlike the other gates, --fail-on defaults to never here — snapshot just writes the artifact unless you ask it to gate.
real-a11y snapshot https://example.com -o base.json
real-a11y snapshot --config a11y.config.json --md -o report.md
real-a11y snapshot --config a11y.config.json --update-baseline
real-a11y snapshot --config a11y.config.json --baseline .a11y-baseline.json --fail-on errorFlags: Browser & page · Config · --rules · --fail-on (default never) · --include-generic · -f, --format (json | md | sarif | junit | jsonl) · --md · --baseline · --update-baseline · -o, --output · -q, --quiet · --verbose · -h, --help.
diff <base.json> <pr.json>
Classify the findings in two snapshot artifacts as new / changed / fixed — robust to DOM churn (re-indentation, renumbered locators) that defeats a line diff. Pure: no browser. Takes exactly two positional files. Exits 1 only on NEW findings at or above --fail-on; fixes and drift never fail the build.
Default output is neutral — findings plus a real unified diff of the structure. Add --explain for a plain-language summary.
real-a11y diff base.json pr.json
real-a11y diff base.json pr.json --explain
real-a11y diff base.json pr.json --format md --explain --max-pages 5 --max-lines 20 -o comment.mdFlags: Config · --fail-on (default error) · --explain · --max-lines · --max-pages · --baseline · --ignore-view-line · -f, --format (pretty | json | md) · -o, --output · -q, --quiet · --verbose · -h, --help.
login <url> --save <file>
Open a visible browser, log in by hand — MFA, SSO, and passkeys all work, because a human is driving — then press Enter to save the session to a file you can later pass to --storage-state. Interactive by construction: it needs a TTY and fails fast in CI. Forces headful; no device/viewport emulation, format, or output flags. The saved file holds live session tokens — keep it out of version control (the command warns if it isn't).
real-a11y login https://app.example.com --save auth.json
real-a11y audit https://app.example.com/dashboard --storage-state auth.jsonFlags: --save (required) · --wait-until · --settle · --timeout · Config · --verbose · -h, --help.
Flags
Grouped and documented once. The Commands line above each entry names which commands accept it. An explicit flag always wins over an a11y.config.json default; see Configure once.
Browser & page
Control the browser that renders the page before extraction. Accepted by every browser-driving command — audit, inspect, tree, outline, tabs, list, snapshot. login takes only the settling flags (--wait-until, --settle, --timeout) and forces headful.
--root <selector>
- Type: CSS selector · Default:
body· Commands: audit, inspect, tree, outline, tabs, list
Scope extraction to a region or component instead of the whole page. snapshot accepts the flag but scopes each page via its config rootSelector instead.
real-a11y tree http://localhost:3000 --root "#app main"--device <name>
- Type: Playwright device name · Default: none · Commands: audit, inspect, tree, outline, tabs, list, snapshot
Emulate a device — viewport, user agent, touch — to audit the mobile layout. Can't be combined with --cdp.
real-a11y audit http://localhost:3000 --device "iPhone 13"--viewport <WxH>
- Type:
WIDTHxHEIGHT· Default: none · Commands: audit, inspect, tree, outline, tabs, list, snapshot
Explicit viewport size. Must match ^\d+x\d+$, e.g. 1280x800. Can't be combined with --cdp.
--wait-until <state>
- Type:
load | domcontentloaded | networkidle | commit· Default:load· Commands: audit, inspect, tree, outline, tabs, list, snapshot, login
The navigation lifecycle event to wait for before extracting. Use networkidle for JS-heavy pages that keep fetching after load.
--settle <ms>
- Type: integer ms · Default:
0· Max:30000(clamped) · Commands: audit, inspect, tree, outline, tabs, list, snapshot, login
Extra wait after the --wait-until state, for animations or late hydration. Values above the max are clamped; a non-integer is an error.
real-a11y audit http://localhost:3000 --wait-until networkidle --settle 500--timeout <ms>
- Type: integer ms · Default:
30000· Min:1· Max:120000(clamped) · Commands: audit, inspect, tree, outline, tabs, list, snapshot, login
Navigation timeout. Unlike Playwright, 0 is not accepted (no "wait forever"); values above the max are clamped.
--headful
- Type: boolean · Default:
false(headless) · Commands: audit, inspect, tree, outline, tabs, list, snapshot
Show the browser window. Can't be combined with --cdp. login is always headful.
--cdp <endpoint>
- Type: CDP endpoint URL · Default: none · Commands: audit, inspect, tree, outline, tabs, list, snapshot
Attach to a running Chrome instead of launching one — the interactive way to audit a login. No emulation over CDP: can't be combined with --headful, --device, --viewport, or --storage-state.
--allow-file
- Type: boolean · Default:
false· Commands: audit, inspect, tree, outline, tabs, list, snapshot
Approve file: targets, which are blocked by default. Real, but omitted from --help. A path you type (./dist/index.html) is normalized to a file: URL, so this is what unlocks auditing a built file.
--storage-state <file>
- Type: path to a saved session · Default: none · Commands: audit, inspect, tree, outline, tabs, list, snapshot
Audit as a logged-in user, using a session file written by login. Can't be combined with --cdp. See Authenticated pages.
real-a11y login https://app.example.com --save auth.json
real-a11y audit https://app.example.com/dashboard --storage-state auth.json--audit-origin <origin>
- Type: origin (repeatable) · Default: the target's own origin · Commands: audit, inspect, tree, outline, tabs, list, snapshot
An extra origin allowed under --storage-state. Origin pinning stops a redirect from routing extraction to an unintended, cookie-matching origin. Repeat for each additional origin; must parse as a URL.
real-a11y audit https://app.example.com --storage-state auth.json \
--audit-origin https://accounts.example.comOutput
Format and destination. -o / a pipe never suppresses progress — that always stays on stderr.
-f, --format <fmt>
- Type: enum (per command) · Default: first value below · Commands: audit, inspect, tree, outline, tabs, list, snapshot, diff
Never auto-switched — piping only drops color. Allowed values depend on the command:
| Command | Values | Default |
|---|---|---|
| audit, inspect, tree, outline, tabs, list | pretty | json | pretty |
| diff | pretty | json | md | pretty |
| snapshot | json | md | sarif | junit | jsonl | json |
sarif requires --config (results anchor to repo file paths). See SARIF, JUnit, JSONL.
-o, --output <file>
- Type: path · Default: stdout · Commands: audit, inspect, tree, outline, tabs, list, snapshot, diff
Write the report to a file (progress stays on stderr). A typo'd path fails before the browser launches, not after. For snapshot, A11Y_SNAPSHOT_OUT is the fallback when this is omitted.
-q, --quiet
- Type: boolean · Default:
false· Commands: audit, inspect, tree, outline, tabs, list, snapshot, diff
Suppress progress lines on stderr.
--verbose
- Type: boolean · Default:
false· Commands: all
Extra diagnostics on stderr (per-page timings, and more).
-h, --help
- Type: boolean · Commands: all
Print that command's usage and flags, then exit 0. real-a11y --help with no command prints the command list.
Config
An a11y.config.json seeds any flag you don't pass — the Jest/ESLint model. Accepted by every command.
--config <file>
- Type: path · Default: auto-discovered
a11y.config.jsonin cwd · Commands: all
Point at a config elsewhere. Its defaults block seeds unset flags; its urls list is the page set for audit and snapshot (diff reads two snapshot files, so it only takes defaults from the config). The config is strict and fail-closed — a typo'd key is a hard error, so a mistake can't silently un-gate CI. See Configure once.
--no-config
- Type: boolean · Default:
false· Commands: all
Ignore an auto-discovered config for this run.
Gate
Which rules run, and what fails the build.
--rules <ids>
- Type: comma-separated ids · Default: all five · Commands: audit, inspect, snapshot
Run only a subset of the rules. Valid ids: no-unlabeled-interactive, image-alt, heading-order, dialog-labeled, landmark-structure. An unknown id is a hard error.
real-a11y audit http://localhost:3000 --rules no-unlabeled-interactive,image-alt--fail-on <level>
- Type:
error | warning | never· Default:error(audit, inspect, diff) ·never(snapshot) · Commands: audit, inspect, snapshot, diff
The gate threshold. error exits 1 on any error; warning also fails on warnings; never never fails the build (it still reports). For diff, only NEW findings at or above the threshold gate — drift and fixes never fail.
--no-annotate
- Type: boolean · Default: annotate on · Commands: audit, inspect
Skip the GitHub Actions ::error annotations and job-summary report that audit and inspect emit when running under Actions.
Command-specific
Flags that belong to a single command (or a small set).
--include-generic
Include generic container nodes (untyped div/span wrappers) in the semantic tree, which are collapsed away by default. Only the commands that print a full tree honor it. snapshot, outline, tabs, and list accept the flag but ignore it — snapshot's artifact tree always collapses generics.
--md
- Type: boolean · Default:
false· Commands: snapshot
Shorthand for --format md — a human-readable report instead of the JSON artifact. Conflicts with an explicit non-md --format.
--baseline <file>
- Type: path · Default: none · Commands: snapshot, diff
Suppress findings this baseline accepts: they stay in the report (marked "suppressed": true) but drop out of the --fail-on count (and SARIF). Identity-matched, not string-matched. See Adopt the gate on existing debt.
--update-baseline
- Type: boolean · Default:
false· Commands: snapshot
Rewrite the baseline from the current findings, then stop — it writes the baseline file (.a11y-baseline.json, or --baseline's path) and never gates. Prints +N new, -N stale on stderr and carries forward note fields on entries that still match.
real-a11y snapshot --config a11y.config.json --update-baseline--explain
- Type: boolean · Default:
false· Commands: diff
Add a plain-language summary of structural changes ("Heading level changed: h2 → h3", "Keyboard tab stop removed …") to the neutral diff. Opt-in because the statements are an interpretive layer; the default never makes a claim the diff can't back up. Advisory only — it never affects the exit code.
--ignore-view-line <regex>
- Type: JS regex (repeatable) · Default: none · Commands: diff
Drop view lines matching the pattern before diffing — for generated content that differs on every build (a "last updated" timestamp, a build hash) and would otherwise read as drift on every page. Each value must be a valid RegExp.
real-a11y diff base.json pr.json --ignore-view-line '^time "'--max-lines <n>
- Type: positive integer · Default: full · Commands: diff
Cap the structural diff to n lines per page, then … N more. For CI comments — run once uncapped to a log and once capped to the comment.
--max-pages <n>
- Type: positive integer · Default: all · Commands: diff
Detail at most n changed pages, then list the rest by name. For CI comments.
real-a11y diff base.json pr.json --explain --max-pages 5 --max-lines 20 -o comment.md--save <file>
- Type: path · Default: none (required) · Commands: login
Where login writes the captured session. Written 0o600 (POSIX); the command warns if the path sits un-gitignored inside a repo. Session storage isn't captured — apps that keep auth there need --cdp instead.
real-a11y login https://app.example.com --save auth.json