Add cursor-doctor to your CI pipeline in 2 minutes
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.
why lint Cursor rules in CI
i built cursor-doctor after watching teams waste hours debugging 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 and your team wonders why the AI is ignoring instructions.
Linting in CI catches these before they reach your team:
- Rules drift: A teammate adds a rule that says "use semicolons" when another rule already says "omit semicolons." Nobody notices until Cursor's behavior gets unpredictable.
- Broken frontmatter: YAML syntax errors make rules disappear. Cursor loads everything else and silently skips the broken one.
- Invalid globs: Glob patterns with typos or Windows backslashes match zero files. The rule exists but never activates.
- Vague instructions: New team members copy "follow best practices" into a rule. It burns tokens on every request but doesn't change model behavior.
- Token budget creep: Every
alwaysApply: truerule adds to your context window usage. Without tracking, Cursor starts truncating your instructions.
GitHub Actions setup
Create .github/workflows/cursor-rules.yml in your repo:
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
This runs on every push to main and on every pull request. If cursor-doctor finds issues, the workflow fails and the PR can't merge.
Tip: 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')
path: Where your.cursor/directory lives. Default is the repo root.fail-on-warning: By default, only errors fail the build. Set totrueto also fail on warnings.
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".
ℹ Multiple globs could be simplified: *.ts, *.tsx
→ Consider using ["*.{ts,tsx}"] for cleaner syntax.
──────────────────────────────────────────────────
4 warnings, 1 info, 1 passed
⚡ 4 issues can be auto-fixed. Run: npx cursor-doctor fix
The check command (used by default in CI) gives a pass/fail health grade:
▒▒ Cursor Health: A ▒▒
██████████████████████████████ 96%
✓ Rule syntax
✓ No legacy .cursorrules
✓ Token budget within limits
✓ No semantic conflicts
4 passed 0 issues
Grades D and F fail the build. A, B, and C pass.
pre-commit hook
CI is your safety net. Catch issues before you even push with a pre-commit hook.
Copy the included hook script:
cp node_modules/cursor-doctor/scripts/pre-commit-hook.sh .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Or create .git/hooks/pre-commit manually:
#!/usr/bin/env bash
# cursor-doctor pre-commit hook
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 $?
The hook only runs when you stage rule files. If cursor-doctor finds issues, the commit is blocked.
Note: Pre-commit hooks are local only. They don't transfer when someone clones your repo. Use CI as the enforced gate.
what cursor-doctor catches in CI
frontmatter errors
- Missing YAML frontmatter: A
.mdcfile with no---block. Cursor ignores the entire file. - YAML parse errors: Broken indentation, missing colons, unclosed quotes. The rule won't load.
- Boolean strings:
alwaysApply: "true"instead ofalwaysApply: true. YAML treats this as a string, not a boolean. The rule never activates.
glob pattern mistakes
- Windows backslashes:
src\components\*.tsxdoesn't match anything. Globs use forward slashes. - Typos in extensions:
*.typscriptinstead of*.ts. The rule exists but never fires. - Overly broad patterns:
*or**matching everything when you meantalwaysApply: true.
semantic conflicts
- "Use semicolons" vs "omit semicolons"
- "Use default exports" vs "use named exports"
- "Always use try/catch" vs "let errors bubble up"
cursor-doctor checks 48 semantic conflict patterns across formatting, imports, error handling, state management, and more.
vague instructions
- "Write clean code"
- "Follow best practices"
- "Make it maintainable"
These don't change model behavior. They just waste tokens. Replace them with specific instructions like "extract functions longer than 20 lines" or "add JSDoc comments to exported functions."
other CI platforms
The GitHub Action runs npx cursor-doctor check under the hood. Use the same command anywhere with Node.js:
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
Jenkins
pipeline {
agent any
stages {
stage('Lint Cursor Rules') {
steps {
sh 'npx cursor-doctor check'
}
}
}
}
Exit code 0 means healthy. Exit code 1 means issues found. Same on every platform.
testing locally
Run the same check CI will run:
npx cursor-doctor check
For the detailed breakdown:
npx cursor-doctor lint
Fix the issues, push, and the CI check passes on the first try.
Pro tip: npx cursor-doctor fix --preview shows what auto-fixes are available. Many issues (frontmatter syntax, boolean strings, glob corrections) can be fixed automatically. First fix is free, all fixes with Pro ($9).
related guides
- How to lint your Cursor rules
- How to fix Cursor rule conflicts
- Sharing Cursor rules across a team
- Cursor token budget: how many rules is too many?
Start linting Cursor rules in CI
One line of YAML. Zero config. Broken rules never merge again.
- uses: nedcodes-ok/cursor-doctor@v1