---
name: conventional-commit-message
source: https://app.decimal.ai/s/conventional-commit-message@1/SKILL.md
source_sha256: 47494898df4c
---

# Conventional Commit Message

## Contract

Enforces the Conventional Commits format on every git commit message you write.
Apply whenever you are asked to write, draft, or generate a commit message —
even if the request just says "write the commit message" with no mention of any
convention.

## Rules

### Subject line (the first line)

Format it EXACTLY as: `type(scope): subject`. The `(scope)` is optional; the
`type`, the `: ` separator, and the `subject` are not.

1. **Type** — MUST be one of these exact lowercase tokens and nothing else:

   | token | use for |
   |---|---|
   | `feat` | a new feature / capability for the user |
   | `fix` | a bug fix |
   | `docs` | documentation only (README, comments, API docs) |
   | `style` | formatting / whitespace only, no change to code meaning |
   | `refactor` | restructuring that neither fixes a bug nor adds a feature |
   | `perf` | a change that improves performance, output unchanged |
   | `test` | adding or correcting tests only |
   | `build` | build system or external dependencies |
   | `ci` | CI configuration and scripts |
   | `chore` | anything else (`.gitignore`, configs, housekeeping) |

   Spell them exactly: `feat` (never `feature`), `perf` (never `performance`),
   `docs`, `refactor`. Never invent a type — no `update`, `improve`, `add`,
   `change`, `misc`, `enhancement`, `bugfix`, `cleanup`, `wip`.

2. **Scope** (optional) — a lowercase noun in parentheses naming the area
   touched, e.g. `fix(auth):`, `feat(api):`. No space between the type and `(`.
   Omit the parentheses entirely when there is no scope; never write empty `()`.

3. **Separator** — exactly a colon then a single space: `: `.

4. **Subject** — the description after `: `:
   - The first character is **lowercase**. Never capitalize the subject.
   - Use the **imperative mood**: `add`, `fix`, `remove` — not `added`,
     `adds`, `adding`, `fixed`, `removed`.
   - **No period** (or any other punctuation) at the end.
   - Keep the whole first line **50 characters or fewer**.

### Body (optional)

- Separate it from the subject with **one blank line**.
- Wrap lines at **72 characters**.
- Explain **what and why**, not how — the diff already shows how.

### Footer (optional)

- Reference an issue with `Fixes #123` or `Closes #123` on its own line.
- A breaking change MUST include a footer line that begins with the exact
  uppercase token `BREAKING CHANGE:` followed by a description.

### Choosing the type from the diff

Read what the change actually does, not how it feels:

- a bug fix → `fix`; a new endpoint/button/feature → `feat`
- a README/comment/API-doc edit with no code change → `docs`
- a reformat / reindent / trailing-comma sweep with no logic change → `style`
- a rename or extract-helper with identical behavior → `refactor`
- a same-output speedup → `perf`; a new or repaired test → `test`
- a dependency bump or lockfile change → `build`; a workflow YAML edit → `ci`
- a `.gitignore` / config / housekeeping edit → `chore`

## Worked examples

Each shows the base model's wrong default (BEFORE) and the conforming form
(AFTER).

**feat — new capability**
- BEFORE: `Added dark mode toggle to settings page.`
- AFTER: `feat: add dark-mode toggle to settings`

**fix — bug fix**
- BEFORE: `Fixed crash when profile is null`
- AFTER: `fix: guard against missing user profile`

**fix with scope**
- BEFORE: `Fixed case-sensitive email lookup in auth`
- AFTER: `fix(auth): match email case-insensitively`

**docs — documentation only**
- BEFORE: `Update README installation instructions`  (wrong type `update`)
- AFTER: `docs: correct npm install commands`

**style — formatting only**
- BEFORE: `Reformatted src with prettier`
- AFTER: `style: reindent src and add trailing commas`

**refactor — no behavior change**
- BEFORE: `Refactored: extracted formatDate helper.` (capital + period)
- AFTER: `refactor: extract shared formatDate helper`

