This document provides comprehensive information about creating and configuring rules in Commit Coach.
- Rule Configuration
- Available Variables
- Built-in Rules
- Custom Rule Examples
- Rule Conditions Reference
- Best Practices
Rules are defined in your .commit-coach.yml configuration file. Each rule has the following structure:
rules:
- id: unique-rule-id
enabled: true
severity: error | warning | info | suggestion
conditions: ["condition1", "condition2"]
message: "Human-readable message"
metadata:
# Optional additional data| Property | Type | Required | Description |
|---|---|---|---|
id |
string | ✅ | Unique identifier for the rule |
enabled |
boolean | ✅ | Whether the rule is active |
severity |
string | ✅ | Rule severity level |
conditions |
array | ✅ | JavaScript expressions to evaluate |
message |
string | ✅ | Message shown when rule triggers |
metadata |
object | ❌ | Additional rule configuration |
error: Critical issues that should block commitswarning: Important issues that should be addressedinfo: Informational insightssuggestion: Helpful recommendations
When writing rule conditions, you have access to the following variables:
| Variable | Type | Description |
|---|---|---|
hash |
string | Commit hash |
message |
string | Commit message |
author |
string | Commit author |
date |
Date | Commit date |
messageLength |
number | Length of commit message |
| Variable | Type | Description |
|---|---|---|
files |
array | Array of changed files |
totalLines |
number | Total lines added + deleted |
filesChanged |
number | Number of files changed |
testFilesChanged |
number | Number of test files changed |
documentationFilesChanged |
number | Number of documentation files changed |
| Variable | Type | Description |
|---|---|---|
testFilesAdded |
array | Test files that were added |
testFilesModified |
array | Test files that were modified |
sourceFilesWithoutTests |
array | Source files without corresponding tests |
testCoverageRatio |
number | Ratio of source files with tests (0-1) |
| Variable | Type | Description |
|---|---|---|
addedApis |
array | Public APIs that were added |
removedApis |
array | Public APIs that were removed |
modifiedApis |
array | Public APIs that were modified |
| Variable | Type | Description |
|---|---|---|
hasNewFeatures |
boolean | Whether new features were added |
hasDocUpdates |
boolean | Whether documentation was updated |
documentationChanges |
array | Documentation files that changed |
| Variable | Type | Description |
|---|---|---|
featureFlags |
array | Feature flags that were added/modified |
| Variable | Type | Description |
|---|---|---|
breakingChanges |
array | Breaking changes detected |
| Variable | Type | Description |
|---|---|---|
hasTodos |
boolean | Whether TODO/FIXME comments were found |
diff |
string | Full diff content |
Commit Coach comes with several built-in rules that you can enable/disable:
- id: missing-tests
enabled: true
severity: warning
conditions: ["sourceFilesWithoutTests.length > 0"]
message: "Consider adding tests for new/modified source files"- id: public-api-removed
enabled: true
severity: warning
conditions: ["removedApis.length > 0"]
message: "Public API removed - check for downstream dependencies"
- id: public-api-added
enabled: true
severity: info
conditions: ["addedApis.length > 0"]
message: "New public APIs added - consider documenting them"- id: large-commit
enabled: true
severity: info
conditions: ["totalLines > 200"]
message: "Large commit - consider breaking into smaller changes"
- id: short-commit-message
enabled: true
severity: suggestion
conditions: ["messageLength < 10"]
message: "Consider adding more context to commit message"- id: missing-documentation
enabled: true
severity: suggestion
conditions: ["hasNewFeatures && !hasDocUpdates"]
message: "Consider updating documentation for new features"- id: feature-flags-added
enabled: true
severity: suggestion
conditions: ["featureFlags.length > 0"]
message: "Document new feature flags and their purpose"- id: breaking-changes
enabled: true
severity: error
conditions: ["breakingChanges.length > 0"]
message: "Breaking changes detected - update version and changelog"- id: hardcoded-secrets
enabled: true
severity: error
conditions: ["diff.match(/['\"](sk-|pk_|ghp_|gho_|ghu_|ghs_|ghr_|AKIA|ya29\.)/)"]
message: "Potential hardcoded secret detected - use environment variables instead"
- id: sql-injection-risk
enabled: true
severity: error
conditions: ["diff.match(/query.*\\$\\{.*\\}|query.*\\+.*\\+/)"]
message: "Potential SQL injection risk detected - use parameterized queries"
- id: xss-risk
enabled: true
severity: error
conditions: ["diff.includes('innerHTML') && !diff.includes('textContent')"]
message: "Potential XSS risk - use textContent instead of innerHTML"- id: debug-code
enabled: true
severity: warning
conditions: ["diff.includes('console.log') || diff.includes('debugger') || diff.includes('alert(')"]
message: "Debug code detected - remove before merging"
- id: large-file-addition
enabled: true
severity: warning
conditions: ["files.some(f => f.status === 'added' && f.additions > 1000)"]
message: "Large file(s) added - consider if these should be in version control"
- id: dependency-update
enabled: true
severity: info
conditions: ["files.some(f => f.path.includes('package.json') || f.path.includes('yarn.lock') || f.path.includes('pnpm-lock.yaml'))"]
message: "Dependencies updated - run tests and check for breaking changes"
- id: missing-error-handling
enabled: true
severity: warning
conditions: ["diff.includes('async ') && !diff.includes('try') && !diff.includes('catch')"]
message: "Async function added without error handling - consider try/catch blocks"
- id: typescript-any-type
enabled: true
severity: warning
conditions: ["files.some(f => f.path.endsWith('.ts')) && diff.includes(': any')"]
message: "Avoid using 'any' type - use specific types for better type safety"
- id: todo-comments
enabled: true
severity: info
conditions: ["hasTodos"]
message: "TODO/FIXME comments found - track these items"- id: merge-conflict-markers
enabled: true
severity: error
conditions: ["diff.includes('<<<<<<<') || diff.includes('>>>>>>>') || diff.includes('=======')"]
message: "Merge conflict markers detected - resolve conflicts before committing"
- id: binary-file-addition
enabled: true
severity: warning
conditions: ["files.some(f => f.status === 'added' && /\.(jpg|jpeg|png|gif|pdf|zip|exe|dll|bin|so|dylib)$/i.test(f.path))"]
message: "Binary file(s) added - ensure they're necessary and properly sized"
- id: config-file-changes
enabled: true
severity: info
conditions: ["files.some(f => f.path.includes('config') || f.path.includes('.env') || f.path.includes('settings'))"]
message: "Configuration files changed - verify all environments are updated"# Detect potential password exposure
- id: password-exposure
enabled: true
severity: error
conditions: ["diff.toLowerCase().includes('password')"]
message: "Potential password exposure detected - review carefully"
# Detect hardcoded secrets
- id: hardcoded-secrets
enabled: true
severity: error
conditions: ["diff.match(/['\"](sk-|pk_|ghp_|gho_|ghu_|ghs_|ghr_)/)"]
message: "Potential hardcoded secret detected"# Detect large file additions
- id: large-file-addition
enabled: true
severity: warning
conditions: ["files.some(f => f.status === 'added' && f.additions > 1000)"]
message: "Large file added - consider if this should be in version control"
# Detect potential performance issues
- id: performance-concerns
enabled: true
severity: warning
conditions: ["diff.includes('console.log') || diff.includes('debugger')"]
message: "Debug code detected - remove before merging"# Enforce specific file extensions
- id: wrong-file-extension
enabled: true
severity: warning
conditions: ["files.some(f => f.path.endsWith('.js') && f.diff.includes('import'))"]
message: "Consider using .mjs or .ts extension for ES modules"
# Detect missing semicolons
- id: missing-semicolons
enabled: true
severity: suggestion
conditions: ["diff.match(/^\+.*[^;{}]\s*$/m)"]
message: "Consider adding semicolons for consistency"# Enforce specific patterns for your project
- id: api-version-check
enabled: true
severity: warning
conditions: ["files.some(f => f.path.includes('api/') && !f.diff.includes('version'))"]
message: "API changes should include version updates"
# Check for required files
- id: missing-changelog
enabled: true
severity: warning
conditions: ["hasNewFeatures && !files.some(f => f.path.includes('CHANGELOG'))"]
message: "New features should be documented in CHANGELOG"// Contains text
"message.includes('fix')"
"diff.includes('TODO')"
// Regex matching
"message.match(/^feat:/)"
"diff.match(/console\.log/)"
// String length
"message.length > 50"
"message.length < 10"// Array length
"files.length > 5"
"sourceFilesWithoutTests.length > 0"
// Array filtering
"files.filter(f => f.status === 'added').length > 3"
"files.some(f => f.path.includes('test'))"
// Array includes
"files.some(f => f.path.endsWith('.md'))"// Line counts
"totalLines > 200"
"totalLines < 10"
// File counts
"filesChanged > 5"
"testFilesChanged === 0"
// Ratios
"testCoverageRatio < 0.8"// AND operations
"hasNewFeatures && !hasDocUpdates"
"totalLines > 100 && filesChanged > 3"
// OR operations
"message.includes('fix') || message.includes('bug')"
// NOT operations
"!files.some(f => f.path.includes('test'))"// File extensions
"files.some(f => f.path.endsWith('.js'))"
"files.some(f => f.path.endsWith('.test.js'))"
// Directory patterns
"files.some(f => f.path.startsWith('src/'))"
"files.some(f => f.path.includes('/api/'))"
// File patterns
"files.some(f => f.path.includes('config'))"Begin with basic conditions and gradually add complexity:
# Start with this
- id: large-commit
conditions: ["totalLines > 200"]
# Then refine
- id: large-commit
conditions: ["totalLines > 200 && filesChanged > 3"]- Error: Blocking issues (security, breaking changes)
- Warning: Important issues (missing tests, large commits)
- Info: Informational (new features, API changes)
- Suggestion: Helpful tips (documentation, code style)
# Good
message: "Large commit detected - consider breaking into smaller changes"
# Better
message: "Commit has 250+ lines - consider splitting into focused commits for easier review"- id: large-commit
conditions: ["totalLines > threshold"]
message: "Large commit detected"
metadata:
threshold: 200
skipPatterns: ["*.md", "*.json"]Use the demo repository to test your rules:
# Test with demo repo
cd commit-coach-test-repo
commit-coach analyze --output reportAdd comments to explain complex rules:
rules:
# Security: Detect potential API key exposure
- id: api-key-exposure
enabled: true
severity: error
conditions: ["diff.match(/['\"](sk-|pk_|ghp_)/)"]
message: "Potential API key detected - use environment variables instead"- Avoid complex regex patterns in frequently triggered rules
- Use specific conditions to reduce false positives
- Consider using
skipOnSmallChangesfor expensive rules
# Only warn about missing tests for significant changes
- id: missing-tests-significant
enabled: true
severity: warning
conditions: [
"sourceFilesWithoutTests.length > 0",
"totalLines > 50",
"!files.some(f => f.path.includes('migration'))"
]
message: "Significant changes without tests - consider adding test coverage"# Different rules for different file types
- id: js-file-tests
enabled: true
severity: warning
conditions: [
"files.some(f => f.path.endsWith('.js') && f.status !== 'deleted')",
"!files.some(f => f.path.endsWith('.test.js'))"
]
message: "JavaScript files should have corresponding test files"
- id: ts-file-tests
enabled: true
severity: warning
conditions: [
"files.some(f => f.path.endsWith('.ts') && f.status !== 'deleted')",
"!files.some(f => f.path.endsWith('.test.ts'))"
]
message: "TypeScript files should have corresponding test files"# Check for specific patterns that indicate external tool usage
- id: dependency-update
enabled: true
severity: info
conditions: ["files.some(f => f.path.includes('package.json') || f.path.includes('yarn.lock'))"]
message: "Dependencies updated - run tests and check for breaking changes"- Rule not triggering: Check that conditions are correctly formatted
- False positives: Make conditions more specific
- Performance issues: Simplify complex regex patterns
- Syntax errors: Validate JavaScript expressions
Use the report output format to see what variables are available:
commit-coach analyze --output report > debug.jsonThis will show you the exact values of all variables for debugging your conditions.
Found a bug in the rules system or want to add new built-in rules? Please open an issue or submit a pull request!
For more information, see: