Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Atomic commits, PR size limits, commit thresholds, stacked PRs
.claude/skills/kunanonj-commit-hygiene/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 206% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 120% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 222% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 270% | 0% |
Purpose: Keep commits atomic, PRs reviewable, and git history clean. Advise when it's time to commit before changes become too large.
┌─────────────────────────────────────────────────────────────────┐
│ ATOMIC COMMITS │
│ ───────────────────────────────────────────────────────────── │
│ One logical change per commit. │
│ Each commit should be self-contained and deployable. │
│ If you need "and" to describe it, split it. │
├─────────────────────────────────────────────────────────────────┤
│ SMALL PRS WIN │
│ ───────────────────────────────────────────────────────────── │
│ < 400 lines changed = reviewed in < 1 hour │
│ > 1000 lines = likely rubber-stamped or abandoned │
│ Smaller PRs = faster reviews, fewer bugs, easier reverts │
├─────────────────────────────────────────────────────────────────┤
│ COMMIT EARLY, COMMIT OFTEN │
│ ───────────────────────────────────────────────────────────── │
│ Working code? Commit it. │
│ Test passing? Commit it. │
│ Don't wait for "done" - commit at every stable point. │
└─────────────────────────────────────────────────────────────────┘| Metric | Yellow Zone | Red Zone | Action | |--------|-------------|----------|--------| | Files changed | 5-10 files | > 10 files | Commit NOW | | Lines added | 150-300 lines | > 300 lines | Commit NOW | | Lines deleted | 100-200 lines | > 200 lines | Commit NOW | | Total changes | 250-400 lines | > 400 lines | Commit NOW | | Time since last commit | 30-60 min | > 60 min | Consider committing |
┌─────────────────────────────────────────────────────────────────┐
│ IDEAL COMMIT │
│ ───────────────────────────────────────────────────────────── │
│ Files: 1-5 │
│ Lines: 50-200 total changes │
│ Scope: Single logical unit of work │
│ Message: Describes ONE thing │
└─────────────────────────────────────────────────────────────────┘bash# See what's changed (staged + unstaged) git status --short # Count files and lines changed git diff --stat git diff --cached --stat # Staged only # Get totals git diff --shortstat # Example output: 8 files changed, 245 insertions(+), 32 deletions(-)
bash# Full diff summary with file names git diff --stat HEAD # Just the numbers git diff --numstat HEAD | awk '{add+=$1; del+=$2} END {print "+"add" -"del" total:"add+del}' # Files changed count git status --porcelain | wc -l
bash#!/bin/bash # scripts/check-commit-size.sh # Thresholds MAX_FILES=10 MAX_LINES=400 WARN_FILES=5 WARN_LINES=200 # Get stats FILES=$(git status --porcelain | wc -l | tr -d ' ') STATS=$(git diff --shortstat HEAD 2>/dev/null) INSERTIONS=$(echo "$STATS" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0) DELETIONS=$(echo "$STATS" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0) TOTAL=$((INSERTIONS + DELETIONS)) echo "📊 Current changes: $FILES files, +$INSERTIONS -$DELETIONS ($TOTAL total lines)" # Check thresholds if [ "$FILES" -gt "$MAX_FILES" ] || [ "$TOTAL" -gt "$MAX_LINES" ]; then echo "🔴 RED ZONE: Commit immediately! Changes are too large." echo " Consider splitting into multiple commits." exit 1 elif [ "$FILES" -gt "$WARN_FILES" ] || [ "$TOTAL" -gt "$WARN_LINES" ]; then echo "🟡 WARNING: Changes getting large. Commit soon." exit 0 else echo "🟢 OK: Changes are within healthy limits." exit 0 fi
| Trigger | Example | |---------|---------| | Test passes | Just got a test green → commit | | Feature complete | Finished a function → commit | | Refactor done | Renamed variable across files → commit | | Bug fixed | Fixed the issue → commit | | Before switching context | About to work on something else → commit | | Clean compile | Code compiles/lints clean → commit | | Threshold hit | > 5 files or > 200 lines → commit |
✅ "Add email validation to signup form"
- 3 files: validator.ts, signup.tsx, signup.test.ts
- 120 lines changed
- Single purpose: email validation
✅ "Fix null pointer in user lookup"
- 2 files: userService.ts, userService.test.ts
- 25 lines changed
- Single purpose: fix one bug
✅ "Refactor: Extract PaymentProcessor class"
- 4 files: payment.ts → paymentProcessor.ts + types
- 180 lines changed
- Single purpose: refactoring❌ "Add authentication, fix bugs, update styles"
- 25 files changed
- 800 lines changed
- Multiple purposes mixed
❌ "WIP"
- Unknown scope
- No clear purpose
- Hard to review/revert
❌ "Updates"
- 15 files changed
- Mix of features, fixes, refactors
- Impossible to review properlyInstead of one commit with:
- API endpoint + database migration + frontend + tests
Split into:
1. "Add users table migration"
2. "Add User model and repository"
3. "Add GET /users endpoint"
4. "Add UserList component"
5. "Add integration tests for user flow"Instead of one commit with:
- All CRUD operations for users
Split into:
1. "Add create user functionality"
2. "Add read user functionality"
3. "Add update user functionality"
4. "Add delete user functionality"Instead of:
- Feature + refactoring mixed
Split into:
1. "Refactor: Extract validation helpers" (no behavior change)
2. "Add email validation using new helpers" (new feature)Instead of:
- Safe changes + risky changes together
Split into:
1. "Update dependencies" (safe, isolated)
2. "Migrate to new API version" (risky, separate)| Metric | Optimal | Acceptable | Too Large | |--------|---------|------------|-----------| | Files | 1-10 | 10-20 | > 20 | | Lines changed | 50-200 | 200-400 | > 400 | | Commits | 1-5 | 5-10 | > 10 | | Review time | < 30 min | 30-60 min | > 60 min |
┌─────────────────────────────────────────────────────────────────┐
│ RESEARCH FINDINGS (Google, Microsoft studies) │
│ ───────────────────────────────────────────────────────────── │
│ PRs < 200 lines: 15% defect rate │
│ PRs 200-400 lines: 23% defect rate │
│ PRs > 400 lines: 40%+ defect rate │
│ │
│ Review quality drops sharply after 200-400 lines. │
│ Large PRs get "LGTM" rubber stamps, not real reviews. │
└─────────────────────────────────────────────────────────────────┘bash# Check PR size before creating git diff main --stat git diff main --shortstat # If too large, consider: # 1. Split into multiple PRs (stacked PRs) # 2. Create feature flag and merge incrementally # 3. Use draft PR for early feedback
<type>: <description> (50 chars max)
[optional body - wrap at 72 chars]
[optional footer]| Type | Use For | |------|---------| | feat | New feature | | fix | Bug fix | | refactor | Code change that neither fixes nor adds | | test | Adding/updating tests | | docs | Documentation only | | style | Formatting, no code change | | chore | Build, config, dependencies |
feat: Add email validation to signup form
fix: Prevent null pointer in user lookup
refactor: Extract PaymentProcessor class
test: Add integration tests for checkout flow
chore: Update dependencies to latest versionsbash#!/bin/bash # .git/hooks/pre-commit MAX_LINES=400 MAX_FILES=15 FILES=$(git diff --cached --name-only | wc -l | tr -d ' ') STATS=$(git diff --cached --shortstat) INSERTIONS=$(echo "$STATS" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0) DELETIONS=$(echo "$STATS" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0) TOTAL=$((INSERTIONS + DELETIONS)) if [ "$TOTAL" -gt "$MAX_LINES" ]; then echo "❌ Commit too large: $TOTAL lines (max: $MAX_LINES)" echo " Consider splitting into smaller commits." echo " Use 'git add -p' for partial staging." exit 1 fi if [ "$FILES" -gt "$MAX_FILES" ]; then echo "❌ Too many files: $FILES (max: $MAX_FILES)" echo " Consider splitting into smaller commits." exit 1 fi echo "✅ Commit size OK: $FILES files, $TOTAL lines"
bash# Stage specific hunks interactively git add -p # Stage specific files git add path/to/specific/file.ts # Stage with preview git add -N file.ts # Intent to add git diff # See what would be added git add file.ts # Actually add
bash# Unstage everything git reset HEAD # Unstage specific files git reset HEAD path/to/file.ts # Stage just what you need for THIS commit git add -p
Claude should run this check after every significant change:
bash# Quick status git diff --shortstat HEAD
Thresholds for Claude to advise committing:
| Condition | Claude Action | |-----------|---------------| | > 5 files changed | Suggest: "Consider committing current changes" | | > 200 lines changed | Suggest: "Changes are getting large, commit recommended" | | > 10 files OR > 400 lines | Warn: "⚠️ Commit now before changes become unmanageable" | | Test just passed | Suggest: "Good checkpoint - commit these passing tests" | | Refactoring complete | Suggest: "Refactoring done - commit before adding features" |
📊 Status: 7 files changed, +180 -45 (225 total)
💡 Approaching commit threshold. Consider committing current work.
---
📊 Status: 12 files changed, +320 -80 (400 total)
⚠️ Changes are large! Commit now to keep PRs reviewable.
Suggested commit: "feat: Add user authentication flow"
---
📊 Status: 3 files changed, +85 -10 (95 total)
✅ Tests passing. Good time to commit!
Suggested commit: "fix: Validate email format on signup"When a feature is genuinely large, use stacked PRs:
┌─────────────────────────────────────────────────────────────────┐
│ STACKED PR PATTERN │
│ ───────────────────────────────────────────────────────────── │
│ │
│ main ─────────────────────────────────────────────────────────│
│ └── PR #1: Database schema (200 lines) ← Review first │
│ └── PR #2: API endpoints (250 lines) ← Review second │
│ └── PR #3: Frontend (300 lines) ← Review third │
│ │
│ Each PR is reviewable independently. │
│ Merge in order: #1 → #2 → #3 │
└─────────────────────────────────────────────────────────────────┘bash# Create base branch git checkout -b feature/auth-schema # ... make changes ... git commit -m "feat: Add users table schema" git push -u origin feature/auth-schema gh pr create --base main --title "feat: Add users table schema" # Create next branch FROM the first git checkout -b feature/auth-api # ... make changes ... git commit -m "feat: Add authentication API endpoints" git push -u origin feature/auth-api gh pr create --base feature/auth-schema --title "feat: Add auth API endpoints" # And so on...
Files: ≤ 5 = 🟢 | 6-10 = 🟡 | > 10 = 🔴
Lines: ≤ 200 = 🟢 | 201-400 = 🟡 | > 400 = 🔴
Time: ≤ 30min = 🟢 | 30-60min = 🟡 | > 60min = 🔴bash# Quick status git diff --shortstat HEAD # Detailed file list git diff --stat HEAD # Partial staging git add -p # Check before PR git diff main --shortstat
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 9,642 | 5,291 | -45% | 1 | 1 | 0% | 1,411 | 4,254 | +201% | 0 | 0 | — |
case-02 | fail→pass | 11,834 | 18,494 | +56% | 1 | 1 | 0% | 2,621 | 8,017 | +206% | 0 | 0 | — |
case-03 | pass→pass | 9,308 | 6,139 | -34% | 1 | 1 | 0% | 1,808 | 5,145 | +185% | 0 | 0 | — |
case-04 | pass→pass | 5,668 | 6,534 | +15% | 1 | 1 | 0% | 1,111 | 5,144 | +363% | 0 | 0 | — |
case-05 | pass→pass | 3,534 | 4,895 | +39% | 1 | 1 | 0% | 780 | 4,895 | +528% | 0 | 0 | — |
case-06 | fail→pass | 16,616 | 8,067 | -51% | 1 | 1 | 0% | 2,476 | 5,452 | +120% | 0 | 0 | — |
case-07 | pass→pass | 13,699 | 11,704 | -15% | 1 | 1 | 0% | 2,204 | 5,935 | +169% | 0 | 0 | — |
case-08 | pass→pass | 11,800 | 11,458 | -3% | 1 | 1 | 0% | 2,398 | 6,168 | +157% | 0 | 0 | — |
case-09 | pass→pass | 15,908 | 15,637 | -2% | 1 | 1 | 0% | 3,238 | 7,171 | +121% | 0 | 0 | — |
case-10 | pass→pass | 2,630 | 2,441 | -7% | 1 | 1 | 0% | 467 | 4,373 | +836% | 0 | 0 | — |
case-11 | pass→pass | 7,863 | 4,003 | -49% | 1 | 1 | 0% | 1,226 | 4,690 | +283% | 0 | 0 | — |
case-12 | fail→pass | 7,255 | 2,827 | -61% | 1 | 1 | 0% | 1,392 | 4,480 | +222% | 0 | 0 | — |
case-13 | pass→pass | 7,322 | 2,491 | -66% | 1 | 1 | 0% | 1,446 | 4,386 | +203% | 0 | 0 | — |
case-14 | pass→fail | 10,650 | 4,834 | -55% | 1 | 1 | 0% | 1,970 | 4,850 | +146% | 0 | 0 | — |
case-15 | fail→pass | 18,580 | 11,393 | -39% | 1 | 1 | 0% | 3,664 | 5,873 | +60% | 0 | 0 | — |
case-16 | pass→pass | 4,217 | 3,963 | -6% | 1 | 1 | 0% | 967 | 4,664 | +382% | 0 | 0 | — |
case-17 | pass→pass | 5,717 | 3,068 | -46% | 1 | 1 | 0% | 1,007 | 4,471 | +344% | 0 | 0 | — |
case-18 | pass→pass | 6,117 | 2,584 | -58% | 1 | 1 | 0% | 1,060 | 4,405 | +316% | 0 | 0 | — |
case-19 | pass→pass | 3,856 | 3,321 | -14% | 1 | 1 | 0% | 669 | 4,544 | +579% | 0 | 0 | — |
case-20 | pass→pass | 3,029 | 3,327 | +10% | 1 | 1 | 0% | 550 | 4,635 | +743% | 0 | 0 | — |
case-21 | fail→pass | 6,748 | 3,102 | -54% | 1 | 1 | 0% | 1,226 | 4,541 | +270% | 0 | 0 | — |
case-22 | pass→pass | 13,141 | 6,693 | -49% | 1 | 1 | 0% | 2,447 | 5,492 | +124% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.