**perf — same output, faster**
- BEFORE: `performance: improved user search speed` (spelled out, past-ish)
- AFTER: `perf: use map lookup for user search`

**test — tests only**
- BEFORE: `Add tests for CSV parser`  (capitalized)
- AFTER: `test: add unit tests for csv parser`

**build — dependency change**
- BEFORE: `Bumped webpack to 5.92`
- AFTER: `build: bump webpack from 5.88 to 5.92`

**ci — CI config**
- BEFORE: `Update workflow to use Node 20`  (wrong type, capital)
- AFTER: `ci: run build pipeline on node 20`

**chore — housekeeping**
- BEFORE: `Updated .gitignore`
- AFTER: `chore: ignore dist and .env.local`

**breaking change (footer)**
- BEFORE: `Removed deprecated timeout param from fetchData`
- AFTER:
  ```
  refactor: drop deprecated timeout param

  BREAKING CHANGE: fetchData no longer accepts a timeout
  argument; callers must remove it.
  ```

**issue reference (footer)**
- BEFORE: `Fix empty-cart total crash (issue 217)`
- AFTER:
  ```
  fix: handle empty cart in total calculation

  Fixes #217
  ```

## Edge cases & exceptions

- **A bug fix in a test file** is `test` if you are fixing the test itself
  (e.g. a flaky test), not `fix`. `fix` is for product behavior.
- **A dependency bump** is `build` (it changes what gets built). `chore` is the
  fallback only when nothing more specific fits; prefer `build` for deps.
- **A `.gitignore` edit** is `chore`, not `build` — it changes no build output.
- **A CI workflow edit** is `ci` even if it touches the same YAML a build uses;
  CI config wins over `build`.
- **A reformat is `style`; a rename is `refactor`.** Whitespace-only → `style`;
  identifier/structure change with identical behavior → `refactor`. They are
  different types; do not collapse both into one.
- **A change that breaks callers** keeps its natural type (`feat`, `fix`, or
  `refactor`) on the subject AND adds the `BREAKING CHANGE:` footer. The footer
  is what signals the break, not the type.
- **Subject would exceed 50 chars** — tighten wording or move detail into the
  body; do not let the first line spill past 50.

## Do / Don't

- DON'T capitalize the subject (`fix: Guard …`). ALWAYS lowercase it
  (`fix: guard …`).
- DON'T end the subject with a period. ALWAYS leave it unpunctuated.
- DON'T use past tense (`fix: added toggle`). ALWAYS imperative (`fix: add
  toggle`).
- DON'T invent types (`update:`, `improve:`, `bugfix:`). ALWAYS use the closed
  set above.
- DON'T spell `feature:` or `performance:`. ALWAYS `feat:` / `perf:`.
- DON'T write a bare summary line with no type. ALWAYS prefix with `type:`.
- DON'T put the breaking-change note only in the body. ALWAYS use a
  `BREAKING CHANGE:` footer.

## Common mistakes (the base's wrong defaults)

- Writing a capitalized plain-English summary with no type prefix —
  `Improved API performance` instead of `perf: speed up api responses`.
- Capitalizing the subject after a correct type — `feat: Add toggle`.
- Adding a trailing period — `fix: handle null profile.`.
- Past-tense subjects — `feat: added export button`.
- Long-form or invented types — `feature:`, `performance:`, `update:`,
  `chore: misc changes`.
- Putting "BREAKING CHANGE" in the subject instead of a footer.

## Quick checklist

- [ ] First line is `type(scope): subject`, scope optional.
- [ ] Type is one of the 10 exact lowercase tokens.
- [ ] Subject starts lowercase, imperative mood, no trailing period.
- [ ] First line ≤ 50 characters.
- [ ] Body (if any) after a blank line, wrapped at 72.
- [ ] Issue → `Fixes #N` footer; breaking → `BREAKING CHANGE:` footer.
