Create Commit
Create a conventional commit from staged changes with branch safety, automatic type detection, and optional PR creation.
Isolation
CRITICAL: Each invocation of this skill operates in complete isolation. Ignore all prior conversation context, previous instructions, earlier diffs, commit messages, user decisions, and any other information from the current session. Base every decision — type, scope, message, branch handling — solely on the current state of the git repository as observed by the commands executed within this invocation.
Process
- •
Verify staged changes — Run
git diff --cached --name-only. If no files are staged, inform the user and stop. - •
Load commitlint config — Search the repository root for a commitlint configuration file. Use Glob to check for these files (in priority order):
codecommitlint.config.{js,cjs,mjs,ts,cts,mts} .commitlintrc .commitlintrc.{json,yaml,yml,js,cjs,mjs,ts,cts,mts}Also check
package.jsonfor acommitlintfield.If a config is found, read it and extract all applicable rules:
- •
type-enum— allowed commit types (overrides the default type table) - •
scope-enum— allowed scopes (restricts scope choices) - •
header-max-length— max header length (overrides the 72-char default) - •
subject-case— required casing for the subject - •
body-max-line-length— max line length in the body - •
body-leading-blank— whether a blank line is required before the body - •
footer-leading-blank— whether a blank line is required before the footer - •Any other rules defined in the config
If the config uses
extends(e.g.,@commitlint/config-conventional), acknowledge the base ruleset and apply any rule overrides on top.If no config is found, apply the default constraints defined in the steps below.
- •
- •
Gather context (run in parallel):
- •
git diff --cached— full diff of staged changes - •
git branch --show-current— current branch name - •
git log --oneline -5— recent commits for style consistency
- •
- •
Branch guard — If on
mainormaster, ask whether to:- •Create a new branch (derive name as
<kebab-description>, max 50 chars), then rungit checkout -b <name> - •Continue committing directly to the protected branch
- •Create a new branch (derive name as
- •
Determine commit type — If commitlint config defines
type-enum, only use types from that list. Otherwise, use the default table:Type When to use featNew functionality, new public interfaces fixBug fixes, corrections preserving existing interfaces refactorCode restructuring without behavior change choreTooling, config, dependencies, non-functional changes docsDocumentation-only changes styleFormatting, whitespace, no logic change testAdding or updating tests ciCI/CD pipeline changes perfPerformance improvements revertReverting a previous commit - •
Determine scope — If commitlint config defines
scope-enum, only use scopes from that list. Otherwise, use a scope when all changes fall within a single logical module, component, or directory. Omit scope when changes span multiple areas or touch root-level config. - •
Compose the commit message following the Conventional Commits specification and all loaded commitlint rules:
- •Format:
type(scope): subjectortype: subject - •Subject rules:
- •Must contain a verb and a subject — the verb describes the action, the subject addresses the area
- •Use present simple, imperative mood (
addnotadds/added) - •Start lowercase (unless commitlint
subject-caserequires otherwise) - •Stay under 72 characters (or the
header-max-lengthfrom commitlint config — note this limit applies to the entire header including type, scope, and colon) - •Be specific and meaningful — the reader must understand what changed without looking at the diff
- •Keep it short — if motivation or context is needed, put it in the body
- •Describe what actually changed, not the meta-task you are working on
- •Body (when needed): Explain what changed and why, note breaking changes or migration steps. Use the body to clarify motivation when the subject alone is insufficient. If commitlint enforces
body-max-line-length, wrap body lines accordingly. - •Blank lines: Always add a blank line between header and body, and between body and footer (commitlint
body-leading-blankandfooter-leading-blankrules enforce this by default). - •No metadata trailers: Do not append
Co-Authored-By, AI attribution, or any trailers not explicitly requested by the user. The commit message contains only the header and optional body.
Subject quality rules
Must have verb + subject (action + area):
- •Bad:
feat: bearer login functionality(no verb) - •Bad:
feat: add(no subject) - •Good:
feat: add bearer login functionality
Must be meaningful — reader should understand the change:
- •Bad:
style: change bunch files(unclear what changed) - •Good:
style: format src folder with prettier - •Bad:
chore: fix build(unclear how) - •Good:
chore: add env var extract plugin
Must address a specific area, not be generic:
- •Bad:
fix: fix bug(says nothing) - •Bad:
fix: fix schema(still vague) - •Good:
fix: change first name type in user schema
Keep short — use body for context:
- •Bad:
feat: add another get user endpoint because first endpoint doesn't return security information for admin - •Good:
code
feat: add admin get user endpoint The existing endpoint works for simple user, but now admins want to get additional information about the user.
Describe actual changes — never the meta-task:
- •Bad sequence:
chore: final try→chore: trying to enable→chore: fix→chore: fix build - •Good sequence:
chore: add extract env plugin→chore: remove default env plugin→chore: enable cache layer for webpack - •Never use words like "trying", "another try", "final fix" — each commit must stand on its own
- •Format:
- •
Present the message to the user for approval before committing.
- •
Commit — Execute
git commitwith the approved message using a heredoc:bashgit commit -m "$(cat <<'EOF' type(scope): subject Optional body explaining what and why. EOF )"
- •
Handle pre-commit failures — If the commit fails due to linting or formatting hooks:
- •Analyze the error output
- •Apply targeted fixes to the reported issues
- •Stage fixes with
git add(specific files only, notgit add .) - •Re-attempt the commit
- •Repeat up to 3 times, then report remaining issues to the user
- •Offer PR creation (non-main branches only) — After a successful commit, push the branch and ask whether to create a PR. Run the exact command as shown — no additional flags:
- •Create PR →
gh pr create --fill - •Create draft PR →
gh pr create --fill --draft - •Skip → do nothing
- •Create PR →
Commit Message Examples
feat(auth): add jwt token validation fix(parser): handle empty input gracefully refactor: consolidate duplicate helper functions chore: update terraform provider versions docs(api): add rate limiting section test(billing): add edge case coverage for zero amounts ci: add staging deployment workflow perf(db): add index on users.email column feat!: redesign authentication flow BREAKING CHANGE: OAuth tokens from v1 are no longer valid.