# Commit Message

> Write a clean commit message from the staged changes — imperative subject in the codebase's convention, body only when it earns its place, no filler. Triggers on "write a commit message", "commit this", "what should this commit say", or when the user is about to run `git commit` and hasn't written a message.

- Skill: `duckcode-js/commit-message` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add duckcode-js/commit-message`
- Raw SKILL.md: https://api.skillmd.com/api/skills/duckcode-js/commit-message/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: DuckCode-js (https://skillmd.com/u/duckcode-js)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/duckcode-js/commit-message

---


# commit-message

Turn the staged diff into a commit message that actually tells the reader
what changed and, when needed, why. Follows the codebase's convention
automatically. Refuses to write a message for a diff that shouldn't be one
commit.

## When to use this

- "Write a commit message"
- "Commit this"
- "What should this commit say"
- User is about to `git commit` with no `-m` and asks for help

## Procedure

### 1. Read the actual staged changes

```sh
git diff --cached --stat
git diff --cached
git status --short
```

If nothing is staged (`git diff --cached` is empty), stop and ask the user
what to stage. Do not run `git add -A` on their behalf — you don't know what
they want in this commit.

If there are unstaged changes alongside staged ones, note that to the user
(possible split-commit situation).

### 2. Detect the codebase's convention

Check `git log --pretty=format:"%s" -30` for the pattern in the last ~30 commits:

- **Conventional Commits** — subjects like `feat:`, `fix:`, `docs:`, `chore:`,
  `refactor:`, sometimes with a scope (`fix(auth): …`). Very common in
  JavaScript/TypeScript ecosystems and any project with a CHANGELOG generator.
- **Gitmoji / emoji prefix** — starts with an emoji, e.g. `🐛 fix crash on load`.
- **Plain imperative** — no prefix, just verb-first sentence, e.g.
  `Fix crash on load when config missing`. Common in older projects, Rails,
  and many system-level codebases.
- **Trailer conventions** — some projects use `Signed-off-by:` or `Refs: #123`
  trailers; match if present.

Match whichever the history uses. Do not impose Conventional Commits on a repo
that has never used them.

If there's a `CONTRIBUTING.md`, `COMMITS.md`, or `.gitmessage` in the repo,
read those first — explicit convention beats detected convention.

### 3. Write the subject line

Rules that apply to every convention:

- **Imperative present tense.** "Fix" not "Fixed". "Add" not "Added". "Refactor"
  not "Refactored". The convention is that the subject completes: "If applied,
  this commit will _______".
- **≤ 72 characters** hard, ≤ 50 preferred. Terminals wrap at 72; GitHub UI
  truncates around 50.
- **No trailing period.**
- **Capitalize first word** after any prefix.
- **Specific over generic.** "Fix off-by-one in pagination cursor" beats
  "Fix bug". "Update dependency" is almost never right — say what for and to
  what version.

If using Conventional Commits, pick the type from the actual change:

- `feat` — user-visible new capability
- `fix` — user-visible bug fixed
- `docs` — documentation only (READMEs, comments, guides)
- `refactor` — internal restructure with no behavior change
- `test` — tests added or fixed
- `perf` — performance improvement without behavior change
- `chore` — build tooling, deps, configs
- `style` — formatting only, no logic
- `ci` — CI pipeline changes
- `revert` — reverts a previous commit

If the diff spans multiple types (feat + fix + refactor together), that's a
sign this should be multiple commits. Say so; offer to help split them.

### 4. Decide whether a body is needed

Write a body when — and only when — the subject alone leaves an obvious
"why?" or "why this way?" unanswered. Examples:

- Non-obvious tradeoff was made
- Change is smaller than the discussion around it (fix that took hours to
  find — one-line diff, worth explaining what was wrong)
- Breaking change (mandatory body noting the break and migration path)
- Change is easy to misread from the diff alone
- Change references an issue or ADR the reader should see

Skip the body when:

- Change is small and self-explanatory
- Change is one of many similar (tenth typo fix, third dep bump)

If you write a body:

- Blank line between subject and body
- Wrap at 72 columns
- Explain **why**, not what. The diff shows what.
- Reference issues/PRs at the bottom: `Refs: #123` or `Closes #123`

### 5. Refuse to lie or leak

Before showing the message, verify:

- **No fabricated context.** If the diff doesn't tell you why the change was
  made and there are no other clues (issue link in branch name, TODO
  comments, related recent commits), ask the user for the "why" instead of
  guessing.
- **No secrets in the diff.** If the diff appears to contain API keys, tokens,
  or `.env`-shaped strings, halt. Do not write a message. Tell the user which
  lines look sensitive.
- **No `wip`, `fix stuff`, `updates` as the whole subject.** Even if the user
  says "just commit it", offer a real message and let them override.

### 6. Present and offer to commit

Print the full proposed message (subject + body if any). Offer:

- "Commit as-is" — run `git commit -m "<subject>" -m "<body>"`
- "Edit first" — open in editor via `git commit` (no -m)
- "Split" — if step 3 flagged multiple types, help split into separate
  staged sets and commit each

Do not run `git commit` without explicit approval, and never rewrite history
(`--amend`) unless the user asks for it.

## Anti-patterns

- Do not just paraphrase the file names ("Update foo.js and bar.js").
- Do not use marketing language ("Improve performance dramatically"). Say
  what by how much: "Cut cold-start time by 40% by caching schema load".
- Do not use `--no-verify` or `--no-gpg-sign` unless the user asks — respect
  their hook and signing setup.
- Do not squash unrelated changes into one commit. If the diff is doing two
  things, offer to split.

