Diagnose and improve Angular codebases with a single command.
Angular Doctor scans your project for Angular-specific lint issues and dead code, then produces a 0β100 health score plus actionable diagnostics.
β¨ Features
- Angular-aware linting (components, directives, pipes, performance, architecture, TypeScript)
- Dead code detection (unused files, exports, types) via knip
- Workspace support (Angular CLI + npm/pnpm workspaces)
- Diff mode to scan only changed files
- Markdown reports for sharing results
β Quick start
Run at your Angular project root (or workspace root):
npx -y angular-doctor@latest .Generate a Markdown report in the current directory:
npx -y angular-doctor@latest . --report .
Show affected files and line numbers:
npx -y angular-doctor@latest . --verboseπ€ Install for your coding agent
Teach your coding agent to run Angular Doctor automatically after every Angular change:
curl -fsSL https://raw.githubusercontent.com/antonygiomarxdev/angular-doctor/main/install-skill.sh | bashSupports Cursor, Claude Code, Windsurf, Amp Code, Codex, Gemini CLI, and OpenCode.
Once installed, your agent will automatically run:
npx -y angular-doctor@latest . --verbose --diffβ¦after making Angular changes, catching issues before they reach review.
π GitHub Actions CI
Integrate Angular Doctor into your GitHub CI pipeline to post PR comments with health scores and enforce quality gates.
Basic Setup
name: Angular Doctor on: push: branches: [main] pull_request: jobs: angular-doctor: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Angular Doctor uses: antonygiomarxdev/angular-doctor@v1.2.0 with: directory: . verbose: true github-token: ${{ secrets.GITHUB_TOKEN }}
With Score Gating
Fail the CI build when the score falls below a threshold:
name: Angular Doctor on: push: branches: [main] pull_request: jobs: angular-doctor: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Angular Doctor id: angular-doctor uses: antonygiomarxdev/angular-doctor@v1.2.0 with: directory: . github-token: ${{ secrets.GITHUB_TOKEN }} score-threshold: 75 # Fail if score < 75 - name: Use score output run: echo "Score: ${{ steps.angular-doctor.outputs.score }}"
Diff Mode for PRs
Scan only changed files vs the main branch:
name: Angular Doctor on: push: branches: [main] pull_request: jobs: angular-doctor: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Required for diff mode - name: Run Angular Doctor uses: antonygiomarxdev/angular-doctor@v1.2.0 with: directory: . diff: main # Compare against main branch github-token: ${{ secrets.GITHUB_TOKEN }}
Action Inputs
| Input | Description | Default |
|---|---|---|
directory |
Project directory to scan | . |
verbose |
Show file details per rule | true |
project |
Workspace project(s) to scan (comma-separated) | β |
diff |
Base branch for diff mode | β |
github-token |
GitHub token for posting PR comments | β |
score-threshold |
Exit with error code when score is below threshold | 0 |
node-version |
Node.js version to use | 20 |
Action Outputs
| Output | Description |
|---|---|
score |
Health score (0-100) |
label |
Score label (Great, Needs work, Critical) |
PR Comment Example
When github-token is provided on pull request events, Angular Doctor posts a comment like:
π§ Workspace support
Angular Doctor automatically detects multiple projects:
- Angular CLI workspaces β reads
angular.jsonand scans each project insideprojects/ - npm / pnpm workspaces β detects packages with
@angular/corefromworkspacesorpnpm-workspace.yaml
When multiple projects are found:
- Interactive mode: prompts for which projects to scan
- Non-interactive mode (
-y, CI): scans all detected projects
Target a specific project (comma-separated for multiple):
npx -y angular-doctor@latest . --project my-app,my-libβοΈ CLI Options
Usage: angular-doctor [directory] [options]
Options:
-v, --version display the version number
--no-lint skip linting
--no-dead-code skip dead code detection
--verbose show file details per rule
--score output only the score
--report [path] write a markdown report (optional output path)
--fast speed up by skipping dead code and type-aware lint
-y, --yes skip prompts, scan all workspace projects
--project <name> select workspace project (comma-separated for multiple)
--diff [base] scan only files changed vs base branch
-h, --help display help for command
π Reports
Use --report to write a Markdown report:
--reportwrites to the diagnostics temp folder--report .writes to the current project directory--report ./reportswrites to a custom folder--report ./reports/scan.mdwrites to a specific file
π§ Configuration
Create an angular-doctor.config.json in your project root:
{
"ignore": {
"rules": ["@angular-eslint/prefer-standalone"],
"files": ["src/generated/**"]
}
}Or use the angularDoctor key in package.json:
{
"angularDoctor": {
"ignore": {
"rules": ["@angular-eslint/prefer-standalone"]
}
}
}Config options
| Key | Type | Default | Description |
|---|---|---|---|
ignore.rules |
string[] |
[] |
Rules to suppress using the plugin/rule format |
ignore.files |
string[] |
[] |
File paths to exclude, supports glob patterns |
lint |
boolean |
true |
Enable/disable lint checks |
deadCode |
boolean |
true |
Enable/disable dead code detection |
verbose |
boolean |
false |
Show file details per rule |
diff |
`boolean | string` | β |
π¦ Node.js API
import { diagnose } from "angular-doctor/api"; const result = await diagnose("./path/to/your/angular-project"); console.log(result.score); // { score: 82, label: "Great" } console.log(result.diagnostics); // Array of Diagnostic objects console.log(result.project); // Detected framework, Angular version, etc.
Each diagnostic has the following shape:
interface Diagnostic { filePath: string; plugin: string; rule: string; severity: "error" | "warning"; message: string; help: string; line: number; column: number; category: string; }
π§ͺ What it checks
Components
- Missing
Component/Directiveclass suffixes - Empty lifecycle methods
- Missing lifecycle interfaces
- Pipe not implementing
PipeTransform
Performance
- Missing
OnPushchange detection strategy - Outputs shadowing native DOM events
Architecture
- Conflicting lifecycle hooks (
DoCheck+OnChanges) - Use of
forwardRef - Renamed inputs/outputs
- Inline
inputs/outputsmetadata properties - Non-standalone components (Angular 17+)
TypeScript
- Explicit
anyusage
Dead Code
- Unused files
- Unused exports and types
π‘ Inspiration
Inspired by react-doctor.
π License
MIT

