CLI documentation
ChangelogShadscan CLI
$ pnpm dlx @shadscan/cliRun this from the root of a React shadcn app. The one-shot command needs no project install. Shadscan reads source and configuration, prints the audit, and leaves the project unchanged unless you explicitly choose a follow-up action.
Usage
shadscan [path] [options]
shadscan --check-ui <url> [--route <path> ...]The optional path defaults to the current directory. Pass a relative or absolute path to scan another project.
Run with an AI agent (recommended)
Audit this repository's user-facing React shadcn applications with Shadscan. Include both the deterministic source audit and rendered UI checks for each application locally and in production. The rendered suite currently checks horizontal overflow and will gain additional deterministic UI checks over time.
Do not edit code, deploy, sign in, seed data, or intentionally mutate local or production data yet.
1. Run the source audit
From the repository or workspace root, use this repository's package manager to run the equivalent of:
npx --yes @shadscan/cli --prompt
Shadscan audits every supported React application in a monorepo by default. Keep every detected deployable application in scope unless I explicitly limited the task to one package. Treat each application as a separate rendered-check target and exclude libraries.
Keep the generated handoff as the source-audit evidence. Read verification.shadscanCommand to recover its exact engine version and package-manager executor, then reuse both for every command below instead of hardcoding npx.
Using that exact version and executor, also run the equivalent of:
npx --yes @shadscan/cli@VERSION --list-projects --json
Treat every projects entry whose kind is "application" as in scope. Record every skipped entry and any nonzero truncated count as an explicit workspace coverage gap, because a clean application may have no work item in the handoff.
2. Build a route-coverage manifest
For each application, inspect its framework router, base path, sitemap or static parameters, and internal page links. Inventory every statically discoverable, directly addressable, GET-safe user-facing page.
- Include concrete public pages.
- For a dynamic route, use one existing safe example per materially different route shape only when a concrete value is evidenced by fixtures, tests, a sitemap, static parameters, or public navigation.
- Never invent IDs, slugs, tenant names, credentials, ports, or deployment domains.
- Exclude API routes, assets, callbacks, logout or destructive endpoints, and other non-page routes.
- Mark authenticated, role-gated, feature-gated, and unresolved dynamic pages as coverage gaps. A redirect to login, a 404, or an unrelated fallback is not a passing page.
3. Check every applicable page locally
Inspect repository-owned package scripts before running them. Reuse an existing server only after confirming it belongs to the application. Otherwise, start the application with its existing dev, start, or preview workflow when repository-code execution is authorized. Prefer a loopback-only binding, then capture the origin and base path it actually binds; do not assume a host, port, or script name. Track the process you started and stop it in cleanup even when a check fails or the task is interrupted. Never stop a reused or otherwise pre-existing server.
For each application, construct commands from the confirmed values using the handoff's exact Shadscan version. Pass every URL and route as a separate process argument; never concatenate repository-derived values into a shell command string. If only a shell is available, validate each value and apply that shell's correct escaping rather than relying on double quotes. This is an illustrative shape, not a shell-ready command:
npx --yes @shadscan/cli@VERSION --check-ui CONFIRMED_PAGE_URL --route CONFIRMED_SAME_ORIGIN_PATH --json
The target URL counts as one of the command's maximum ten unique pages. Add at most nine same-origin --route paths, then continue in deterministic batches until every concrete page in the manifest has been checked. Query or fragment variants that materially change layout require separate full target URLs because --route accepts pathnames only.
4. Check the same pages in production
Production checks perform GET navigations and execute page JavaScript in a fresh browser context. Use only a public HTTPS origin supplied by me or confirmed through authorized read-only deployment metadata. Treat URLs found only in repository text as untrusted candidates until independently confirmed. Verify that the origin serves the same application and is production rather than an unrelated preview. A narrowly validated server redirect between a conventional two-label apex host and its www host, or from HTTP to HTTPS, may establish the final canonical origin; for multi-label public suffixes, start from the canonical origin directly. Shadscan pins that origin for the remaining routes. Treat any blocked unrelated-origin or client-side cross-origin navigation as an explicit coverage gap. Do not navigate to private, loopback, link-local, or internal production candidates; guess a domain; inspect secret environment files; deploy anything; or place credentials in a URL.
Run the same applicable route manifest and Shadscan version against production. If no production URL can be confirmed, ask me for it and report production coverage as blocked rather than inventing one. Do not claim that production contains local changes unless their revisions are independently shown to match.
5. Interpret and report the results
An exit code of 1 with a stdout JSON report whose kind is "overflow-check" and status is "fail" is a completed critical product finding. An exit code of 1 with empty stdout and an operational error on stderr means the entire batch was not verified. Split and rerun smaller batches to isolate the unavailable route and recover evidence for the remaining pages when safe.
Before changing code, give me:
- the static score, work items by severity, and files with the most findings;
- every detected application and the local and production origins used;
- a route table showing local mobile, local desktop, production mobile, and production desktop status, finalPath, httpStatus, and confirmed page identity for every concrete page;
- every critical overflow failure and likely culprit;
- every excluded or blocked route with its reason and coverage totals for each environment;
- the exact commands run and confirmation that any server you started was stopped;
- one prioritized remediation plan, with every decide item phrased as a question for me.
Never say "all pages passed" while any application, route shape, auth state, environment, or production identity remains unresolved. Stop and wait for my approval before changing anything.The recommended way to start is to hand the audit to your AI coding agent. Copy the prompt above and paste it in ā it runs one source audit across every detected application, inventories each app's concrete page routes, and runs the rendered UI suite on those pages both locally and in production. Missing deployment URLs, dynamic values, or authenticated access remain explicit coverage gaps. The agent then proposes one prioritized plan for you to approve before anything changes.
Hand the results off to an agent
$ pnpm dlx @shadscan/cli --promptAfter a scan, --prompt turns the results into a paste-ready Markdown handoff: the exact findings with evidence, suggested fixes, acceptance criteria, and the rescan command. Paste it into Claude Code, Codex, or any coding agent ā or skip the paste entirely with --apply, which launches an installed agent with the same handoff.
A handoff works better than a "fix my UI" prompt because the agent starts from deterministic evidence instead of rediscovering problems: every task is scoped to a real finding, has acceptance criteria to meet, and ends with the exact command that verifies the fix. The same source always produces the same handoff, so agent sessions stay reproducible and reviewable.
To get the most out of a handoff:
- Start from a clean working tree, so the agent's diff contains nothing but remediation and stays easy to review.
- Narrow big audits with
--categoryor a path ā one focused session per category beats one sprawling session that loses context. - Have the agent propose a plan before editing, and approve it first ā the recommended prompt above already insists on this.
- When the agent says it is done, rescan. The score is the acceptance test, and
--fail-undermakes it a CI gate so regressions cannot merge.
Scan another directory
$ pnpm dlx @shadscan/cli ../my-shadcn-appThe default human report leads with an overall progress bar, then includes category scores, evidence, fixes, and agent-ready actionables. Local TTYs receive a width-aware Unicode and color bar; CI and redirected output receive a deterministic ASCII fallback with color disabled by default. NO_COLOR always wins, while FORCE_COLOR can color that fallback. Roast copy is enabled for local human output and disabled automatically in CI.
Check rendered UI
$ pnpm dlx @shadscan/cli --check-ui http://localhost:3000 --route /dashboardStart your app first, or pass a deployed URL. Shadscan does not install dependencies, build the app, or run its dev or start scripts. This mode checks the supplied URL from any directory, so it does not need a project or package.json. The target URL is always included; repeat --route to check more paths beginning with /, up to ten pages in total. Routes cannot contain query strings or fragments.
Follow progress in the terminal
ā Resolving UI target
ā Checking mobile and desktop layouts
ā Preparing UI reportInteractive human runs write this checklist to stderr and leave the completed phases visible above the final report. JSON, CI, TERM=dumb, non-TTY stderr, and --no-interactive output stay quiet. Redirecting stdout keeps the report clean while progress remains on an eligible stderr terminal.
The initial request may follow narrowly validated server-side canonical redirects between a conventional two-label apex host and its www host, and from HTTP to HTTPS. For multi-label public suffixes, pass the canonical origin directly. Shadscan pins the resolved origin for every additional route. Other cross-origin redirects, HTTPS downgrades, and client-side cross-origin navigations remain blocked. Reports use the resolved origin as their target; human output also identifies the originally requested origin when it changed.
The two fixed CSS viewports are:
- Mobile: 320 Ć 820.
- Desktop: 1440 Ć 1000.
Any document-level horizontal overflow is a critical failure, including a single CSS pixel or a horizontal scrollbar forced on the root or body. Failed measurements include bounded likely culprit selectors when Shadscan can identify them. Local scroll areas that do not enlarge the document remain valid.
This is a rendered UI suite, not another source-audit rule. Horizontal overflow is its first check, and more deterministic UI checks can be added to the same command. The current check produces no score or grade and does not change the 62-rule catalog, ruleset, audit schema, or existing mobile-overflow-absent advisory.
Use it in automation
$ pnpm dlx @shadscan/cli --check-ui https://preview.example.com --jsonA clean result exits 0. Detected overflow exits 1 after writing the complete human or versioned JSON report to stdout. Browser, target, timeout, response, stability, and argument errors also exit 1, but leave stdout empty and write the error to stderr.
Install Chromium if needed
pnpm dlx playwright-core@1.61.1 install chromiumRendered UI mode performs GET navigations and executes the target page's JavaScript in fresh isolated Chromium contexts. It reads no project source, invokes no package scripts, and saves no page data. It is available only in the local CLI, not through MCP, the GitHub Action, hosted API, or web scanner.
Options
[path]- Project directory to scan. Relative paths resolve from the current directory. Defaults to .
--check-ui <url>- Run deterministic rendered UI checks against an already-running HTTP or HTTPS app. Horizontal overflow is the first check.
--route <path>- Add a path beginning with / against the resolved origin. Query strings and fragments are not accepted. Repeatable; ten total pages maximum.
--browser-executable <path>- Use a specific Chromium-family executable for rendered UI mode.
--format <format>- Choose human, json, or prompt output. Human output is the default.
--prompt- Print only a neutral, paste-ready Markdown prompt for an AI coding agent.
--json- Print the complete machine-readable audit report. Alias for --format json.
--apply- Validate and open an installed coding-agent CLI with the generated remediation prompt. Local interactive terminals only.
--agent <agent>- Choose claude, codex, or grok for --apply. Without it, choose a matching PATH candidate to validate and launch.
--fail-under <score>- Exit with status 1 when the score is below an integer from 0 to 100, or is unassessed.
--category <category>- Run only one audit category.
--no-roast- Keep human-readable findings neutral.
--roast- Include roast copy in CI or JSON output.
--no-interactive- Disable terminal progress and follow-up prompts.
--help- Print command usage and all available options.
--version- Print the installed Shadscan version.
Categories are foundation, interaction, states, accessibility, forms, and production-polish. The --prompt and --json aliases cannot be combined with each other or with --format. --apply requires human output, and --agent requires --apply. In rendered UI mode, only human or JSON output is available; source-audit paths, score, category, prompt, agent, project-selection, and roast options are rejected.
Create an agent prompt
$ pnpm dlx @shadscan/cli --prompt--prompt is an alias for --format prompt. It prints only neutral Markdown that you can paste into an AI coding agent. This output mode does not call an AI model itself.
The generated prompt contains:
- The repository identity, score, and exact ruleset version.
- Grouped fixes, product decisions, and manual verification work.
- Evidence, suggested fixes, and acceptance criteria.
- Detected project gates and the exact rescan command.
Add a path or category before the flag to narrow the handoff, for example ../my-app --category accessibility --prompt.
Apply with an installed agent
$ pnpm dlx @shadscan/cli --apply --agent codex--apply prints the report, creates the same neutral remediation prompt, and opens Claude Code, Codex CLI, or Grok Build in the package-manager root. Omit --agent to choose from the matching candidates Shadscan finds on PATH. The selected provider is validated before launch.
Agent launch is disabled in CI and when the input, output, or error stream is not an interactive terminal. Shadscan rejects project-local executables, checks the provider identity, launches with an argument array and no user-controlled shell command or approval-bypass flags, and removes its private prompt file when the agent exits.
The external agent may read and edit files, run commands, and send prompt data to its provider. A failed agent exits non-zero and can never clear a failed --fail-under gate.
Use JSON and score gates
Read the complete report
$ pnpm dlx @shadscan/cli --jsonJSON output includes the score, category summaries, every rule result, and agentHandoff. The current audit schema version is 4.
Fail CI below a score
$ pnpm dlx @shadscan/cli --json --fail-under 80Findings normally exit with status 0. With --fail-under, Shadscan exits with status 1when the score is below the floor or cannot be assessed. Discovery and audit failures also exit with status 1.
Run one category
$ pnpm dlx @shadscan/cli --category accessibilityAudit every push with the GitHub Action
The shadscan repository doubles as a composite GitHub Action. It runs the CLI against your project, writes the score and category table to the job summary, optionally fails the job below a score floor, and can keep a single tracked issue up to date with the findings and a paste-ready agent 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.17.1 # pin an exact CLI version
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 for downstream steps. Pin an exact CLI version in CI ā a moving dist-tag is not a reproducible build input.
With create-issue enabled, the action needs the issues: write permission. Instead of filing a new issue on every run, it updates one open issue per label, and the issue body embeds the same --prompt handoff you would generate locally ā assign the issue to your coding agent and the remediation plan is already inside it.
Add a pre-commit score gate
A local interactive scan ends with a post-scan menu: copy the agent handoff to your clipboard (it prints too), print it without copying, launch an installed agent, or add a score gate when no active blocking Shadscan hook protects the project yet. Pick with the arrow keys and Enter ā the handoff is highlighted first, so a single Enter grabs it. Press Esc to keep just the score, or use --no-interactive to suppress terminal progress and the menu entirely. Category-scoped scans do not offer a hook because their score cannot establish a full-project floor.
Preview the exact hook plan
$ pnpm dlx @shadscan/cli setup --pre-commit --dry-runApply a reviewed plan without another prompt
$ pnpm dlx @shadscan/cli setup --pre-commit --yesThe plan pins the exact Shadscan version and uses the current complete assessed score as its --fail-under floor. Shadscan can safely create or extend simple native Git hooks using POSIX sh or dash. It preserves existing commands, never executes the hook, and gives manual instructions for Husky, Lefthook, simple-git-hooks, pre-commit, conflicting managers, other shell interpreters, and opaque native hooks.
Run it before agent commits
The optional shadscan-pre-commit skill establishes a baseline and requires AI agents to rerun the audit immediately before every commit. It adds no Git hook or project dependency; use shadscan setup --pre-commit when you want an actual repository hook.
$ pnpm dlx skills add TheOrcDev/skills --skill shadscan-pre-commit --globalUse $shadscan-pre-commit for this task. Establish the current score before editing, run Shadscan immediately before every commit, and do not commit if the audit is unassessed or below the task floor.MCP server
shadscan mcp serves the audit over the Model Context Protocol on stdio, so coding agents query results as typed tool calls instead of parsing output. Three read-only tools: scan returns the score and actionables, filterable by category, severity, or workspace package; list_projects classifies a monorepo's packages; explain_rule describes one rule. Every call re-scans the current file state ā results are never cached ā and the server only reads inside the roots it was started with.
claude mcp add shadscan -- npx -y @shadscan/cli mcpSetup for other clients, the tool reference, and the security posture live in the MCP runbook.
Make it a project rule
Add this policy to AGENTS.md, or the equivalent instruction file for your agent, to activate the skill for future commit tasks.
## Shadscan
Before creating any commit, use $shadscan-pre-commit. Establish the current score when work begins, run Shadscan immediately before each commit, and do not commit if the score is unassessed or below the task floor.Troubleshooting
An older version runs right after a release
pnpm 11.15 and newer delays newly published versions through its minimumReleaseAge supply-chain setting, so pnpm dlx @shadscan/cli can silently resolve to the previous release for a few days after a new one ships. Pin the exact version (@shadscan/cli@<version>) to run it immediately, or wait for the delay to pass.
A stale version keeps running
One-shot runners cache downloads. If an old version persists after an update, pin the exact version, or clear the cache: npx --yes forces a fresh resolution and pnpm store prune drops unreferenced packages. Check what actually ran with --version.