CLI reference
Run a scan without installing anything:
npx nestjs-doctor@latest [directory] [options]The directory defaults to the current one.
Commands
| Command | Does |
|---|---|
ci install | Writes .github/workflows/nestjs-doctor.yml at the repository root. Add --force to replace an existing file |
Scanning
| Flag | Does |
|---|---|
--verbose | Show the file and line behind every diagnostic |
--config <path> | Use a specific config file instead of auto-detecting |
--list-rules | Print every built-in rule and exit |
-h, --help | Print usage and exit |
Ctrl+C cancels a running scan immediately and exits 130.
Scope
Scoping changes what is reported, never what is analyzed. Cross-file rules need the whole project, so the score always covers all of it.
| Flag | Does |
|---|---|
--scope full | Everything. The default |
--scope files | Diagnostics in the changed files |
--scope lines | Diagnostics on the changed lines |
--scope changed | Only what the change introduced, compared against the merge base |
--base <ref> | The ref to compare against. Auto-detected when omitted |
--staged | Scope to staged files, for a pre-commit hook |
--changed-files-from <path> | Read the changed file list from a file, for CI |
changed needs history. Without a reachable base ref it degrades wider and says
so: to every diagnostic in the changed files when --changed-files-from is set,
and to the whole project when it is not. In CI, check out with fetch-depth: 0.
files and lines keep a finding whose file sits above the scanned directory.
The changed-file set describes the scanned tree only, so a package.json one
level up is never known to be unchanged. changed still drops it, because it
compares against the base revision rather than the file list.
Output
| Flag | Does |
|---|---|
--format <f> | console (default), json, report-json, sarif, gitlab, markdown, github |
--json | Shorthand for --format json |
--json-compact | Emit JSON formats without indentation |
--output <path> | Write to a file instead of stdout. With --report, where the HTML goes |
--score | Print only the number |
--report | Build the interactive HTML report. --graph is an alias |
--timings <path> | Overlay boot timings on the report's module graph; with --format report-json, embeds them in the artifact. See Boot trace |
--sources <mode> | How much source text the report carries: all (default), touched (only files with findings), none |
--share-sections <csv> | Write a shareable slice as nestjs-doctor-shared.json. See Sharing a report |
--share-code | With --share-sections, include a few lines of code around each shared finding |
--format report-json writes the same document the HTML report embeds, as
versioned JSON for another tool to load: the score, findings, module graph,
providers, endpoints, code graph, schema, rule examples, source text, and the
slices behind Sharing a report. It writes
nestjs-doctor-report.json beside the scanned project, or wherever --output
points, and replaces the console report. The HTML report and the JSON artifact
are built from that one document, so they always agree.
--report writes HTML rather than a payload, so it refuses to share a run with
--format, --json, --score or --share-sections. Any of those combinations
exits 2 and names the flag. Run them as separate commands.
Only the payload goes to stdout, so a machine-readable one stays parseable. Warnings print on stderr.
Two of them are suppressed instead in machine-readable mode, meaning --score
and every format except console and github. A custom rule that failed to
load is silent, and a run below --min-score exits 1 with no message on
either stream.
The menu
A console scan in a terminal ends on a score screen: the nest, the score with its bar, the severity counts, and a short action menu in two groups. Keep it running holds the three ways to make the scan recur. This scan holds fix the issues with your coding agent, review the findings, open the HTML report, and a More row that unfolds copy as markdown and share a slice of the report. Everything comes from the scan that just ran, so nothing is scanned twice.
Three menu items make the scan recur, and the one the repository is closest to
carries a Recommended badge: Review every pull request scaffolds the
GitHub Actions workflow when it is missing; Check every commit appends a
--staged --blocking error scan of the directory you scanned, pinned to the
running version, to .husky/pre-commit, or copies or shows a snippet for
lefthook and simple-git-hooks, and shows only when one of those tools is set
up; Rescan after every agent edit installs the agent skill.
The first plain terminal run on a project ends with one dim line on stderr
naming the recurring trigger the repository is closest to: ci install when a
.github/workflows directory exists without the nestjs-doctor workflow,
--staged in a pre-commit hook when husky or lefthook is set up, and --init
otherwise. It prints once per project and never in CI, inside a coding agent,
in a pipe, or with machine-readable output.
Share the report opens a checkbox picker over the sections the scan produced. See Sharing a report.
In a monorepo the breakdown is a two-pane browser. Sub-projects list worst score first. The left pane is the scrollable project list, and the right pane is the action menu.
A side panel shows the selected project's score, error, warning and info counts,
file count, and the rules it trips most. ↑↓ moves in the focused pane, ←→ or
tab switches panes, enter confirms the menu action, q quits.
An interactive run hands its presentation to that screen and prints nothing
else. Pass --verbose to print the full findings list above it instead.
Review issues opens a live browser. The left pane lists the findings grouped by rule under category captions, worst first; the right pane follows the selection with the rule's identity and severity badge, the location, the message, the offending code window, the rule's recommendation with its docs link, and then a bad and a good sample of the pattern. Most samples are tested against the rule they illustrate, so the bad one is what the rule reports and the good one is what it accepts.
Navigation is by key: ↑↓ or j/k moves finding by finding, ←→ jumps a
whole rule group, g/G go to the ends, c copies an agent-ready fix prompt
for the selected rule, o opens the docs page, b returns to the score
screen.
Handing off detects Claude Code, Codex, and Cursor on your PATH and starts the one you pick with the top findings as its first prompt, plainly: no permission-skipping flags are passed. Copy the prompt instead to use any other agent. The prompt never leaves your machine; what the scan itself reports is listed on Telemetry.
The menu never appears where it could hang a machine. It is skipped in CI,
inside coding agents, in pipes, in dumb terminals, and in every mode other
than plain console output. Quitting keeps the run's exit code.
Gates
| Flag | Does |
|---|---|
--blocking <level> | Severity that fails the run: none, warning, error. Only findings on the ciFailure surface can trip it |
--min-score <n> | Fail when the project's score is below this |
--min-score overrides the config file's minScore, which applies on its own
when the flag is omitted. --blocking has no single default. It is set by the
output mode:
| Output mode | Default |
|---|---|
| The console report | error |
--format github | error |
--score, and the formats that replace the console report: json, report-json, sarif, gitlab, markdown | none |
Those exit codes predate the flag. Set --blocking explicitly and every mode
agrees.
Agents
| Flag | Does |
|---|---|
--init | Install the skill for your coding agent. See Coding agents |
Exit codes
Every run ends in one of four codes:
| Code | Meaning |
|---|---|
0 | Passed |
1 | A gate failed |
2 | Bad input: the path does not exist, holds no TypeScript files, a flag is invalid, or two flags conflict |
130 | You cancelled the scan with Ctrl+C |
The score gate is checked before the severity gate, so a run below --min-score
exits 1 whether or not any diagnostic was blocking.