---
title: "void CLI reference"
description: "Every void command, flag, exit code and void.config.ts key: audit a running site, lint source, extract a site's design DNA and explain any rule."
canonical: https://void-design.vercel.app/cli
lastModified: 2026-09-16
---

# void CLI reference

void is a Bun CLI. It audits a running website in real Chromium on a throttled mobile and a desktop profile, lints source without a browser, extracts design systems from sites you admire, and explains every rule it can report.

## Commands

| Command | What it does | Exit codes |
| --- | --- | --- |
| `void audit [url]` | Run every page category: perf, smooth, a11y, seo, geo, design, plus lint when a source directory is configured. | 0 · 1 · 2 · 3 · 4 |
| `void perf [url]` | Core Web Vitals and bytes from web-vitals and resource timing, median of --runs, optional Lighthouse. | 0 · 1 · 2 · 3 · 4 |
| `void smooth [url]` | Scripted scroll and interactions: dropped frames, long animation frames, INP, shifts after input, reduced motion, idle rAF, WebGL contexts. | 0 · 1 · 2 · 3 · 4 |
| `void a11y [url]` | axe-core WCAG 2.2 AA, keyboard focus visibility, target size on mobile, 320px reflow. | 0 · 1 · 2 · 3 · 4 |
| `void seo [url]` | Status codes, head placement per user agent, canonical, titles, h1, links, Open Graph, icons, robots.txt, sitemap. | 0 · 1 · 2 · 3 · 4 |
| `void geo [url]` | Raw HTML versus rendered content for AI crawlers, JSON-LD, AI robots policy, llms.txt, Markdown mirrors. | 0 · 1 · 2 · 3 · 4 |
| `void design [url]` | Fonts, type scale, line length, palette and accent sprawl, spacing grid, radius sprawl, generated-UI tells, overflow. | 0 · 1 · 2 · 3 · 4 |
| `void lint [dir]` | Static source checks, no browser. Defaults to the config's src, else the current directory. | 0 · 1 · 2 |
| `void extract <url>` | Measure a site's design DNA and write dna.json, brief.md and direction.css. | 0 · 2 · 4 |
| `void rules [id\|category]` | List all rules, a category or prefix, or explain one rule: why, fix, example, refs. | 0 · 2 unknown id |
| `void report <report.json>` | Re-render a saved JSON report as pretty, md or json. | 0 if it passed, else 1 |
| `void doctor` | Check Bun, Chromium launch, playwright-core, axe-core, web-vitals, optional Lighthouse and the config file. | 0 · 2 · 4 |

## Audit flags

| Flag | Values | Notes |
| --- | --- | --- |
| `--only` | perf,smooth,a11y,seo,geo,design,lint | Categories to run. The shorthand commands set this. |
| `--profile` | mobile \| desktop \| both | Default both. Mobile is 412×823 at 2.625x with 4× CPU and 150 ms RTT; desktop is 1350×940 unthrottled. |
| `--routes` | /,/pricing | Paths resolved against the URL. Default: the URL's own path. |
| `--runs` | 1–20 (3) | Perf runs per profile; the median is reported. |
| `--start` | "bun run start -p 3100" | Start a server, wait for a 2xx on readyPath, audit, stop the process group. Requires --port. |
| `--port` | 1–65535 | Port of the started server; the URL becomes http://localhost:<port>. |
| `--site-url` | https://example.com | Production origin, so canonical and og:url checks pass while auditing localhost. |
| `--src` | ./src | Also lint this directory as part of the audit. |
| `--kind` | marketing \| app | Selects the default budget set (JS 170 KB vs 300 KB). |
| `--lighthouse` | boolean | Also run Lighthouse 13 (optional peer dependency). |
| `--screenshots` | dir | Save fold and full-page screenshots. |
| `--format, -f` | pretty \| md \| json | md is compact and grouped by rule, for agents. |
| `--json` | boolean | JSON only on stdout; progress goes to stderr. |
| `--out, -o` | report.json \| report.md | Also write the report to a file; format from the extension. |
| `--fail-on` | error \| warn \| info \| never | Exit 1 threshold, default error. Budgets also fail unless never. |
| `--max-per-rule` | number | Occurrences listed per rule (md default 5). |
| `--config, -c` | path | Default: void.config.ts, .mts, .js or .mjs in the current directory. |
| `--quiet, -q` | boolean | No progress output. |
| `--no-color` | boolean | Plain output. NO_COLOR is honoured too. |

