Shadscan – Deterministic UI Audits for Shadcn Apps Shadscan, a new deterministic UI audit tool for React shadcn apps, scores UI fundamentals from 0 to 100 and provides evidence for each finding, covering command menus, theme shortcuts, route states, accessible controls, form feedback, metadata, and mobile behavior. The tool, available via pnpm dlx @shadscan/cli, is read-only and does not start the app, edit files, call an AI model, upload source, or require secrets. It offers JSON, prompt, and CI outputs, and includes a composite GitHub Action that enforces score floors and creates issue reports. Website https://www.shadscan.com · Scan a repository https://www.shadscan.com/scan · Docs https://www.shadscan.com/docs · 59 rules /TheOrcDev/shadscan/blob/main/docs/rules.md · Sponsor https://www.shadscan.com/sponsors Shadscan inspects a React shadcn app, scores its UI fundamentals from 0 to 100, and shows the evidence behind every finding. It catches the product details that are easy to postpone: command menus, theme shortcuts, route states, accessible controls, form feedback, metadata, mobile behavior, and more. The default scan is deterministic and read-only. It does not start the app, edit files, call an AI model, upload source, or require application secrets. Run Shadscan from the root of a project: pnpm dlx @shadscan/cli The project path defaults to the current directory. Pass a path to scan another app: pnpm dlx @shadscan/cli ../my-shadcn-app Using npm or Bun: npx --yes @shadscan/cli bunx @shadscan/cli Commands resolve to the latest stable release. Prereleases are published under the next tag @shadscan/cli@next for early testing. Interactive human scans show progress immediately and keep each completed phase above the final report: ✓ Resolving project ✓ Discovering app structure ✓ Evaluating UI rules ✓ Preparing report JSON, prompt, CI, non-TTY stderr, and --no-interactive output stay quiet. Redirecting stdout keeps the report clean while progress remains on an eligible stderr terminal. Every interactive scan ends with a short menu — pick with the arrow keys and Enter: copy the agent handoff to your clipboard, print it, launch an installed coding agent, or add a pre-commit score gate. The handoff is highlighted first, so a single Enter grabs it; press Esc to keep just the score. Your shadscan score: - 92/100 Grade A shadscan has entered the chat. Categories: Foundation: 20/20 100% Interaction: 12.2/20 61% States: 20/20 100% Accessibility: 20/20 100% Forms and Data Entry: 10/10 100% Production Polish: 10/10 100% Missing: command menu has a Cmd/Ctrl+K shortcut Evidence: No complete mounted Cmd/Ctrl+K command-menu shortcut was found. Fix: Register a shortcut that prevents the browser default and toggles the menu. Every report separates: Fixes : high-confidence defects with repository-relative evidence. Decisions : product choices that should be implemented or explicitly waived. Advisories : lower-confidence checks that need rendered or manual verification. Not applicable : rules excluded because the relevant UI surface is absent. Machine-readable, versioned report pnpm dlx @shadscan/cli --json Paste-ready remediation plan for a coding agent pnpm dlx @shadscan/cli --prompt Explicitly launch an installed agent with the generated plan pnpm dlx @shadscan/cli --apply --agent codex Fail CI when the complete assessed score is below the floor pnpm dlx @shadscan/cli@0.8.0 --fail-under 80 --no-interactive --no-roast Audit one category while investigating a focused area pnpm dlx @shadscan/cli --category accessibility See which workspace packages shadscan found, without scanning pnpm dlx @shadscan/cli --list-projects Scan one package of a monorepo instead of pooling every application pnpm dlx @shadscan/cli --project apps/web Use --format human , --format json , or --format prompt when output selection needs to be explicit. Pin an exact package version in CI; unqualified commands resolve to the latest stable release. Run pnpm dlx @shadscan/cli --help for every option. The repository doubles as a composite GitHub Action that runs the CLI, writes the score to the job summary, enforces an optional score floor, and can create or update a tracked issue containing the findings and a paste-ready AI-agent remediation handoff. name: shadscan on: push: branches: main permissions: contents: read issues: write only needed with create-issue jobs: audit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: TheOrcDev/shadscan@main with: path: . version: 0.8.0 pin an exact CLI version in CI fail-under: "80" create-issue: "true" Inputs: path , version , category , fail-under , create-issue , issue-label , and github-token . Outputs: score , grade , and report-path the machine-readable JSON report . With create-issue , the action keeps a single open issue per label up to date instead of filing a new issue on every run, and the issue body embeds the same --prompt handoff you would generate locally — ready to paste into a coding agent. --prompt turns the same deterministic report into a neutral, paste-ready plan for another coding agent. The handoff includes: - prioritized work items grouped as fix , decide , or verify ; - rule IDs, evidence, suggested fixes, and acceptance criteria; - detected framework, package manager, and source-coverage context; - repository-owned verification commands that the agent must inspect first; - the exact pinned Shadscan command to rescan after the work. --apply is an explicit local action. It validates an installed Claude Code, Codex CLI, or Grok Build executable before launching it. Shadscan itself still does not make an AI request; the selected external agent follows its own provider and approval model. The bundled ruleset contains 59 deterministic checks across six weighted categories. | Category | Examples | |---|---| | Foundation | shadcn config, mounted theme provider, metadata, favicon, not-found and error boundaries | | Interaction | dark-mode and command-menu shortcuts, safe global hotkeys, mobile navigation, focus visibility | | States | loading and Suspense fallbacks, empty states, retryable errors, pending actions, mounted toasts | | Accessibility | names and labels, semantic controls, alt text, landmarks, live regions, keyboard and focus behavior | | Forms and Data Entry | validation, rendered field errors, error associations, legends, button types, autocomplete | | Production Polish | complete metadata, social previews, Button icon spacing, responsive shells, SEO files, mobile overflow | See the generated rule catalog /TheOrcDev/shadscan/blob/main/docs/rules.md for every rule ID, confidence level, score behavior, and supported adapter. Raw rule points are normalized within each weighted category to produce the 100-point score. High- and medium-confidence failures can reduce the score. Low-confidence checks stay visible as score-neutral advisories instead of pretending static analysis can prove rendered behavior. Rules only run where they apply. Shadscan supports Next.js App Router, Pages Router, hybrid Next.js projects, React Router framework mode, TanStack Start, Laravel with Inertia and React, Astro with React islands, Vite React, and generic React applications. Run shadscan at a workspace root and it audits every React application it finds, pooling their findings into one score. The report lists each package with its own score so the pooled number is explicable, and --list-projects prints that list without scanning. Packages are classified as applications or libraries . A library — a React package with no application entry point — is scanned and reported, but its findings do not count toward the score: it has no document shell, so it would fail rules about page titles and favicons that it should never satisfy, and pooling those would punish you for owning a design system. Packages that shadscan cannot audit at all, such as one that does not declare React, are listed as skipped with the reason. Workspaces are found by walking the tree for package.json files, so pnpm, npm, yarn, bun, Turborepo, Nx and Lerna all work without configuration. A workspace containing a single application is scanned exactly as before, so the common "app at the root plus shared packages" layout keeps its existing score. Use --project