iconscan CLI
Run this from the root of a React, Next.js, or TypeScript app. The one-shot command needs no project install. iconscan reads source files only — it never calls an AI model, uploads code, or touches your project unless you pass --apply.
Usage
iconscan [path] [options]
The optional path defaults to the current directory. Pass a relative or absolute path to scan another project — the scan walks *.ts/*.tsx files, skipping node_modules, build output, and your --exclude globs.
What it checks
Findings are grouped by rule and severity. Warnings carry a suggested fix; infos are facts worth a human glance.
| Rule | Severity | What it means |
|---|---|---|
| dead-import | warning | Icon imported but never rendered — safe to delete. |
| brand-icon | warning / info | Brand logo imported from a library that removed brands (lucide, heroicons) → warning + react-icons/si fix. From a library that still ships brands or a local component → info, verify it renders the official asset. |
| generic-icon | info | Placeholder names like Icon, Logo, Img — rename to something meaningful. |
| duplicate | info | Same icon imported from multiple libraries. |
| fragmentation | info | More than two icon libraries in one project. |
| parse-error | info | File failed AST parsing — scanned with the regex fallback, results may undercount. |
Options
| [path] | Project directory to scan. Defaults to . |
| -f, --format <fmt> | pretty (default), json, or md. |
| -e, --exclude <globs> | Comma-separated glob patterns to skip. |
| --apply | Apply safe fixes — AST-verified renames with .iconscan.bak backups. Prompts before writing unless --yes. |
| --yes | Skip the confirmation prompt for --apply. |
| --prompt | Print a paste-ready AI-agent remediation handoff instead of the report. |
| --rollback | Restore files from .iconscan.bak backups. |
| --fail-under <n> | Exit 1 when the score is below n (0–100). |
| --help / --version | Print usage / installed version. |
Exit codes: 0 success, 1 score below --fail-under, 2 usage error (bad format, nonexistent path).
Output formats
The report always goes to stdout; progress and status go to stderr, so piping stays clean.
iconscan . # colored terminal report (default) iconscan . --format md # markdown report for PRs/issues iconscan . --format json # score, stats, and every issue, machine-readable
Scoring
Starts at 100 and subtracts capped penalties per category — dead imports, duplicates, generic names, parse errors, libraries beyond two, and error-severity issues. Deterministic: same project, same score.
Autofix and rollback
--apply performs AST-level rewrites — it removes dead specifiers, migrates brand imports to verified targets, and consolidates libraries. Before touching a file it writes a byte-identical .iconscan.bak backup, and only emits a rename when the target library is installed and actually exports the replacement (verifyExport) — otherwise it skips and says why.
iconscan . --apply # review each fix interactively iconscan . --apply --yes # apply all safe fixes iconscan . --rollback # restore every .iconscan.bak
Agent prompt
--prompt prints a neutral Markdown handoff: the score, grouped findings with evidence, suggested fixes, acceptance criteria, and the exact rescan command. Paste it into Claude Code, Codex, or any coding agent — the agent starts from deterministic evidence instead of rediscovering problems.
iconscan . --prompt > iconscan-handoff.md
JSON and CI
--format json emits the complete report — score, stats, and every issue with rule, severity, file, line, and fix. Combine with --fail-under to gate merges:
# .github/workflows/iconscan.yml
name: iconscan
on: [push, pull_request]
jobs:
icons:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx iconscan . --fail-under 80Pin an exact version in CI — a moving dist-tag is not a reproducible build input.
Troubleshooting
An older version runs right after a release
One-shot runners cache downloads. Pin the exact version (iconscan@<version>) or clear the cache; check what ran with --version.
Brand imports show info, not a fix
Intentional — iconscan only autofixes brands from libraries that removed them upstream (lucide, heroicons). Libraries that still ship brands get a verify-official info; migrating them would swap one unofficial asset for another.
A file is skipped with a parse error
Unparseable files fall back to regex extraction, which can undercount refs — it is counted in stats.parseErrors and surfaced as an info finding, never silently dropped.
Report a bug or missing library
Open an issue at github.com/princepal9120/iconscan.