CLI reference
Commands: check, fix, new, baseline, explain, init.
shapelint check
Loads the nearest config, checks every file claimed by a rule, prints the findings, and exits with a status code.
shapelint check- Config discovery walks up from the current directory looking for
shapelint.config.ts,.js, or.mjs. You can run it from any subfolder. - Globs in each rule's
filesare resolved relative to the config'sroot. - First-match-wins: a file claimed by an earlier rule is not re-checked by a later one.
Exit codes
| Code | Meaning |
|---|---|
0 | No violations (or warn-severity findings only). |
1 | One or more error-severity findings. |
2 | Operational failure, no config, invalid config, no rules, or a bad pattern. |
Exit 2 is distinct from 1 on purpose: it means Shapelint could not do its job, not that your code failed. CI should treat both as failures but can message them differently.
--format
Overrides the config output field:
| Format | Use |
|---|---|
human | Default. Colorized, self-contained diagnostics. |
agent | Same text, color stripped, for piping into an AI agent. |
json | Structured (version: 1, summary, full diagnostics array). |
github | GitHub Actions workflow annotations (::error file=…,line=…::…). |
shapelint check --format json
shapelint check --format github # inline annotations in a PR--semantic
Runs the AI/semantic tier in addition to the deterministic checks. Requires a judge in the config; without one, Shapelint warns and skips the pass. Semantic findings are warnings unless a rule opts into blocking.
shapelint check --semantic--cache
Persists a content-hash cache in .shapelint/check-cache.json so unchanged files skip the parse/match work on the next run, useful in CI (restore the cache between runs) and pre-commit.
shapelint check --cacheCorrectness is preserved by construction: only the pure, content-derived checks (pattern, filename, imports, usage) are cached, keyed by the file's content hash and a hash of the config. Filesystem-dependent checks (requires, belongsHere, unmatched) are always recomputed, and any config change invalidates the whole cache. Commit .shapelint/check-cache.json or not, as you prefer, it is safe to delete at any time.
Running without installing
If Shapelint isn't a dependency of the target project, use a plain-object config and invoke the built CLI by path:
node /path/to/shapelint/dist/cli.js checkshapelint init
Writes a starter shapelint.config.ts with one example rule to edit. It detects whether your project uses a src/ directory (to set root), nothing else is inferred from your code; the rules are yours to write. Refuses to overwrite an existing config.
shapelint initInferring a config from your actual code (a full-repo scan that proposes rules from the shapes it finds) is a v2 idea, not what
initdoes today.
shapelint baseline
Turning Shapelint on in an existing repo can surface hundreds of violations at once. baseline records the current failures so they stop failing the build, new violations still fail, and you fix the grandfathered ones over time.
shapelint baseline # grandfather every current error
shapelint baseline --prune # drop entries that no longer failWrites .shapelint/baseline.json (commit it). A baseline entry is a fingerprint of file + rule + code, deliberately excluding line numbers, so editing elsewhere in a file doesn't churn the baseline. check then suppresses matching errors and reports them as N grandfathered.
shapelint new <rule> <Name>
Scaffolds a conforming file from a rule's pattern, the file is correct by construction, so the agent starts from the right shape instead of being corrected afterwards. Prevention beats correction.
shapelint new ui-component Card
# → src/components/ui/Card.tsx, matching the ui-component patternThe target directory comes from the rule's files glob (its literal prefix), and the filename from the rule's filename spec. $Name / $name / $NAME placeholders in the pattern are substituted from <Name> (given in PascalCase). Refuses to overwrite an existing file.
shapelint explain <file>
Prints which rule claims a file and why (the matched glob, filename spec, import and usage rules), then runs that rule against the file and reports whether it conforms. This answers "why did / didn't this fire".
shapelint explain src/components/ui/Button.tsxshapelint fix
Applies the mechanical, judgment-free fixes Shapelint can make with certainty. Anything requiring a naming or decomposition decision is left for you (or the agent), those are reported by check as usual.
shapelint fix # dry run: list what would change, write nothing
shapelint fix --write # apply the fixes
shapelint fix --write --force # apply even if the git tree is dirtyCurrently fixes:
| Diagnostic | Fix |
|---|---|
ARCH_NAME_MISMATCH (literal or filename-bound target) | Rename the symbol and every reference. |
ARCH_EXPORT_FORM | Convert between named and default export, and rewrite importers. |
ARCH_FILENAME_MISMATCH (a kebab-case / PascalCase / camelCase convention) | Rename the file and rewrite import specifiers. |
ARCH_MISPLACED_FILE (belongsHere) | Move the file into the governed folder and rewrite import specifiers. |
Safety guarantees:
- Dry run by default. Nothing is written unless you pass
--write. - Verify-and-rollback. All edits are applied in memory, then the whole project is re-checked. If the fixes wouldn't reduce errors, or would make a previously-clean file fail, nothing is written.
- Refuses a dirty tree.
--writeaborts ifgit statusis dirty, unless you pass--force, so a fix is always its own reviewable diff.
Exit code is 0 when the tree is clean (or fully fixed), 1 when unfixable errors remain.
Move safety. When a fix moves or renames a file, verification re-checks the project with the moved-away path treated as gone and the new path in place, so the same converge-or-discard guarantee applies to moves. Path-alias imports (
@/…) aren't rewritten automatically yet, the verify step will refuse the move if that would break a build.