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, 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. See Boot trace |
--report writes HTML rather than a payload, so it refuses to share a run with
--format, --json or --score. 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. Review the findings, open the HTML report, hand off to a coding agent, scaffold the GitHub Actions workflow when it is missing, or copy the findings as markdown. Everything comes from the scan that just ran, so nothing is scanned twice.
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; the scan itself reports only anonymous rule counts.
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, 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, 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.