Contributing
This guide covers everything you need to contribute to claudelint: setting up your dev environment, writing rules, submitting PRs, and maintaining the project.
The most common contribution is adding a validation rule.
Code of Conduct
Please read the Code of Conduct before contributing.
Getting Started
Prerequisites
- Node.js 18.0.0 or higher
- npm or yarn
- Git
Dev environment setup
Fork the repository on GitHub
Clone your fork locally:
bashgit clone https://github.com/YOUR_USERNAME/claudelint.git cd claudelintInstall dependencies:
bashnpm installBuild the project:
bashnpm run buildRun tests to verify setup:
bashnpm testSet up git hooks (runs automatically on install):
bashnpm run setup:hooks
Development Workflow
Making changes
Create a new branch for your feature or fix:
bashgit checkout -b feature/your-feature-nameMake your changes following the code style guidelines below
Add or update tests for your changes
Run the full test suite:
bashnpm testRun linting and formatting:
bashnpm run lint npm run format:checkRun validation on the project itself (dogfooding):
bashnpm run check:self
See CLI Reference for complete command reference.
Previewing linter output
To see what claudelint errors and warnings look like in the terminal, run it against the test fixture projects:
# All categories with intentional errors/warnings (agents, skills, hooks, etc.)
npm run check:fixtures:invalid
# Clean run (zero issues)
npm run check:fixtures:valid
# Or point individual validators at fixtures
npx claudelint validate-agents --path tests/fixtures/projects/invalid-all-categoriesThe invalid-all-categories fixture has intentional violations across all 10 validator categories. The valid-complete fixture has valid files for every category and should produce zero issues. Both are tested in CI via tests/integration/fixture-projects.test.ts.
Code style
- Follow TypeScript best practices
- Use
unknowninstead ofanyfor unknown types - Add JSDoc comments to all public APIs
- Keep functions small and focused
- Write descriptive variable and function names
- Use proper type guards when narrowing types
Diagnostic collection
Library code uses DiagnosticCollector instead of console for all output. See Architecture for full details.
import { DiagnosticCollector } from '../utils/diagnostics';
// In functions
export function myFunction(
param: string,
diagnostics?: DiagnosticCollector
): Result {
if (invalid) {
diagnostics?.warn(
'Invalid param',
'MyFunction',
'MY_001'
);
}
}
// In classes
export class MyClass {
constructor(private diagnostics?: DiagnosticCollector) {}
myMethod() {
this.diagnostics?.error(
'Operation failed',
'MyClass',
'MY_002'
);
}
}This makes the library testable, allows programmatic usage, and provides structured diagnostics with source tracking.
Console is only allowed in the CLI layer (src/cli/utils/logger.ts), output formatting (src/utils/reporting/), and script utilities (scripts/util/logger.ts). This is enforced by npm run check:logger-usage in CI and pre-commit hooks.
Testing
- Write unit tests for all new rules
- Add integration tests for CLI commands
- Aim for 80%+ code coverage
- Test error conditions and edge cases
- Use descriptive test names
Verifying constants
Constants like ToolNames and ModelNames must stay synchronized with Claude Code. This is verified by querying the Claude Code CLI and is only required for maintainers doing releases.
Requirements: Claude Code CLI installed (from code.claude.com) and ANTHROPIC_API_KEY configured.
# Verify all constants
npm run check:constants
# Or individually
npm run check:tool-names
npm run check:model-namesIf drift is detected:
- Review the output to see missing/extra values
- Cross-check with official docs: Tools, Models
- Update
src/schemas/constants.tsif needed - Run tests:
npm test - Re-verify:
npm run check:constants
See the scripts/check/ directory for detailed documentation on verification scripts.
Commit messages
Follow Conventional Commits format (enforced by commitlint):
type(scope): subject
body (optional)
footer (optional)Types: feat, fix, docs, test, refactor, chore, perf
Examples:
feat(validators): add MCP server validatorfix(cli): handle missing config file gracefullydocs(readme): update installation instructions
Adding Validation Rules
claudelint uses a rule-based architecture similar to ESLint. Contributors write individual validation rules, not validators.
See the Custom Rules Guide for the full walkthrough: rule structure, validation patterns, testing strategies, auto-fix, and best practices.
Checklist:
- Create rule file in
src/rules/{category}/{rule-id}.ts - Define rule metadata (id, name, description, category, severity)
- Add
meta.docsdocumentation metadata (see schema and example below) - Implement
validate()function - Add rule to category index in
src/rules/{category}/index.ts - Write unit tests in
tests/rules/{category}/{rule-id}.test.ts - Test the rule with
npm test - Run
npm run docs:generateto verify documentation generates - Run validation on project:
npm run validate
Rule docs metadata
Rule documentation is auto-generated from meta.docs in each rule's source file. Include a docs property so the documentation site stays in sync automatically. See the RuleDocumentation schema for all available fields.
docs: {
recommended: true,
summary: 'Hook command references a script file that does not exist',
details: 'When a hook command points to a script, the referenced file must exist on disk...',
examples: {
incorrect: [{ description: 'Missing script', code: `command: "bash .claude/hooks/missing.sh"` }],
correct: [{ description: 'Existing script', code: `command: "bash .claude/hooks/validate.sh"` }],
},
howToFix: 'Create the missing script or update the command path.',
whenNotToUse: 'Disable if hook scripts are generated at build time.',
}For rules with configurable options, add optionExamples and relatedRules — see the schema for details.
Run npm run docs:generate after adding metadata to verify the generated page. Output appears in website/rules/{category}/{rule-id}.md.
Contributing Skills
Skills are interactive capabilities that allow Claude to help users validate, optimize, and fix their Claude Code projects through conversation.
Quality standards
All skills must follow Anthropic's best practices for skill development.
Required for all skills:
- Description with trigger phrases — must include what, when, triggers, and capabilities
- Proper naming — no single-word verbs, use suffixes like
-all,-cc,-cc-md - Automated validation — must pass
claudelint validate-skills - Manual testing — trigger phrases tested, functionality verified
Required for complex skills:
- Examples section — scenario-based examples (User says → Actions → Result)
- Troubleshooting section — for skills with >3 scripts or that edit files
Recommended:
- Progressive disclosure — for skills with >3,000 words, use a
references/directory
Submitting a skill
Before submitting a PR:
Validate structure:
bashclaudelint validate-skills .claude/skills/your-skillTest trigger phrases:
- Start fresh Claude session
- Test phrases from description field
- Verify 90%+ trigger success rate
Test functionality:
- Valid inputs work correctly
- Invalid inputs detected properly
- Edge cases handled
Update documentation:
- Add to README.md skills list
- Add to .claude-plugin/README.md
- Include in PR description
Skill PR checklist
When submitting a skill PR, include the following in your PR description (the PR template will guide you):
- Skill name and one-line description
- Trigger phrases (list at least 3)
- Confirmation that
claudelint validate-skillspasses - Trigger phrase test results (90%+ success rate)
Review criteria: follows naming conventions (no generic names like "format", "validate"), description includes trigger phrases, progressive disclosure used if >3,000 words, examples follow scenario format, troubleshooting addresses skill usage issues (not the issues the skill fixes).
Rule Deprecation Policy
When a rule needs to be changed or removed, follow this deprecation policy to give users time to migrate.
Deprecate a rule when:
- The rule validates a field that no longer exists in the official spec
- The rule's behavior is being merged into another rule
- The rule's validation logic needs a complete rewrite
- The rule is being split into multiple focused rules
Do not deprecate for minor fixes, bug fixes, or improved error messages — update in place.
Marking rules deprecated
Add a deprecated field to the rule's metadata:
deprecated: {
reason: 'This rule validates a field that was removed from the spec',
replacedBy: 'new-rule-name', // or an array: ['rule-1', 'rule-2']
deprecatedSince: '0.3.0',
removeInVersion: '1.0.0', // or null to retain indefinitely
url: 'https://claudelint.com/rules/category/new-rule-name',
}For simple cases, deprecated: true also works.
Deprecation lifecycle
- Deprecate in a minor version — add metadata, document in CHANGELOG.md under "Deprecated", add migration guide if there's a replacement
- Warn for 2+ minor versions — users see warnings,
claudelint check-deprecatedlists deprecated rules,claudelint migrateauto-updates configs for 1:1 replacements - Remove in next major version — document in CHANGELOG.md under "Breaking Changes"
Rules deprecated before 1.0.0 may be removed in 1.0.0 if they validate non-existent fields.
User-facing commands
claudelint check-deprecated— list all deprecated rules in configclaudelint check-all --no-deprecated-warnings— suppress deprecation warningsclaudelint check-all --error-on-deprecated— treat deprecated rules as errors (CI mode)claudelint migrate— auto-update config files (1:1 replacements)claudelint migrate --dry-run— preview changes without writing
Submitting Pull Requests
Push your changes to your fork:
bashgit push origin feature/your-feature-nameOpen a pull request on GitHub
Fill out the PR template (summary, type of change, test plan, checklist)
Ensure your PR title follows Conventional Commits format (e.g.,
feat: add new rule) — this is enforced by CIWait for CI checks to pass
Address any review feedback
Once approved, a maintainer will merge your PR
Reporting Issues
Bug reports should include: claudelint version (claudelint --version), Node.js version (node --version), operating system, steps to reproduce, expected vs actual behavior, and error messages or logs.
Feature requests should include: use case description, proposed solution, alternative solutions considered, and impact on existing functionality.
Documentation Website
The documentation site is built with VitePress and lives in the website/ directory. Rule documentation pages are auto-generated from source code metadata.
Running locally
# Start the dev server (generates rule docs + launches at localhost:5173)
npm run docs:dev
# Generate rule pages only (no dev server)
npm run docs:generate
# Production build
npm run docs:build
# Preview the production build
npm run docs:previewHow it works
- Rule docs are auto-generated from
meta.docsin each rule's TypeScript source - Running
npm run docs:generatereads all rules and produces markdown pages inwebsite/rules/ - A sidebar JSON file (
website/rules/_sidebar.json) is generated for navigation - Custom Vue components live in
website/.vitepress/theme/components/ - See the Development Overview for the full metadata schema
Editing documentation
- Rule docs: edit the
meta.docsproperty in the rule's source file, then runnpm run docs:generate - Guide/API pages: edit markdown files directly in
website/ - Components: edit Vue files in
website/.vitepress/theme/components/ - Navigation: edit sidebar config in
website/.vitepress/config.mts
Related docs
For contributing code: Architecture, Custom Rules
For users: Getting Started, Configuration, Rules Reference, Troubleshooting
Release Process
For maintainers only.
Verify constants are current:
bashnpm run check:constantsIf drift detected, fix it before proceeding. See Verifying Constants.
Run full validation:
bashnpm run validate:allChoose release type:
bashnpm run release:patch # Patch (bug fixes): 0.2.0 -> 0.2.1 npm run release:minor # Minor (new features): 0.2.0 -> 0.3.0 npm run release:major # Major (breaking changes): 0.2.0 -> 1.0.0 npm run release # Interactive (prompts for version)
The release command uses release-it and handles everything: lint, test, build, CHANGELOG generation, version bump, skill version sync, git tag, GitHub release, and npm publish.
Getting Help
License
By contributing to claudelint, you agree that your contributions will be licensed under the MIT License.