Skip to content
This repository was archived by the owner on Jul 7, 2026. It is now read-only.

Latest commit

 

History

History
710 lines (504 loc) · 19.3 KB

File metadata and controls

710 lines (504 loc) · 19.3 KB

Contributing to claudelint

Thank you for your interest in contributing to claudelint! This document provides guidelines for contributing to the project.

Quick Start for Contributors

Want to add a validation rule? See the Rule Development Guide - this is our detailed technical guide for writing rules.

Want to contribute in other ways? Keep reading this document for general contribution guidelines (git workflow, testing, code style, etc.).

Code of Conduct

This project adheres to a Code of Conduct that all contributors are expected to follow. Please read CODE_OF_CONDUCT.md before contributing.

Getting Started

Prerequisites

  • Node.js 20.0.0 or higher
  • npm or yarn
  • Git

Setup Development Environment

  1. Fork the repository on GitHub

  2. Clone your fork locally:

    git clone https://github.com/YOUR_USERNAME/claudelint.git
    cd claudelint
  3. Install dependencies:

    npm install
  4. Build the project:

    npm run build
  5. Run tests to verify setup:

    npm test
  6. Set up git hooks (runs automatically on install):

    npm run setup:hooks

Development Workflow

Making Changes

  1. Create a new branch for your feature or fix:

    git checkout -b feature/your-feature-name
  2. Make your changes following the code style guidelines below

  3. Add or update tests for your changes

  4. Run the full test suite:

    npm test
  5. Run linting and formatting:

    npm run lint
    npm run format:check
  6. Run validation on the project itself (dogfooding):

    npm run validate

See the CLI Reference for complete command reference.

Code Style Guidelines

  • Follow TypeScript best practices
  • Use unknown instead of any for 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 Guidelines

IMPORTANT: Library code MUST NOT use console directly.

See the Internals Guide for full details.

Use DiagnosticCollector instead:

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'
    );
  }
}

Why:

  • Makes library testable (no console spam during tests)
  • Allows programmatic usage (consumers control output)
  • Provides structured diagnostics with source tracking
  • Follows industry standards (ESLint, TypeScript, Webpack)

Where console IS allowed:

  • CLI layer only: src/cli/utils/logger.ts
  • Output formatting: src/utils/reporting/
  • Script utilities: scripts/util/logger.ts

Enforcement:

Library code is checked in CI and pre-commit hooks:

npm run check:logger-usage

Testing Guidelines

  • Write unit tests for all new validators
  • Add integration tests for CLI commands
  • Aim for 80%+ code coverage
  • Test error conditions and edge cases
  • Use descriptive test names

Verifying Constants (Maintainers Only)

Constants like ToolNames and ModelNames must stay synchronized with Claude Code. We verify these by querying the Claude Code CLI.

Requirements:

When to verify:

  • Before releases (required)
  • After Claude Code updates
  • Every 90 days (recommended)
  • When users report validation issues

How to verify:

# Verify all constants
npm run check:constants

# Or individually
npm run check:tool-names
npm run check:model-names

If drift detected:

  1. Review the output to see missing/extra values
  2. Cross-check with official docs:
  3. Update src/schemas/constants.ts if needed
  4. Run tests: npm test
  5. Re-verify: npm run check:constants
  6. Re-verify: npm run check:constants

Note: Regular contributors don't need Claude CLI installed. This is only for maintainers doing releases.

Commit Message Guidelines

Follow conventional commit format:

type(scope): subject

body (optional)

footer (optional)

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • test: Test changes
  • refactor: Code refactoring
  • chore: Build/tooling changes
  • perf: Performance improvements

Examples:

  • feat(validators): add MCP server validator
  • fix(cli): handle missing config file gracefully
  • docs(readme): update installation instructions

Project Structure

claudelint/
├── src/
│   ├── validators/      # Validator implementations
│   ├── utils/           # Utility functions
│   └── cli.ts           # CLI entry point
├── tests/
│   ├── validators/      # Validator tests
│   ├── utils/           # Utility tests
│   └── integration/     # Integration tests
├── docs/projects/       # Internal project tracking
├── website/             # Documentation site (claudelint.com)
├── .claude/             # Claude Code plugin files
│   ├── skills/          # Plugin skills
│   └── hooks/           # Plugin hooks
└── scripts/             # Build and automation scripts

Adding Validation Rules

claudelint uses a rule-based architecture (similar to ESLint). Contributors write individual validation rules, not validators.

See the comprehensive Rule Development Guide for:

  • Understanding rules and architecture
  • Writing custom rules (external developers)
  • Contributing built-in rules (contributors)
  • Rule structure and metadata
  • Validation logic patterns
  • Testing strategies
  • Auto-fix capabilities
  • Best practices