## Exit codes

| Code | Meaning |
| --- | --- |
| 0 | Pass: no findings at or above --fail-on and every budget holds. |
| 1 | Findings at or above --fail-on, or a budget exceeded. |
| 2 | Usage or config error: a bad flag, an invalid void.config.ts, an unknown rule id. |
| 3 | Target unreachable, or the --start server exited or timed out. The last server log lines are printed. |
| 4 | Chromium failed to launch. Run void doctor, install Chromium or set VOID_CHROMIUM. |

## void.config.ts

| Key | Type | Notes |
| --- | --- | --- |
| `url` | string | Base URL when none is passed. |
| `routes` | string[] | Paths to audit. |
| `start` | { command, port, cwd?, readyPath?, timeoutMs? } | Server to spawn. readyPath defaults to /, timeout to 120 s. |
| `src` | string | Source directory for lint; also added to audit. |
| `profiles` | ("mobile" \| "desktop")[] | Default both. |
| `runs` | 1–20 | Perf runs per profile, default 3. |
| `kind` | "marketing" \| "app" | Default budget set. |
| `budgets` | { mobile?: Budgets, desktop?: Budgets } | lcp, inp, tbt, ttfb (ms), cls, jsKb, cssKb, fontKb, imageKb, htmlKb, requests, droppedFramePct. Merged over the defaults. |
| `rules` | Record<ruleId, "error" \| "warn" \| "info" \| "off"> | Severity overrides per rule id. |
| `failOn` | "error" \| "warn" \| "info" \| "never" | Default error. |
| `lighthouse` | boolean | Default false. |
| `only` | Category[] | Default: all page categories. |

```ts
/** @type {import('@void/cli/config').VoidConfig} */
const config = {
  kind: "marketing",
  src: "src",
  start: { command: "bun run start -p 3100", port: 3100, readyPath: "/" },
  routes: ["/", "/pricing", "/this-page-does-not-exist"],
  profiles: ["mobile", "desktop"],
  runs: 3,
  budgets: { mobile: { lcp: 2000, jsKb: 150 } },
  rules: { "geo/answer-first": "off" },
  failOn: "error",
};

export default config;
```

## Default budgets

| Profile | LCP | CLS | INP | TBT | TTFB | JS | CSS | Fonts | HTML |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| marketing · mobile | 2.5 s | 0.1 | 200 ms | 200 ms | 800 ms | 170 KB | 25 KB | 120 KB | 30 KB |
| marketing · desktop | 1.5 s | 0.1 | 200 ms | 200 ms | 800 ms | 170 KB | 25 KB | 120 KB | 30 KB |
| app · mobile | 2.5 s | 0.1 | 200 ms | 300 ms | 800 ms | 300 KB | 40 KB | 120 KB | 60 KB |
| app · desktop | 1.5 s | 0.1 | 200 ms | 200 ms | 800 ms | 300 KB | 40 KB | 120 KB | 60 KB |

## JSON report (abridged)

```json
{
  "schemaVersion": 1,
  "tool": { "name": "void", "version": "0.1.0" },
  "scores": { "perf": 97, "smooth": 100, "a11y": 100, "seo": 100, "geo": 96, "design": 94 },
  "overall": 98,
  "metrics": [{ "name": "lcp", "value": 1180, "unit": "ms", "profile": "mobile", "budget": 2500 }],
  "findings": [{
    "id": "perf/lcp-image-lazy",
    "category": "perf",
    "severity": "error",
    "message": "LCP image /hero.avif has loading=lazy",
    "source": "web-vitals",
    "target": { "url": "http://localhost:3100/", "profile": "mobile", "selector": "main img" },
    "fix": { "hint": "Remove loading=\"lazy\" from the LCP image." },
    "docs": "https://void.parthkapoor.me/rules/perf/lcp-image-lazy"
  }],
  "summary": { "errors": 1, "warnings": 0, "infos": 2, "pass": false }
}
```
