Agent Skills: Clean Commits

Use when committing code - ensures atomic, descriptive commits that leave the codebase in a merge-ready state at every point

UncategorizedID: troykelly/codex-skills/clean-commits

Skill Files

Browse the full folder contents for clean-commits.

Download Skill

Loading file tree…

skills/clean-commits/SKILL.md

Skill Metadata

Name
clean-commits
Description
Use when committing code - ensures atomic, descriptive commits that leave the codebase in a merge-ready state at every point

Clean Commits

Overview

Every commit is atomic, descriptive, and leaves code in a working state.

Core principle: Anyone should be able to checkout any commit and have working code.

Announce at use: "I'm committing with a descriptive message following clean-commits standards."

Commit Message Format

Structure

[type](scope): Short description (max 72 chars)

[Optional body - what and why, not how]

[Optional footer - issue references, breaking changes]

Refs: #[ISSUE_NUMBER]

Types

| Type | Use For | |------|---------| | feat | New feature | | fix | Bug fix | | docs | Documentation only | | style | Formatting, no code change | | refactor | Code restructuring | | test | Adding/fixing tests | | chore | Maintenance, dependencies |

Examples

feat(auth): Add user registration endpoint

Implement POST /api/users/register with email validation,
password hashing, and duplicate detection.

- Validates email format and uniqueness
- Hashes password with bcrypt
- Returns user object without password

Refs: #123
fix(auth): Prevent redirect loop on expired session

Session expiry was triggering redirect to login, which
checked session, found expired, and redirected again.

Now clears session cookie before redirecting.

Refs: #456
test(auth): Add integration tests for registration

Cover success case, duplicate email, invalid format,
and weak password scenarios.

Refs: #123

Atomic Commits

What Makes a Commit Atomic

| Atomic | Not Atomic | |--------|------------| | One logical change | Multiple unrelated changes | | Passes all tests | Breaks tests | | Complete feature slice | Half-implemented feature | | Can be reverted cleanly | Reverts would break things |

Signs of Non-Atomic Commits

  • Commit message uses "and" to describe multiple things
  • Diff includes unrelated files
  • Some tests fail after commit
  • "WIP" in commit message

Splitting Large Changes

If you have multiple changes, commit them separately:

# Stage specific files
git add src/auth/register.ts
git add src/auth/register.test.ts
git commit -m "feat(auth): Add registration endpoint"

# Stage next logical unit
git add src/auth/login.ts
git add src/auth/login.test.ts
git commit -m "feat(auth): Add login endpoint"

Working State Requirement

Every commit must leave the codebase in a state where:

  • [ ] All tests pass
  • [ ] Build succeeds
  • [ ] Application runs
  • [ ] No TypeScript errors
  • [ ] No linting errors

Before committing:

# Run tests
pnpm test

# Check build
pnpm build

# Check types
pnpm typecheck

# Check lint
pnpm lint

If any fail, fix before committing.

Commit Frequency

Commit Often

  • After each passing test in TDD cycle
  • After each refactoring step
  • After completing a logical unit

Don't Wait Too Long

| Too Infrequent | Just Right | |----------------|------------| | "Implement entire feature" | "Add user model" | | "Fix all bugs" | "Fix session expiry redirect" | | "Update everything" | "Update auth dependencies" |

Small is Good

Smaller commits are:

  • Easier to review
  • Easier to revert
  • Easier to bisect
  • Easier to understand

The Commit Process

1. Stage Selectively

# Review what changed
git diff

# Stage specific files
git add [specific files]

# Or stage interactively
git add -p

2. Review Staged Changes

# See what will be committed
git diff --staged

3. Write Descriptive Message

# Short message (if simple)
git commit -m "fix(auth): Handle null user in session check"

# Long message (if complex)
git commit
# Opens editor for full message

4. Verify After Commit

# Check commit looks right
git show --stat

# Verify tests still pass
pnpm test

Commit Message Body

When to include a body:

  • Why the change was made (not just what)
  • Context that isn't obvious from code
  • Trade-offs or alternatives considered
  • Breaking changes if any

Body Examples

refactor(api): Extract validation middleware

Validation logic was duplicated across 12 endpoints.
Extracted to reusable middleware that can be composed.

Alternative considered: validation library.
Rejected because our rules are domain-specific.
fix(data): Use optimistic locking for updates

Race condition was causing lost updates when two users
edited the same record simultaneously.

BREAKING CHANGE: Update operations now require
version field in request body.

Issue References

Always reference the issue:

# In commit message
Refs: #123

# Or if commit closes the issue
Closes: #123

Amending Commits

When to Amend

  • Typo in message (if not pushed)
  • Forgot to stage a file (if not pushed)
# Amend last commit (before push only!)
git add forgotten-file.ts
git commit --amend

When NOT to Amend

  • After pushing to remote
  • Changing commits others have based work on

Revert, Don't Delete

If a commit was wrong:

# Create a new commit that undoes the change
git revert [commit-sha]

# DON'T rewrite history on shared branches
# DON'T force push to fix mistakes

Checklist

Before each commit:

  • [ ] Tests pass
  • [ ] Build succeeds
  • [ ] Change is atomic (one logical unit)
  • [ ] Message follows format
  • [ ] Message describes why, not just what
  • [ ] Issue is referenced
  • [ ] No "WIP" or placeholder messages

Integration

This skill is called by:

  • issue-driven-development - Throughout development
  • pr-creation - Before creating PR

This skill enforces:

  • Reviewable history
  • Revertible changes
  • Clear project narrative