Quick checklist:

  1. ✓ Create rule file in src/rules/{category}/{rule-id}.ts
  2. ✓ Define rule metadata (id, name, description, category, severity)
  3. ✓ Implement validate() function
  4. ✓ Add rule to category index in src/rules/{category}/index.ts
  5. ✓ Write unit tests in tests/rules/{category}/{rule-id}.test.ts
  6. ✓ Run npm run docs:generate to generate rule documentation
  7. ✓ Test the rule with npm test
  8. ✓ Run validation on project: npm run validate

Contributing Skills

Skills are interactive capabilities that allow Claude to help users validate, optimize, and fix their Claude Code projects through natural conversation.

Skill Quality Standards

All skills must follow Anthropic's best practices for skill development.

Required for all skills:

  1. Description with trigger phrases - Must include what, when, triggers, and capabilities
  2. Proper naming - No single-word verbs, use suffixes like -all, -cc, -cc-md
  3. Automated validation - Must pass claudelint validate-skills
  4. Manual testing - Trigger phrases tested, functionality verified

Required for complex skills:

  1. Examples section - Scenario-based examples (User says → Actions → Result)
  2. Troubleshooting section - For skills with >3 scripts or that edit files

Recommended:

  1. Progressive disclosure - For skills with >3,000 words, use references/ directory

Submitting a New Skill

Before submitting a PR:

  1. Validate structure:

    claudelint validate-skills .claude/skills/your-skill
  2. Test trigger phrases:

    • Start fresh Claude session
    • Test phrases from description field
    • Verify 90%+ trigger success rate
  3. Test functionality:

    • Valid inputs work correctly
    • Invalid inputs detected properly
    • Edge cases handled
  4. 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-skills passes
  • 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 issues skill fixes)

See the Contributing Guide for detailed requirements.

Rule Deprecation Policy

When a rule needs to be changed or removed, follow this deprecation policy to give users time to migrate their configurations.

When to Deprecate Rules

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 is fundamentally flawed and 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 - these should be updated in place.

How to Mark a Rule as Deprecated

Add a deprecated field to the rule's metadata. Use boolean for simple cases, or DeprecationInfo object for full metadata:

// Simple deprecation (boolean)
export const rule: Rule = {
  meta: {
    id: 'old-rule-name',
    name: 'Old Rule Name',
    description: 'Description',
    category: 'Category',
    severity: 'warn',
    fixable: false,
    deprecated: true,  // Simple boolean
    since: '0.1.0',
  },
  validate: async (context) => {
    // Rule still executes but shows deprecation warning
  },
};

// Full deprecation metadata (recommended)
export const rule: Rule = {
  meta: {
    id: 'old-rule-name',
    name: 'Old Rule Name',
    description: 'Description',
    category: 'Category',
    severity: 'warn',
    fixable: false,
    deprecated: {
      reason: 'This rule validates a field that was removed from the spec',
      replacedBy: 'new-rule-name',        // Single replacement
      // OR: replacedBy: ['rule-1', 'rule-2'],  // Multiple replacements
      deprecatedSince: '0.3.0',
      removeInVersion: '1.0.0',           // When it will be removed
      // OR: removeInVersion: null,       // Retained indefinitely
      url: 'https://claudelint.com/guide/troubleshooting',
    },
    since: '0.1.0',
  },
  validate: async (context) => {
    // Rule still executes but shows deprecation warning
  },
};

Deprecation Lifecycle

Follow this timeline for deprecating rules:

  1. Deprecate (Minor Version)

    • Add deprecated metadata to the rule
    • Rule still executes normally but shows warnings
    • Document in CHANGELOG.md under "Deprecated" section
    • Add migration guide (if replacedBy exists)
  2. Warn (2+ Minor Versions)

    • Keep the rule for at least 2 minor versions after deprecation
    • Users see warnings when they use deprecated rules
    • claudelint check-deprecated shows all deprecated rules in config
    • claudelint migrate can auto-update configs (1:1 replacements only)
  3. Remove (Next Major Version)

    • Remove the rule implementation in next major version (e.g., 1.0.0)
    • Document in CHANGELOG.md under "Breaking Changes"
    • Add to migration guide for major version

Exception: Rules deprecated before 1.0.0 may be removed in 1.0.0 if they validate non-existent fields.

Replacement Scenarios

1:1 Replacement (Single Rule)

deprecated: {
  reason: 'Field was renamed in official spec',
  replacedBy: 'new-rule-name',
}

Users: Run claudelint migrate to auto-update configs.

1:Many Replacement (Multiple Rules)

deprecated: {
  reason: 'Rule was split into multiple focused rules',
  replacedBy: ['rule-1', 'rule-2', 'rule-3'],
}

Users: Must manually update configs. claudelint migrate will warn about this.

No Replacement (Removal)

deprecated: {
  reason: 'Field no longer exists in official spec',
  // No replacedBy field
}

Users: Remove rule from config. claudelint migrate will suggest removal.

