Claude-skill-registry commitlint
When setting up commit message validation for a project. When project has commitlint.config.js or .commitlintrc files. When configuring CI/CD to enforce commit format. When extracting commit rules for LLM prompt generation. When debugging commit message rejection errors.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/commitlint" ~/.claude/skills/majiayu000-claude-skill-registry-commitlint && rm -rf "$T"
skills/data/commitlint/SKILL.mdCommitlint
Validate commit messages against Conventional Commits format using commitlint configuration and rules.
When to Use This Skill
Use this skill when:
- Setting up commitlint for a repository
- Configuring commitlint rules and shareable configurations
- Integrating commitlint with pre-commit hooks or CI/CD pipelines
- Extracting rules from commitlint config to generate LLM prompts for commit message generation
- Validating commit messages programmatically
- Troubleshooting commitlint configuration or validation errors
- Understanding commitlint rule syntax and severity levels
- Detecting commitlint configuration files in a repository
Core Capabilities
Configuration Detection
Commitlint uses cosmiconfig to find configuration files in this priority order:
Dedicated config files:
.commitlintrc .commitlintrc.json .commitlintrc.yaml .commitlintrc.yml .commitlintrc.js .commitlintrc.cjs .commitlintrc.mjs .commitlintrc.ts .commitlintrc.cts commitlint.config.js commitlint.config.cjs commitlint.config.mjs commitlint.config.ts commitlint.config.cts
Package files:
withpackage.json
fieldcommitlint
(PNPM) withpackage.yaml
fieldcommitlint
Configuration Formats
JavaScript ES Modules (Recommended):
// commitlint.config.js or commitlint.config.mjs export default { extends: ['@commitlint/config-conventional'], };
TypeScript:
// commitlint.config.ts import type { UserConfig } from '@commitlint/types'; import { RuleConfigSeverity } from '@commitlint/types'; const config: UserConfig = { extends: ['@commitlint/config-conventional'], rules: { 'type-enum': [RuleConfigSeverity.Error, 'always', ['feat', 'fix', 'docs']], }, }; export default config;
JSON:
{ "extends": ["@commitlint/config-conventional"] }
YAML:
extends: - "@commitlint/config-conventional"
Rule Configuration
Rules are configured as arrays:
[level, applicability, value]
Severity Levels:
| Level | Meaning | TypeScript Enum |
|---|---|---|
| 0 | Disabled | |
| 1 | Warning | |
| 2 | Error | |
Applicability:
- Rule must match'always'
- Rule must not match'never'
Example rules:
rules: { // Error if type is not in enum 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert']], // Error if type is empty 'type-empty': [2, 'never'], // Error if subject is empty 'subject-empty': [2, 'never'], // Error if header exceeds 100 chars 'header-max-length': [2, 'always', 100], // Error if subject ends with period 'subject-full-stop': [2, 'never', '.'], // Warning if body doesn't have leading blank line 'body-leading-blank': [1, 'always'], }
Common Configurations
@commitlint/config-conventional
The most widely used shareable configuration. Default error-level rules:
| Rule | Configuration | Pass Example | Fail Example |
|---|---|---|---|
| | | |
| | | |
| | | |
| + | | |
| | | |
| , | | |
| | Short header | Header > 100 chars |
| (warning) | Blank line before body | No blank line |
| | Lines <= 100 chars | Line > 100 chars |
| (warning) | Blank line before footer | No blank line |
| | Lines <= 100 chars | Line > 100 chars |
Complete Configuration Schema
// commitlint.config.js export default { // Extend shareable configs (resolved via node resolution) extends: ['@commitlint/config-conventional'], // Parser preset for parsing commit messages parserPreset: 'conventional-changelog-atom', // Output formatter formatter: '@commitlint/format', // Custom rules (override inherited rules) rules: { 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore']], }, // Functions that return true to ignore specific commits // Merged with default ignores (merge commits, reverts, semver tags) ignores: [(commit) => commit.includes('WIP')], // Whether to use default ignore patterns // Default patterns: 'Merge pull request', 'Revert X', 'v1.2.3', etc. defaultIgnores: true, // Custom help URL shown on failure helpUrl: 'https://example.com/commit-guidelines', // Prompt configuration (for @commitlint/cz-commitlint) prompt: { messages: {}, questions: { type: { description: 'Select the type of change:', }, }, }, };
CLI Usage
Installation
# npm npm install -D @commitlint/cli @commitlint/config-conventional # yarn yarn add -D @commitlint/cli @commitlint/config-conventional # pnpm pnpm add -D @commitlint/cli @commitlint/config-conventional
Common Commands
# Lint the last commit npx commitlint --last # Lint a range of commits npx commitlint --from HEAD~5 # Lint from a specific commit npx commitlint --from abc1234 # Lint message from stdin echo "feat: add feature" | npx commitlint # Lint message from file npx commitlint < .git/COMMIT_EDITMSG # Lint with edit flag (reads .git/COMMIT_EDITMSG) npx commitlint --edit # Lint with custom config path npx commitlint --config ./custom-commitlint.config.js # Print resolved config npx commitlint --print-config # Strict mode (warnings become exit code 2) npx commitlint --last --strict
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success (no errors) |
| 1 | Lint errors found |
| 2 | Warnings found (strict mode only) |
| 3 | Errors found (strict mode) |
| 9 | Config file missing (with -g flag) |
Rule Reference
Type Rules
| Rule | Condition | Default Applicability |
|---|---|---|
| is found in value | |
| is in case | , |
| is empty | |
| has or less characters | , |
| has or more characters | , |
Subject Rules
| Rule | Condition | Default Applicability |
|---|---|---|
| is in case | |
| is empty | |
| ends with | , |
| has or less characters | , |
| has or more characters | , |
| has exclamation before | |
Scope Rules
| Rule | Condition | Default Applicability |
|---|---|---|
| is found in value | , |
| is in case | , |
| is empty | |
| has or less characters | , |
| has or more characters | , |
Header Rules
| Rule | Condition | Default Applicability |
|---|---|---|
| is in case | , |
| ends with | , |
| has or less characters | , |
| has or more characters | , |
| has no leading/trailing whitespace | |
Body Rules
| Rule | Condition | Default Applicability |
|---|---|---|
| begins with blank line | |
| is empty | |
| has or less characters | , |
| lines have or less characters (URLs excluded) | , |
| has or more characters | , |
| is in case | , |
| ends with | , |
Footer Rules
| Rule | Condition | Default Applicability |
|---|---|---|
| begins with blank line | |
| is empty | |
| has or less characters | , |
| lines have or less characters | , |
| has or more characters | , |
Case Values
For rules that check case (
*-case):
[ 'lower-case', // lowercase 'upper-case', // UPPERCASE 'camel-case', // camelCase 'kebab-case', // kebab-case 'pascal-case', // PascalCase 'sentence-case', // Sentence case 'snake-case', // snake_case 'start-case', // Start Case ]
Programmatic Usage
Load Configuration
import load from '@commitlint/load'; async function getCommitlintConfig() { const config = await load(); console.log(config.rules); return config; }
Validate Message
import load from '@commitlint/load'; import lint from '@commitlint/lint'; async function validateMessage(message) { const config = await load(); const result = await lint(message, config.rules); return { valid: result.valid, errors: result.errors, warnings: result.warnings, }; }
LLM Integration Patterns
Extract Rules for Prompt Generation
Generate LLM-friendly constraints from commitlint config:
def extract_rules_for_prompt(config: dict) -> str: """Extract commitlint rules into LLM-friendly format.""" rules = config.get('rules', {}) prompt_parts = [] # Extract type-enum if present if 'type-enum' in rules: level, applicability, types = rules['type-enum'] if level > 0 and applicability == 'always': prompt_parts.append(f"Allowed commit types: {', '.join(types)}") # Extract scope-enum if present if 'scope-enum' in rules: level, applicability, scopes = rules['scope-enum'] if level > 0 and applicability == 'always' and scopes: prompt_parts.append(f"Allowed scopes: {', '.join(scopes)}") # Extract header-max-length if 'header-max-length' in rules: level, applicability, length = rules['header-max-length'] if level > 0: prompt_parts.append(f"Header must be {length} characters or less") # Extract subject-case if 'subject-case' in rules: level, applicability, cases = rules['subject-case'] if level > 0 and applicability == 'never': prompt_parts.append(f"Subject must NOT use: {', '.join(cases)}") return '\n'.join(prompt_parts)
Validation Loop
import subprocess async def validate_with_commitlint(message: str, cwd: Path | None = None) -> tuple[bool, list[str]]: """ Validate commit message with commitlint. Args: message: The commit message to validate cwd: Working directory (defaults to current directory) Returns: Tuple of (is_valid, error_messages) """ result = subprocess.run( ['npx', 'commitlint'], input=message, capture_output=True, text=True, cwd=cwd, ) if result.returncode == 0: return True, [] # Parse errors from stderr errors = [line.strip() for line in result.stderr.split('\n') if line.strip()] return False, errors
Validation loop pattern:
- LLM generates commit message based on diff and rules
- Run commitlint on generated message
- If validation fails, feed errors back to LLM with context
- Retry (max 3 times by default)
- Return final message (valid or best effort after retries)
Common Issues
Node v24 ESM issues:
Use
.mjs extension for ES modules config, or add "type": "module" to package.json
Missing extends:
Config without
extends or rules fails with "Please add rules" error. Include at least one:
export default { extends: ['@commitlint/config-conventional'], };
Empty config error:
Config file must have at least
extends or rules defined.
Scope enum empty array:
scope-enum with [] passes all scopes. Use specific array to restrict:
rules: { 'scope-enum': [2, 'always', ['api', 'ui', 'docs']], }
Subject case trap:
@commitlint/config-conventional uses never with specific cases, meaning those cases are forbidden (not required):
// This forbids sentence-case, start-case, pascal-case, upper-case 'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']]
Pre-commit Integration
For pre-commit hook integration with commitlint, activate the pre-commit skill:
Skill(command: "pre-commit")
Conventional Commits Reference
For Conventional Commits format specification and examples, activate the conventional-commits skill:
Skill(command: "conventional-commits")
References
Official Documentation
- Commitlint Official Site (accessed 2025-01-15)
- Configuration Reference (accessed 2025-01-15)
- Rules Reference (accessed 2025-01-15)
- CLI Reference (accessed 2025-01-15)
- Getting Started Guide (accessed 2025-01-15)
- GitHub Repository (accessed 2025-01-15)
Related Specifications
- Conventional Commits - Commit message format specification
- Cosmiconfig - Configuration file discovery mechanism
Source Attribution
This skill was created from reference documentation at
the commit-polish repository (2025-12-01)