| name | smart-commit |
| description | Create conventional commits in production context with strict validation, tests, linters, and confirmation. |
| tools | Bash, AskUserQuestion |
Skill — smart-commit
Create conventional commits in a production context.
This skill enforces tests, linters, commit conventions, and safety checks.
All commits must pass before being accepted.
Execution Steps
1. Show current changes
git status --short
2. Check for sensitive files (mandatory)
git status --porcelain | grep -E '.(env|key|pem|secret|password)$|credentials'
- If found: warn and stop commit
- User must remove sensitive files before proceeding
3. Run linters (mandatory)
just check
- If any check fails: stop, report the failure, do not proceed to commit
4. Suggest commit type and draft message
Based on changed files, recommend:
- feat — new functionality
- fix — bug fix
- docs — documentation only
- test — tests only
- chore — tooling/config/deps
- refactor — restructuring
- ci — CI/CD and workflow changes
Draft a suggested commit title (imperative, English) and compute its character count. Display it as:
Suggested: feat: add payment gateway (27 chars)
This lets the user see the length constraint before answering, avoiding a back-and-forth correction loop.
5. Ask user for commit details
Use AskUserQuestion to get:
- Commit type (mandatory, default to suggested)
- Optional scope (e.g.
domain, feature, ci) — leave blank for no scope
- Commit message (imperative, English, ≤72 characters) — pre-populate with the suggested title from step 4 (including its char count) so the user can accept or adjust inline without a back-and-forth correction loop
feat/fix titles are user-facing. Only feat and fix titles reach the generated CHANGELOG.md (release.py's Added/Fixed sections), which some projects render verbatim in an in-app "What's new". Write the title's description as a plain user-visible outcome — no rule IDs/trigrams (REF-010), no internal jargon or abbreviations. Push the technical why into the body. (The conventional-commit scope is separate and fine.) Titles for other types (chore, refactor, docs, test, ci) don't reach the changelog and may stay technical.
- Commit body (optional, English, max 5 lines):
- Body explains why, not what. The diff is the what. The body captures intent, constraint, tradeoff, or non-obvious reasoning the diff cannot convey. Do not enumerate changes — that's the AI default and it produces noise; resist it.
- Footer rules:
BREAKING CHANGE: is ignored toward the 5-line limit. Co-Authored-By: is forbidden (blocked by the commit-msg hook). Refs: (e.g. Refs: #123) is allowed and counts toward the 5 lines.
6. Validate message format
- Commit type must be one of:
feat, fix, docs, test, chore, refactor, ci
- For breaking changes, append
! after the type (e.g. refactor!: drop foo); the release script will major-bump the version
- Title ≤72 chars, body ≤5 lines (
BREAKING CHANGE: footer lines excluded from count)
- If non-compliant: return to step 5 and prompt the user to correct the message
7. Confirm before committing
Display the full formatted commit title (and body if provided) as plain text in the chat, then ask the user to confirm:
Ready to commit: type(scope): message
Proceed?
Use AskUserQuestion with a Yes / Cancel option. Never pack a multi-line body into the preview field — AskUserQuestion previews render only the first line followed by "N lines hidden", so the user cannot evaluate it. Always show the full message in chat first; the prompt only collects yes/cancel. If the user cancels, stop and do not commit.
8. Create commit
Stage only the relevant files identified in step 1 (never use git add -A — it can accidentally include sensitive or unintended files):
git add <file1> <file2> ...
git commit -m "feat: add payment gateway"
git commit -m "feat(billing): add payment gateway"
Format: type: message (no scope) or type(scope): message (with optional scope).
9. Show result
git log -1 --oneline
Critical Rules
- Never commit sensitive files
- All linters must pass (
just check) before committing
- Commit message must be in English and follow conventional format:
type: message or type(scope): message
- Body explains why, not what — the diff is the what; do not enumerate changes
feat/fix titles are user-facing — only they reach the CHANGELOG; write them as plain outcomes (no rule IDs, trigrams, or internal jargon), technical detail goes in the body
- Never use
git add -A — stage files explicitly by name
- User confirmation required before commit
- No bypassing rules in production
Notes
- Ensures traceability, safety, and maintainability
- Designed for production: correctness over speed