i built cursor-doctor after watching teams waste hours debugging Cursor rules that "stopped working." The problem is always the same: someone added a rule with broken YAML frontmatter, or two rules contradicted each other, or a glob pattern had a typo. Cursor doesn't warn you. The rule silently fails.
Here's how to catch that in CI.
tl;dr
Add this to .github/workflows/cursor-rules.yml:
- uses: nedcodes-ok/cursor-doctor@v1
Every PR now checks your Cursor rules for errors before merge.
GitHub Actions setup
Create .github/workflows/cursor-rules.yml:
name: Cursor Rules Health Check
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint-cursor-rules:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nedcodes-ok/cursor-doctor@v1
If cursor-doctor finds issues, the workflow fails and the PR can't merge.
The action handles Node.js setup automatically. No setup-node step needed.
action inputs
Two optional inputs:
- uses: nedcodes-ok/cursor-doctor@v1
with:
path: './my-project' # Path to scan (default: '.')
fail-on-warning: 'true' # Fail on warnings too (default: 'false')
only run when rules change
Save CI minutes with a paths filter:
on:
push:
branches: [main]
paths:
- '.cursor/rules/**'
- '.cursorrules'
- 'CLAUDE.md'
- 'AGENTS.md'
pull_request:
branches: [main]
paths:
- '.cursor/rules/**'
- '.cursorrules'
- 'CLAUDE.md'
- 'AGENTS.md'
what the output looks like
Here's actual output from cursor-doctor lint on a project with a few issues:
cursor-doctor v1.10.24 -- lint
.cursor/rules/testing.mdc (3 warnings)
⚠ Vague rule detected: "follow best practices" (line 5)
→ Replace with a specific instruction. Say exactly what
to do: what tool, what pattern, what format.
⚠ Description is very short (<10 chars)
→ A descriptive description helps Cursor decide when to
apply this rule.
⚠ Description is identical to filename
→ Describe what the rule does, not just repeat the filename.
.cursor/rules/types.mdc (1 warning, 1 info)
⚠ Rule uses weak language: "try to/maybe/consider"
→ AI models follow commands better than suggestions. Use
imperative mood: "Do X" instead of "try to do X".
──────────────────────────────────────────────────
4 warnings, 1 info, 1 passed
The check command (default in CI) gives a pass/fail health grade. Grades D and F fail the build.
pre-commit hook
Catch issues before you even push. Create .git/hooks/pre-commit:
#!/usr/bin/env bash
STAGED=$(git diff --cached --name-only --diff-filter=ACM \
| grep -E '\.mdc$|\.cursorrules$|CLAUDE\.md$|AGENTS\.md$')
if [ -z "$STAGED" ]; then
exit 0
fi
echo "cursor-doctor: checking staged rule files..."
npx cursor-doctor check
exit $?
Then chmod +x .git/hooks/pre-commit. The hook only runs when you stage rule files.
what it catches
Frontmatter errors: Missing YAML blocks, parse errors, alwaysApply: "true" (string instead of boolean, rule never activates).
Glob mistakes: Windows backslashes that match nothing, typos in extensions, overly broad patterns.
Semantic conflicts: "Use semicolons" vs "omit semicolons." cursor-doctor checks 48 conflict patterns across formatting, imports, error handling, and state management.
Vague instructions: "Write clean code" and "follow best practices" waste tokens without changing model behavior.
Token budget waste: Too many alwaysApply rules burning context window, duplicate content across files, dead rules nobody references.
other CI platforms
The GitHub Action runs npx cursor-doctor check under the hood. Use the same command anywhere:
GitLab CI:
lint-cursor-rules:
image: node:20
script:
- npx cursor-doctor check
only:
- merge_requests
- main
CircleCI:
version: 2.1
jobs:
lint-cursor-rules:
docker:
- image: cimg/node:20.0
steps:
- checkout
- run: npx cursor-doctor check
workflows:
check-rules:
jobs:
- lint-cursor-rules
Exit code 0 = healthy. Exit code 1 = issues found.
testing locally
Run the same check CI will run:
npx cursor-doctor check
For the detailed breakdown:
npx cursor-doctor lint
Fix issues, push, CI passes on the first try.
npx cursor-doctor fix --preview shows available auto-fixes. Many issues can be fixed automatically. First fix is free.
Top comments (0)