Commit message
Skill netopsengineer/axiom/plugins/axiom-git/skills/commit-message
Use ANY time the user signals they want to commit staged changes — including bare "commit", "/commit", "commit this", "commit these changes", "let's commit", "make a commit", "git commit", "write a commit message", "make a conventional commit", "use conventional commits", or any equivalent phrasing in context (e.g., right after staging files, "ready to commit", "okay ship it"). Composes a Conventional Commits message with a gitmoji prefix: reads the staged diff, decides type, scope, emoji, subject, body, and footer using the rubrics in this file, shows one assembled message in a fenced block, and commits after a single yes/no confirmation. It writes the commit message only — NOT other prose about the staged changes: not PR/MR descriptions, not release notes, not changelogs or summaries. Also do NOT use for questions *about* git or *about* conventional commits, amending, rebasing, cherry-picking, reverting/undoing commits, or viewing log history.From its SKILL.md
npx -y skills add netopsengineer/axiom --skill commit-messageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 8 commands, including `git diff --cached --stat` and 7 more.
SKILL.md
12.4 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it
Commit Message Generation
Read the staged diff, decide every field yourself using the rubrics below, and surface one assembled message for a single yes/no confirmation. Don't prompt field-by-field (a GUI extension can afford that; a chat turn can't), and don't short-circuit to a bare git commit -m "fix stuff" — if this skill loaded, run the full flow and never bypass hooks.
Repo defaults
Format: <type>(<scope>): <emoji> <subject>
Emoji style: Unicode glyph (e.g. 🐛 not :bug:)
Scope default: none (include only if the diff points clearly at one)
Co-Authored-By: off (this repo's history doesn't use the trailer)
Body default: skip unless the diff is non-trivial (>~10 lines, multi-file, or non-obvious why)
Footer default: skip; reserve for `BREAKING CHANGE:` or `Closes #N`
Subject limits: warn at >50 chars; hard cap at 72
Hooks: gitleaks runs pre-commit; do not bypass on failure
These are bootstrap defaults from this repo's history. In a different repo, re-detect during preflight (Phase 1 step 5) and adjust silently — observed in-repo history wins.
When to ask the user
Only stop and ask in these cases — otherwise decide and continue:
- Nothing staged. Offer to stage by filename (never
git add -A/-u/.). - On
master,main, or detached HEAD. Offer to create a new branch, move the staged changes there, then resume on that branch. Refuse to commit directly to master/main. - Suspicious staged content (
.env*,*.key,*.pem, files ≥1 MB, secrets in diff). Show the offending file/line, ask whether to unstage or proceed. - Genuinely ambiguous type or emoji choice — i.e., two options are equally defensible from the rubric and the choice changes how a reader will interpret the commit (e.g.,
featvsfixwhen the change adds a new code path that also corrects bad behavior). State the options and the tradeoff in one line, then wait. If the rubric picks a clear winner, do not ask. - Final assembled message. Always show the complete commit message in a fenced block and wait for explicit confirmation before running
git commit.
If the user's invoking message unambiguously specifies the subject ("commit this as a fix to the OAuth timeout"), step 5 may be skipped — otherwise still confirm.
Phase 1 — Preflight (silent unless something fails)
Run these checks in parallel where possible. Surface results to the user only if one fails or trips an "ask" condition above.
-
Staged changes.
git diff --cached --stat. If empty, follow ask-condition #1. -
Branch.
git rev-parse --abbrev-ref HEAD. Ifmaster,main, orHEAD(detached), follow ask-condition #2. Any other branch name is fine — feature/, fix/, chore/, bare names, prefixed names, all acceptable. -
Stage summary.
git diff --cached --name-status+--stat. Flag suspicious paths per ask-condition #3. -
Sensitive-content sniff. Scan the whole staged diff for likely-live credentials, not just the top:
git diff --cached | grep -E -i \ '(password|secret|api[_-]?key|BEGIN [A-Z ]*PRIVATE KEY|AKIA[0-9A-Z]{16}|aws_secret_access_key)[[:space:]]*[=:]' \ | head -20Any hit → follow ask-condition #3. The
[=:]anchor avoids false positives on the bare word "password" appearing in prose or comments. -
Repo-convention sniff.
git log --pretty=%s -20andgit log -20 --format=%B:- Count Unicode glyphs vs
:code:in subjects → output emoji style. - Count
(scope)parens → scope-default on/off. - Look for
Co-Authored-By:→ trailer default.
If detected defaults differ from the "Repo defaults" block above, prefer the detected ones; note the mismatch in the final-confirmation summary but don't block on it.
- Count Unicode glyphs vs
Moving off master/main
If the branch check trips, propose a branch name derived from the staged diff (e.g., from the most-changed top-level dir, or the subject about to be drafted). Confirm the name, then:
git stash --keep-index # preserve staged set, set aside any unstaged work
git switch -c <new-branch>
git stash pop || true # restore unstaged work onto the new branch
Then resume preflight on the new branch. Don't commit on the original branch under any circumstances.
Phase 2 — Decide every field
Work through these in order using the rubrics below and produce a single assembled commit message. No per-field prompts.
Type rubric
Paths below are illustrative — match on the signal (only tests touched, mostly renames, new behavior), not the exact paths, so this generalizes across repos.
| signal in diff | type |
|---|---|
Only test files touched (e.g., tests/**, **/*_test.go, **/*.spec.ts) | test |
Only **/*.md, doc/**, and the file is genuinely docs (not operational instructions) | docs |
Only CI config (.github/workflows/**, .gitlab-ci.yml, .circleci/**) | ci |
Only build configs, dependency manifests (pyproject.toml, package.json, Dockerfile), or setup scripts | build |
Mostly R status (renames/moves) in git diff --cached --name-status | refactor (emoji 🚚) |
| New file with new behavior; new template/role/module; new agent/skill definition | feat |
| Modifies existing behavior to fix wrong output, error, regression | fix |
| Reorganization without behavior change | refactor |
| Speed / resource-use improvement with no behavior change | perf |
git revert-style change (HEAD~1 is a "Revert ..." or message starts with revert:) | revert |
| Whitespace / formatting only | style |
| Catch-all | chore |
Operational .md files (skills, agent instructions, runbook-style READMEs) lean feat/chore, not docs. The docs type is reserved for genuine documentation of something else (READMEs about code, architecture notes, charter docs).
Scope rubric
Default: omit. Include a scope only if all the staged paths cluster under one directory that maps to an obvious name. Spans multiple top-level dirs → no scope. If repo history overwhelmingly skips scope (detected in Phase 1 step 5), only include if the diff really demands it.
Emoji rubric
Pick the contextual emoji if one fits, else the type default:
- feat ✨ — alternates: 🎉 (initial commit), 🚸 (UX), 🏗️ (architecture), 🧑💻 (DX tooling /
.claude/changes) - fix 🐛 — alternates: 🚑️ (critical hotfix), 🩹 (non-critical/one-liner), 🔒️ (security: auth, secrets, CVE)
- docs 📝 — alternates: 💡 (in-code comments), 📄 (license)
- style 🎨 — alternates: ✏️ (typo)
- refactor ♻️ — alternates: 🚚 (mostly
Rrenames/moves), 🔥 (deleted code dominates), ⚰️ (dead code removal) - perf ⚡️
- test ✅ — alternates: 🧪 (failing test added), 📸 (snapshots)
- build 👷 — alternates: 📦️ (compiled output), ⬆️/⬇️/➕/➖/📌 (only lockfile/manifest changes)
- ci 💚 — alternates: 👷 (build system)
- chore 🔧 — alternates: 🔨 (dev scripts), 🙈 (.gitignore), 🏷️ (types)
- revert ⏪️
For the full glyph list and :code: mapping (used if the repo-convention sniff in Phase 1 detects :code: style, or if the user requests a different emoji by name), see references/gitmoji.md.
Emoji glyph integrity: several glyphs include a U+FE0F variation selector that forces emoji-style rendering (🚑️, 🔒️, ♻️, ⚡️, ✏️, ⏪️, 🏷️, 📦️, 🗑️, 🔍️). Copy the glyph as-is — do not strip the variation selector or these will render as monochrome text on some clients.
Subject rules
- Imperative mood ("Add X", not "Added X").
- No trailing period.
- Capitalize the first word.
- Do not repeat the type ("Add X", not "feat: Add X").
- Target ≤50 chars. Warn (in the final summary) at 50, hard-refuse at 72.
- The diff is the source of truth — describe the change, not the motivation.
Body rules
Include a body only if:
- Diff is ≥10 lines changed, or
- Spans multiple files, or
- The why is non-obvious from the diff (constraint, prior incident, ticket context).
When included: 1–3 sentences, wrapped at 72 cols, focused on why, not what.
Footer rules
Include only when:
- Diff includes a breaking change (public API change, schema/migration, removed config key) →
BREAKING CHANGE: <one-line description>. - User mentioned a ticket number in conversation →
Closes #NorRefs #N.
Phase 3 — Confirm and commit
-
Assemble:
{type}({scope}): {emoji} {subject} {body} {footer}Drop
(scope)if no scope. Single space between emoji and subject. Blank line before body and before footer; omit either block entirely if empty. NoCo-Authored-By:trailer unless repo-convention sniff demanded it. -
Show the full message in a fenced code block. Note any caveats inline: "subject is 58 chars (over 50 warn line)", "convention sniff disagrees with repo defaults — using detected style". Ask once: confirm or revise?
-
On confirm, commit via heredoc:
git commit -m "$(cat <<'EOF' <type>(<scope>): <emoji> <subject> <body> <footer> EOF )"Single
git commitcall. Do not stage anything new at this step. -
Verify with
git log -1 --format=%Bso the user sees what actually landed (including any hook-injected trailers). -
If the user revises something on the confirmation step, apply the change and re-show the full message. Don't restart the flow.
Failure modes
Nothing staged, on master/main, and suspicious staged content are decision gates — handle them per When to ask the user. The rest:
- Hook failure (gitleaks etc.). The commit did not land. Surface the hook output verbatim. Don't retry with
--no-verifyand don't--amend(nothing to amend) — the user fixes the root cause, re-stages, and re-invokes for a fresh commit. - User abandons mid-flow ("never mind", "cancel"). Stop without committing; leave staging untouched.
- User asks for
--amend. This skill only creates new commits. Direct them togit commit --amendmanually, orgit reset --soft HEAD~1+ re-invoke. - Subject exceeds 72 chars. Hard refuse. Trim or move detail to the body before confirming.
- Multi-line subject pasted. Treat the first line as the subject; move everything after it into the body.
Out of scope
No commitlint integration (no config in this repo — the rubrics here are the contract; revisit if .commitlintrc* lands). No persistent scope cache — re-derive from the diff each time. No [skip ci], no interactive git add -p (stage first), no amend/rebase, and no bypass flags (--no-verify, --no-gpg-sign, -n).
What ships with it: 2 files
7.2 KB alongside SKILL.md
evals/
- evals.json2.7 KB
references/
- gitmoji.md4.5 KB