Retained Indefinitely

deprecated: {
  reason: 'Deprecated but kept for backward compatibility',
  removeInVersion: null,  // Will never be removed
}

Users: Can keep using but should migrate to new approach when possible.

User-Facing Commands

Users can manage deprecated rules with these commands:

  • claudelint check-deprecated - List all deprecated rules in config
  • claudelint check-all --no-deprecated-warnings - Suppress deprecation warnings
  • claudelint 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

Testing Deprecated Rules

Continue testing deprecated rules until removal:

describe('old-rule-name (deprecated)', () => {
  it('should still validate correctly', async () => {
    // Test the rule's core functionality
  });

  it('should be marked as deprecated', () => {
    const rule = RuleRegistry.getRule('old-rule-name');
    expect(isRuleDeprecated(rule)).toBe(true);
  });

  it('should have replacement info', () => {
    const rule = RuleRegistry.getRule('old-rule-name');
    const info = getDeprecationInfo(rule);
    expect(info?.replacedBy).toBeDefined();
  });
});

Submitting Pull Requests

  1. Push your changes to your fork:

    git push origin feature/your-feature-name
  2. Open a pull request on GitHub

  3. Fill out the PR template (summary, type of change, test plan, checklist)

  4. Ensure your PR title follows Conventional Commits format (e.g., feat: add new rule) — this is enforced by CI

  5. Wait for CI checks to pass

  6. Address any review feedback

  7. Once approved, a maintainer will merge your PR

Reporting Issues

Bug Reports

Include:

  • claudelint version (claudelint --version)
  • Node.js version (node --version)
  • Operating system
  • Steps to reproduce
  • Expected vs actual behavior
  • Error messages or logs

Feature Requests

Include:

  • Use case description
  • Proposed solution
  • Alternative solutions considered
  • Impact on existing functionality

Public API Changes

If your PR changes the public API (adds/removes/modifies exports from src/index.ts or types in src/api/):

  1. Update the API report:

    npm run check:api-report:update

    This regenerates etc/claude-code-lint.api.md. Commit the updated report alongside your code changes.

  2. Update the snapshot test — run npm test -- -u --testPathPatterns=api-surface if you intentionally added or removed exports.

  3. Add JSDoc comments to any new public exports (enforced by ESLint).

  4. Update type assertions in src/index.test-d.ts if you changed function signatures.

  5. Update documentation pages in website/api/ to reflect the change.

CI will fail if the API report is stale, the export snapshot doesn't match, or public exports lack JSDoc.

Documentation

  • Update README.md for user-facing changes
  • All documentation lives at claudelint.com (source in website/)
  • Add JSDoc comments for API changes
  • Include code examples where helpful

Key Documentation

For contributing code:

For users:

Release Process

(For maintainers only)

Pre-release checklist:

  1. Verify constants are current:

    npm run check:constants

    If drift detected, fix it before proceeding. See Verifying Constants section.

  2. Run full validation:

    npm run validate:all
  3. Choose release type:

    # Patch (bug fixes): 0.2.0 -> 0.2.1
    npm run release:patch
    
    # Minor (new features): 0.2.0 -> 0.3.0
    npm run release:minor
    
    # Major (breaking changes): 0.2.0 -> 1.0.0
    npm run release:major
    
    # Or interactive (prompts for version):
    npm run release
  4. What npm run release does:

    • Runs lint, test, and build
    • Analyzes commits since last release
    • Auto-generates CHANGELOG section
    • Bumps version in package.json
    • Syncs skill versions
    • Creates git commit and tag
    • Pushes to GitHub
    • Creates GitHub release

    npm publishing happens automatically via CI when the v* tag is pushed, using OIDC trusted publishing with provenance attestation.

Note: The npm run release command uses release-it and handles all steps automatically. Manual version/changelog updates are not needed.

CI Integration (Optional)

Constants Verification in CI

You can optionally run constants verification in CI, but be aware of trade-offs:

Trade-offs:

  • Pro: Catches drift automatically on every PR
  • Con: Costs tokens (~$0.01 per run, adds up)
  • Con: Requires ANTHROPIC_API_KEY in CI secrets
  • Con: Adds ~30 seconds to CI runs

Example GitHub Actions workflow:

# .github/workflows/verify-constants.yml (optional)
name: Verify Constants

on:
  pull_request:
  schedule:
    # Run weekly on Mondays at 9am UTC
    - cron: '0 9 * * 1'

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: '20'
      - run: npm ci

      # Install Claude CLI (example for Linux)
      - name: Install Claude CLI
        run: |
          curl -fsSL https://code.claude.com/install.sh | sh
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Verify Constants
        run: npm run check:constants
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Recommendation: Don't enable this initially. Manual verification before releases is sufficient for most projects.

Getting Help

License

By contributing to claudelint, you agree that your contributions will be licensed under the MIT License.