Skip to content

Reference · audit

`void` command reference

audit/references/commands.md145 linesupdated 16 Sept 2026

Written from packages/cli/src/cli/*.ts (void 0.1.0, 2026-09-16). If void --help disagrees with this file, trust void --help and report the drift.

Install and run: the plugin ships the CLI in packages/cli (Bun ≥ 1.2). Run bunx void … or bun packages/cli/src/index.ts … from a checkout, or void … when it's linked or installed globally. It needs a Chromium: resolved from VOID_CHROMIUMCHROME_PATH → system paths (/usr/bin/chromium, Chrome.app…) → the Playwright cache. void doctor shows what it found.

Commands

Command Purpose Exit
void audit [url] Run every page category: perf, smooth, a11y, seo, geo, design (+ lint when src is set) 0/1/2/3/4
void perf [url] Only performance (web-vitals + resources [+ Lighthouse]) same
void smooth [url] Only smoothness (scripted scroll, interactions, animations, reduced motion, rAF, WebGL) same
void a11y [url] Only accessibility (axe WCAG 2.2 AA, focus visibility, target size, reflow) same
void seo [url] Only SEO (status, head, canonical, links, OG, icons, robots, sitemap) same
void geo [url] Only AI search (raw vs rendered content, JSON-LD, AI robots, llms.txt, Markdown mirrors) same
void design [url] Only design heuristics (type, color, spacing, overflow, slop tells) same
void lint [dir] Static source checks, no browser. dir defaults to config src, else . 0/1/2
void rules List all rules 0
void rules Show one rule: title, why, fix, example, refs 0 / 2 if unknown (suggests near matches)
void rules List a category (void rules perf) or prefix (void rules seo/canonical) 0
void report Re-render a saved JSON report (--format md|pretty|json) 0 if report passed, else 1
void extract Extract a site's design DNA (tokens, type, color) to dna.json, brief.md, direction.css. (Module in progress: may print "not available in this build") 0/2/4
void doctor Check Bun, Chromium launch, playwright-core, axe-core, web-vitals, optional Lighthouse, config 0/2/4

url may be omitted when --start or config url/start provides it. Bare hosts get a scheme: localhost:3000http://, example.comhttps://.

Audit flags (audit and the category shorthands)

Flag Values / default Notes
--only perf,smooth,a11y,seo,geo,design,lint Comma list. The shorthands set this for you
--profile mobile | desktop | both (default both) mobile = 412×823 @2.625x, 4× CPU, 150 ms RTT, 1.6/0.75 Mbps; desktop = 1350×940, unthrottled
--routes /,/pricing Paths resolved against the URL. Default: the URL's own path
--runs 1–20 (default 3) Perf runs per profile; the median is reported. Use 5 near budgets, 1 for quick iteration
--lighthouse boolean Also run Lighthouse 13 (optional peer: bun add -d lighthouse)
--start "bun run start -p 3100" Spawns the command (with PORT and NODE_ENV=production set), waits for 2xx on readyPath, audits, then kills the process group. Requires --port
--port 1–65535 Port the started server listens on. The URL becomes http://localhost:
--src ./src Also lint this directory as part of the audit
--kind marketing | app Selects default budgets (JS 170 vs 300 KB, etc.)
--screenshots dir Save fold + full-page screenshots (design audit)
--format, -f pretty (TTY default) | md | json md = compact for agents, grouped by rule
--json boolean Same as --format json; only JSON on stdout, progress on stderr
--out, -o report.json | report.md Also write the report to a file (format from extension)
--max-per-rule number (md default 5) Occurrences listed per rule
--fail-on error (default) | warn | info | never Exit 1 threshold. Budgets also fail unless never
--config, -c path Default: void.config.ts / .mts / .js / .mjs in cwd
--quiet, -q boolean No progress output
--no-color boolean Plain output
--help, -h / --version, -v

Lint uses --config, --fail-on, --format/--json, --out, --no-color. Extract uses --out

, --screenshots , --pages /,/pricing, --max-pages N, --format md|css|json, --quiet.

Environment: VOID_CHROMIUM / CHROME_PATH (browser binary), VOID_DEBUG=1 (stack traces), NO_COLOR, CI (plain progress lines).

Exit codes

Code Meaning What to do
0 Pass: no findings at or above --fail-on, all budgets pass Done (check stopping criteria)
1 Findings ≥ --fail-on, or a budget exceeded Fix (see the audit SKILL loop)
2 Usage or config error (bad flag, invalid void.config.ts, unknown rule id) Read the message and hint
3 Target unreachable, or --start server exited / timed out Check the build, port and readyPath; the last 10 server log lines are printed
4 Browser launch failure void doctor; install Chromium or set VOID_CHROMIUM

void.config.ts schema (VoidConfig)

Key Type Default Meaning
url string (absolute) Base URL when none is passed
routes string[] URL path Paths to audit
start { command, port, cwd?, readyPath?, timeoutMs? } Server to spawn (readyPath "/", timeout 120 s)
src string Source dir for lint (used by void lint and added to void audit)
profiles ("mobile" | "desktop")[] both
runs 1–20 3 Perf runs per profile
kind "marketing" | "app" marketing Default budget set
budgets { mobile?: Budgets, desktop?: Budgets } see below Merged over the defaults per key
rules Record Severity overrides
failOn "error" | "warn" | "info" | "never" error
lighthouse boolean false
screenshots string Directory
only Category[] all page categories

Budgets keys: lcp, inp, tbt, ttfb (ms) · cls · jsKb, cssKb, fontKb, imageKb, htmlKb (KB transferred at load) · requests · droppedFramePct (%).

Default budgets:

lcp cls inp tbt ttfb jsKb cssKb fontKb imageKb htmlKb droppedFramePct
marketing mobile 2500 0.1 200 200 800 170 25 120 1000 30 5
marketing desktop 1500 0.1 200 200 800 170 25 120 1500 30 5
app mobile 2500 0.1 200 300 800 300 40 120 60 5
app desktop 1500 0.1 200 200 800 300 40 120 60 5

The config file may export default a plain object (as the template does, with a JSDoc @type {import('@void/cli/config').VoidConfig}) or use defineConfig from @void/cli/config when the package is installed.

Report JSON (--json), abridged

ts
{
  schemaVersion: 1,
  tool: { name: "void", version: "0.1.0" },
  targets: [{ url, profile, status }],
  scores: { perf, smooth, a11y, seo, geo, design, lint },   // 0–100; gates cap a category at 49
  overall: number,                                          // weighted: perf .25 a11y .2 smooth .15 seo .15 design .15 geo .1
  metrics: [{ name: "lcp", value: 1830, unit: "ms", profile: "mobile", url, runs: [..], budget: 2500 }],
  budgets: [{ name, limit, actual, pass, profile, url }],
  findings: [{
    id: "perf/lcp-image-lazy", category: "perf", severity: "error",
    message: "LCP image /hero.avif has loading=lazy …",
    source: "web-vitals" | "axe" | "lighthouse" | "loaf" | "trace" | "cdp" | "dom" | "ast" | "css" | "http" | "heuristic",
    target: { url, profile, selector, html, file, line, column, snippet },
    evidence: { metric: { name, value, unit, threshold }, data: {…} },
    fix: { hint, example }, docs: "https://void-design.vercel.app/rules/perf/lcp-image-lazy", fingerprint
  }],
  errors: [{ category, message, url, profile }],            // audits that could not complete
  failOn: "error",
  summary: { errors, warnings, infos, pass }
}

Useful jq:

bash
void audit --json --start "bun run start -p 3100" --port 3100 > report.json
jq -r '.findings | group_by(.id)[] | "\(.[0].severity)\t\(length)\t\(.[0].id)"' report.json | sort -r   # counts per rule
jq '.budgets[] | select(.pass == false)' report.json
jq '.scores' report.json

Rule id prefixes

Prefix Examples
perf/ lcp-slow, cls-high, tbt-high, ttfb-slow, js-budget, lcp-image-lazy, lcp-image-no-priority, lcp-background-image, images-missing-dimensions, third-party-heavy, bfcache-blocked, cache-headers, no-text-compression
smooth/ scroll-jank, long-frames-during-scroll, inp-slow, layout-shift-after-input, animate-layout-property, reduced-motion-ignored, raf-loop-idle, multiple-webgl-contexts
a11y/ axe ids (color-contrast, button-name, label, link-name, image-alt, heading-order, landmark-one-main, meta-viewport, bypass…), plus target-size, focus-not-visible, reflow-overflow, axe-other
seo/ http-status, soft-404, metadata-in-body, canonical-missing, canonical-not-self, title-length, meta-description-missing, h1-count, og-image-invalid, favicon, robots-blocks-all, sitemap-lastmod, broken-links
geo/ js-dependency, hidden-streamed-content, jsonld-parse-error, jsonld-required, jsonld-not-visible, faq-deprecated, search-bots-blocked, llms-txt-missing, markdown-mirror-indexable, answer-first, no-citations
design/ too-many-font-families, no-type-scale, line-length-long, palette-sprawl, multiple-accents, gradient-text, purple-gradient, emoji-icons, spacing-off-grid, horizontal-overflow
lint/ tw-unknown-class, tw-v3-arbitrary-var, tw-v3-renamed, page-level-use-client, image-priority-deprecated, heavy-import, browser-global-in-render, timer-in-render, outline-none-no-replacement, canonical-in-root-layout, og-merge-drops-parent, not-found-in-suspense, dynamic-metadata-streaming, sitemap-lastmod-now, route-js-budget

void rules --json prints the full registry (the source of truth; the website renders /rules/ from it).