A Claude Code custom slash command that turns git commit into a guided, consistent workflow: it reads your branch name and staged diff, drafts a structured commit message, asks for your explicit approval before committing, and then keeps a companion documentation site in sync with whatever module you just touched.
It’s implemented as a single Markdown file that Claude Code treats as a slash command — no build step, no dependencies, works in any repo that uses Git.
1. What problem this solves
Most teams have a commit message convention (ticket ID, change type, time spent, a short body) and a rule that docs should stay current — and both erode over time because they depend on someone remembering to do them by hand, in the right format, every single time.
This skill automates the mechanical parts (parsing the branch, drafting the message, finding the right doc file) while keeping a human in the loop for the parts that require judgment (approving the final message, deciding whether to commit doc changes).
2. How it works, step by step
Step 1 — Parse the branch name
Reads the current branch (git branch --show-current) and exing convention:
- a ticket/card ID (e.g. feature/PROJ-123-add-search → PROJ-123)
- a change type — classified into a small fixed set
Step 2 — Read the staged diff
Runs git diff --staged. If there’s nothing staged,it stops and tells you to git add first — it never invents a message from unstaged or unrelated changes.
Step 3 — Ask for the one thing it can’t infer
Time spent (or whatever metadata your team tracks per commit) isn’t in the diff or the branch name, so it’s the one question the skill asks directly.
Step 4 — Draft the commit message
Combines branch info + diff + your answer into a fixed template:
The prefix format is <type>:(<TICKET>)#time <time> <title>, for example feature:(PROJ-123)#time 1h30m add retry logic
Rules baked in:
- Exact prefix formatting, including where hooks matter.
- Title: concise, lowercase except acronyms, no trailing pe
- 3–6 bullets, meaningful changes only — formatting-only diffs are skipped unless they affect behavior.
- No file names in the body unless essential.
Step 5 — Confirm before committing (mandatory)
The message is shown once, in a fenced code block, followed
“Use this commit message? (yes / edit / no)”
- yes → commit.
- edit → you describe the change, it regenerates, shows it
- no → you explain what’s wrong, it regenerates from scratch, shows it again, asks again.
git commit never runs until you’ve said yes to a message you’ve actually seen. This is the one non-negotiable step in the whole flow — everything
else can be inferred or skipped, this can’t.
Step 6 — Commit
Runs git commit via a heredoc so multi-line formatting surv
Step 7 — Sync documentation (optional stage )
If your team keeps docs in a separate repo/site, this stageor the module you touched and reconciles it — see below.
Step 8 — Ask about pushing
Simple yes/no at the end; never pushes without being asked.
3. Why a hard confirmation gate
It would be easy to let the skill run git add && git commit && git push in one shot. It deliberately doesn’t:
- Commit messages are semi-generated from a diff — the model can misread intent, especially on large or mixed-purpose diffs.
- Commits are comparatively easy to fix, but a bad message that ships to a shared branch history is annoying to clean up.
- The “edit” path lets you nudge the draft (“focus more on the API change, less on the test tweaks”) instead of writing the whole thing by hand, which is most of the value of the skill without giving up control.
Any variant of this skill you build for your own repo should keep this gate. Don’t let a commit happen on the first draft.
4. Setting it up in your own repo
-
Create
.claude/commands/commit-msg.md(or.claude/skills/commit-msg/SKILL.mdif you’re using the skills format) in your repo — attached below — or in~/.claude/commands/if you want it available across every repo you work in. -
Write the frontmatter + instructions following the steps above, adapted to:
- your branch naming convention (what pattern encodes the ticket ID and change type — or drop this entirely if you don’t use one),
- your commit message format (prefix, body style, any hook it needs to stay compatible with),
- whatever metadata you want asked for (time spent, risk level, testing notes — anything not derivable from the diff).
- Invoke it with /commit-msg after staging changes.
Reference implementation: commit-msg.md
commit-msg.md (11.8 KB)
That’s the whole install. No packages, no CI changes — it’s a prompt that tells Claude Code which git commands to run and in what order, with a confirmation gate in the middle..
5. Using the skill day-to-day
Prerequisites
- The skill file is installed as a Claude Code command — either project-local (.claude/commands/commit-msg.md) or user-global (~/.claude/commands/commit-msg.md).
- You’re working inside a Git repository.
- You’ve staged the changes you want committed (git add ).
Running it
- Stage your changes as usual:
git add src/payments/webhookHandler.ts - Invoke the skill:
/commit-msg - It reads your current branch name and the staged diff automatically — no input needed from you at this point.
- It asks one question:
▎ “How long did you spend on this?”
▎ Answer in whatever shorthand you like (15m, 1h30m, 2h). - It shows you a fully drafted commit message in a code block and asks:
▎ “Use this commit message? (yes / edit / no)”
- Reply yes to commit it as-is.
- Reply edit and describe what to change (e.g. “focus more on the retry logic, less on the test file”) — it regenerates and shows you the new version.
- Reply no and explain what’s wrong — it drafts a fresh version from scratch.
- Once you approve, it runs the commit for you.
- If the change touched a module/area your team documents, it will check the docs repo and propose doc updates — you’ll get a separate summary and a separate yes/no before anything is committed there.
- Finally, it asks whether to push. Answer yes or no.
What you don’t need to do
- Don’t type the commit message yourself — the skill drafts it.
- Don’t manually figure out the ticket ID or change type from your branch name — it parses that automatically.
- Don’t run git commit yourself mid-flow — let the skill run it after you approve.
When to intervene
- If the drafted message misses the actual reason for a change (something only you know, not visible in the diff), use edit rather than approving and fixing it after the fact.
- If a docs update looks wrong or incomplete, say so when it asks for confirmation — don’t approve it blind.
6. Playing nicely with existing git hooks
If your repo already has a prepare-commit-msg (or similar) hook that reformats commit messages — e.g. stamping a time value or reordering fields — check what shape of input it expects and leaves alone. A common trap: the hook only skips reformatting if the message already starts with the final expected prefix; if the skill emits a slightly different shape first, the hook “helpfully” reprocesses it and mangles fields (duplicating a timestamp, dropping the body, etc.).
The fix is simple: read the hook’s logic once, and have the skill emit the message in the exact final shape the hook treats as already-done. Document that constraint directly in the skill file (as a comment near the format rules) so it isn’t silently reintroduced later.
If you have no such hook, ignore this section — just pick whatever format your team prefers.
7. The documentation-sync stage
This is the more advanced half of the skill: after committing code, it checks whether the change touched a “unit” worth documenting (a module, service, feature area — whatever your project’s natural boundary is) and keeps a corresponding doc file up to date in a separate docs repository.
7a. Locating the docs repo once
The docs repo’s local path differs per machine/developer, so it’s resolved once and cached:
- Check a small marker file (e.g. ~/.claude/commit-msg-doc-repo-path).
- If present, validate it’s still a real git repo; if the check fails (moved, renamed, different machine), treat it as missing.
- If missing, ask once for the path, validate it, and save it verbatim for future runs.
This pattern generalizes to anything else a skill needs to remember about your machine without hardcoding a path in the skill file itself.
7b. Mapping code → doc file
Detect which repo/module you’re in (e.g. by repo name or a config file), and apply a fixed mapping to a target doc file — one doc file per module is a reasonable default. Match by closest existing filename rather than assuming exact spelling, since real-world doc trees accumulate naming drift.
7c. Reconcile, don’t just append
Two cases:
- Doc exists — compare it against the module’s current code (its actual files/folders/endpoints/exports today, not just this diff), and fill in whatever’s missing, following the doc’s existing structure and voice. Don’t rewrite or restyle sections that are already correct.
- Doc doesn’t exist — generate it from scratch following a canonical template for that doc type , so every doc of the same kind has the same shape regardless of who or what generated it.
The key rule: touching a module is the trigger to audit its entire doc, not just describe today’s diff. A trivial formatting-only commit still triggers a full audit of that module’s documentation — the target is “is this module’s documentation complete right now,” not “what changed in this commit.” Only skip the audit if the module wasn’t touched at all.
7d. Canonical templates keep docs consistent
Define, per doc type, the exact section list a “complete” doc must have (e.g. Overview → Directory Structure → main flows/pages → dependencies used → external calls/endpoints → error handling → any locale-specific strings). Treat a doc that’s missing whole sections as incomplete, not just “short,” and have the skill upgrade it to the full structure rather than leaving a thin stub in place. This is what prevents docs generated at different times by different people (or different model runs) from drifting into inconsistent shapes.
7e. Separate repo, separate commit
The docs repo has its own git history. After editing it, summarize the change and ask a separate yes/no before committing there — never bundle it into the code repo’s commit, and never assume the answer from the earlier confirmation.
8. Docusaurus implementation
The example above assumes the docs repo is a Docusaurus site, which is a natural fit for this kind of skill because Docusaurus turns plain Markdown into a browsable site with almost no extra configuration. Concretely:
- Docs are just files. Everything under the site’s docs/ folder is a .md or .mdx file. The skill’s job is entirely “write correct Markdown to the right path” — there’s no build API to call, no database to update.
- The sidebar builds itself. With
// sidebars.ts*
const sidebars = {
tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
};
Docusaurus derives the entire sidebar tree from the folder structure of docs/ — new folders become new sidebar sections and new files become new sidebar entries automatically. The skill never has to touch a sidebar config file when it creates a new doc.
Ordering comes from frontmatter. Each doc’s position within its section is controlled by a sidebar_position field in its YAML frontmatter:
---
sidebar_position: 3
---
# My Module
When the skill creates a new doc, it picks the next available position in that folder; when it edits an existing doc, it leaves the existing value alone.
- Folders get labels/order via category.json. A folder can carry a small JSON file controlling how it appears as a sidebar category:
{ "label": "Backend Docs", "position": 2 }
This only needs to be created once per top-level section, not per doc.
- .mdx for anything richer than prose. Plain narrative docs are .md; pages that embed live components (e.g. a component library / design-system reference) use .mdx, which allows JSX inside Markdown. The skill’s own output is almost always plain .md — .mdx is typically for hand-authored reference pages it doesn’t need to touch.
- No rebuild wiring needed. Because routing and the sidebar are both derived from the filesystem, a skill that only ever writes well-formed Markdown files with correct frontmatter into the right folder requires zero changes to docusaurus.config.* — the next docusaurus build (or dev server hot-reload) just picks the new/changed file up.
9. Adapting this to your own repo — checklist
- Decide your branch naming convention (or skip ticket/type extraction entirely if you don’t have one).
- Decide your commit message format, and check it against any existing git hook (§6).
- Decide what single piece of metadata (if any) is worth asking for manually.
- Keep the confirmation gate before any git commit — don’t remove it for convenience.
- If you want doc sync: decide your module boundary (what one doc file covers), where the docs repo lives, and write a canonical template per doc type so generated docs stay consistent over time.
- If using Docusaurus (or adopting it): rely on folder-based autogeneration + sidebar_position + category.json instead of hand-maintaining a sidebar file — it’s what makes “skill writes a Markdown file” sufficient to update the live site.
- Keep the docs repo’s commit/push as a separate, separately-confirmed step from the code repo’s.