| name | commit |
| description | Generates consistent git commit messages following project conventions. Use when committing changes, creating PRs, or when asked to write commit messages. Also validates if proposed messages follow project format. |
Git Commit Messages
Generate well-formatted commit messages following project conventions.
Workflow
- Run
git status and git diff --staged (or git diff if nothing staged)
- Analyze which files changed, what was added/removed/modified
- Determine the correct type and scope (use the Path → Scope table)
- If changes should be split into multiple commits, group files logically
- Draft each commit message
- Run the Validation Checklist on every message before returning
- Return a preview for each proposed commit
Output Format
For each commit, return:
### Commit N
**Files:**
- path/to/file1.ts
- path/to/file2.ts
**Message:**
type(scope): subject
- Body bullet.
Rules for previews:
- List ALL staged files that belong to each commit
- If suggesting multiple commits, clearly indicate which files go in each
- Never execute the commit — only return the preview
- Group related files together (same feature, same scope)
Message Format
type(scope): subject in imperative mood
- Body bullet in past tense with period.
- Another change description.
Closes #123
The Closes #123 trailer is optional — include it only when this single commit is the complete fix for a tracked issue (see Rule 9).
Types
| Type | When to Use |
|---|
feat | Added new functionality or new capabilities |
fix | Fixed a bug |
refactor | Restructured code, no behavior change, no new capabilities |
chore | Dev-time: dependencies, tooling, local configs |
docs | Documentation |
test | Tests |
cicd | Ship-time: CI/CD, releases, deployment, containers, git hooks (e.g., Dockerfile, Kraftfile, lefthook.yml, .github/, .release-it.*) |
revert | Reverted a previous commit |
ai | AI configurations (see AI scope below) |
chore vs cicd: If it affects how code gets to production (build, CI, release, deploy) → cicd. If it affects how developers work locally (deps, formatting, linting, editor) → chore.
Scope
Scope is derived from context and varies by type:
| Type | Scope Convention | Examples |
|---|
feat, fix, refactor | Path-based: derived from package path | feat(server):, fix(domain): |
chore, docs | Path-based or omit if mixed | chore(web):, docs: |
cicd | Functional: release, deploy, or omit | cicd(release):, cicd(deploy):, cicd: |
test | Path-based: same scope as the code being tested | test(domain):, test(server): |
ai | Component: skills, mcp, or omit | ai(skills):, ai(mcp):, ai: |
revert | Match the original commit's scope | revert(web): |
When changes span multiple scopes, omit the scope entirely.
Path → Scope derivation
Derive scope from the deepest meaningful package directory:
| File path prefix | Scope |
|---|
apps/server/ | server |
apps/web/ | web |
packages/domain/ | domain |
docs/, root configs | omit |
Files outside apps/ and packages/ (e.g., docs/, root configs) have no package scope — omit it.
AI Scope
The ai type covers anything that directly configures, instructs, or extends AI capabilities:
| Category | Examples |
|---|
| Agent configs | .claude/, .cursor/, .github/copilot/, .aider/, .continue/ |
| MCP servers | .mcp.json, MCP server implementations |
| Skills & prompts | Skills, system prompts, prompt templates |
| AI rules | CLAUDE.md, AGENTS.md, COPILOT.md, AI coding guidelines |
| Model configs | Model selection, temperature, context window settings |
| AI tooling | Repomix configs, AI-specific linting rules |
Excludes (use other types instead):
- Code that calls AI APIs →
feat/fix
- AI library dependencies →
chore
- Documentation about AI features →
docs
File → Type Quick Lookup
Before choosing a type, check if the changed files match these patterns:
| File Pattern | Type | Scope |
|---|
.mcp.json | ai | mcp |
.claude/skills/** | ai | skills |
.claude/**, CLAUDE.md, AGENTS.md, COPILOT.md | ai | — |
.cursor/**, .github/copilot/** | ai | — |
Dockerfile, Kraftfile, .github/workflows/** | cicd | — |
lefthook.yml, .release-it.* | cicd | — |
If ALL changed files match ai patterns → use ai type. If mixed with non-AI files, split into separate commits.
Rules
- Subject: Imperative mood, lowercase after colon, no period, max 72 chars
- Body: Past tense, capital start, period at end. One physical line per bullet — never hard-wrap a bullet mid-sentence at ~72 columns; only the subject has a length limit. Let the terminal soft-wrap.
- No attribution: Never include "Co-Authored-By", "Generated with", or any AI/author attribution
- AI-only changes: When changes are exclusively AI-related (see AI Scope), always use
ai type
- No mechanical cleanup or implementation narration: Don't mention consequences obvious from the primary change (removed unused imports, unwrapped single-child fragments, updated indentation), and don't describe how the diff achieves the change ("added a helper that maps X to Y" when the diff is the helper). Focus on intent / why, not mechanism
- Plain language for everyone: Write the subject and body so a non-technical reader and a brand-new contributor can follow the change without prior context. Lead with the everyday-terms "what changed and why it matters," spell out an acronym or internal name (a table, a service, a flag) the first time it appears, and don't lean on unstated background. Keep the precise technical terms — add the plain-language point on top, don't drop it. (Commit messages outlive their context: they're read in
git blame, changelogs, and release notes long after the surrounding work is forgotten.)
- No tautology: The subject must not repeat the type as a verb. The type already conveys the action — e.g.,
fix: fix the login → fix: resolve login failure, refactor: refactor auth → refactor: simplify auth flow
- No bare
# tokens in the body: The changelog generator reads #<token> as a GitHub issue reference and renders it as a "closes" link, so a hex color or fragment becomes a broken issue link in the release notes — write b05220 → 95400f, not #b05220 → #95400f
- Issue-closing trailer: When one commit is the complete fix for a tracked issue, add a
Closes #<issue> line as the last line, after a blank line — GitHub auto-closes the issue when the commit lands on the default branch (Fixes/Resolves are equivalent keywords). This deliberate reference is the one sanctioned exception to Rule 8: a Closes #<issue> trailer is fine; a bare #<token> anywhere else is not. Only tag the commit that finishes the issue — if the fix spans several commits, leave the trailer off each partial commit and put Closes #<issue> in the PR description instead, so the issue closes once on merge, not on the first partial commit. Skip it entirely for a commit that touches no tracked issue.
Body sizing
One bullet per topic, not per file. Files are an implementation detail; the diff already lists them. A topic is a distinct concern a reader needs to understand: a behavior change, a follow-up worth flagging, a side effect that lives outside the diff. A 10-file rename across one package is one topic; a one-file PR that fixes a bug and changes a wire-shape and defers a TODO is three.
The diff shows what changed; the message answers why. When in doubt, fewer bullets. Each bullet earns its place by carrying information the diff doesn't.
| Topics in the change | Body |
|---|
| Zero (subject already conveys intent fully) | None — subject is enough |
| One | 0–1 bullet, ≤ 2 sentences |
| Two or three (split into separate commits if practical) | 2–3 bullets |
| More | First reconsider whether this should be multiple commits; if not, 3–5 bullets |
Skip a bullet that:
- Restates the subject in different words.
- Lists files —
git log --stat shows them.
- Narrates implementation steps the diff already shows.
- Recaps the investigation. The investigation belongs in the PR description, not the commit body.
- Reports test counts or "all green" results unless the change itself is a test infra fix.
Keep a bullet that:
- Explains why when it isn't obvious from the diff (non-local invariant, regression cause, external constraint).
- Flags a side effect a future reader might miss (wire-shape change, env var added, perf trade-off).
- Notes follow-up work intentionally deferred.
Validation Checklist
Run this checklist on every message before returning the preview:
- Length: Count the subject line — reject if >72 chars
- Scope: Look up the file paths in the Path → Scope table — confirm the scope matches (or is omitted for root/mixed files)
- Tautology: Verify the subject does not repeat the type word (fix/fix, refactor/refactor, feat/feat, docs/docs, etc.)
- Mood: Subject uses imperative ("add", "fix", "migrate") — not past tense ("added", "fixed")
- Body: Every bullet starts with a capital letter, uses past tense, ends with a period
- Body wrapping: Each bullet is a single physical line — no hard wrap mid-sentence
- Issue trailer: If this one commit fully closes a tracked issue, confirm a
Closes #<issue> trailer sits on its own last line; if the fix spans commits, confirm the trailer is absent (it belongs in the PR body)
Examples
feat(server): add health check endpoint
fix(web): handle empty pipeline state without throwing
test(server): make email-attachment-download self-sufficient
- Previous version resolved admin@taller.cat from the seed; multi-org-isolation truncated inboxes between runs and pre-push then failed in beforeAll. Synthetic fixture ids survived the truncate and cleaned up after themselves.
feat(server): add company search with filters
- Added search_companies route with status, region, industry filters.
- Returned summary projections to minimize payload size.
refactor(domain): migrate interactions to timestamptz columns
- Replaced date columns with timestamp for timezone awareness.
- Replaced date columns with timestamptz for timezone awareness.
chore: update workspaces and dependencies
- Bumped @biomejs/biome to 2.4.10.
- Synced Effect packages to ^3.21.0.
cicd(deploy): add workspace package build chain to server Dockerfile
- Built domain package before server so imports resolve.
- Pinned pnpm version in corepack to match lockfile.
ai(skills): update commit message conventions for batuda
ai(mcp): add batuda CRM server
feat(web): add pipeline dashboard with status counts
- Added pipeline overview route with company counts by status.
- Displayed overdue tasks and companies needing next action.