Create conventional commit messages by analyzing staged changes. Generates semantic commit messages following the Conventional Commits specification. Use when user says "commit", "save changes", or "create commit".
72%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/aif-commit/SKILL.mdBefore mode routing or work, read existing files relative to the current project root in this order (reuse them if already loaded):
.ai-factory/skill-context/global-skill-context.md — all bundled skills..ai-factory/skill-context/aif-commit/SKILL.md — this skill.Missing files are skipped; an existing unreadable file stops dependent work with its path.
Precedence: individual > build (when applicable) > global > skill defaults; retain non-conflicting instructions and check all outputs against the effective rules.
These layers customize workflow; they do not replace the project's rules/architecture hierarchy or relax explicit requirements, ownership, scope, safety/privacy, validation, or approval boundaries. Report conflicts with those boundaries instead of overriding them.
global is a project-local layer, not home-directory configuration. Custom/extension skills do not automatically use it.
Generate commit messages following the Conventional Commits specification.
FIRST: Read .ai-factory/config.yaml if it exists to resolve:
paths.description, paths.architecture, paths.rules_file, paths.roadmap, paths.rules, paths.plan, and paths.planslanguage.ui for prompts and commit message conventionsworkflow.plan_id_format for read-only active plan discovery (slug default; sequential uses numbered full-plan lookup) and workflow.plan_structure for commit-layout detection (classic default; task-based means commits are explicit tasks inside the main task list)git.enabled, git.create_branches, and git.skip_push_after_commit for active plan discovery and post-commit push behaviorrules.base plus any named rules.<area> entriesIf config.yaml doesn't exist, use defaults:
.ai-factory/ for context artifacts, .ai-factory/PLAN.md for paths.plan, .ai-factory/plans/ for paths.plansen (English)workflow.plan_id_format: slug, workflow.plan_structure: classicgit.enabled: true, git.create_branches: trueskip_push_after_commit: falseRead .ai-factory/skill-context/aif-commit/SKILL.md — MANDATORY if the file exists.
This file contains project-specific rules accumulated by /aif-evolve from patches,
codebase conventions, and tech-stack analysis. These rules are tailored to the current project.
How to apply skill-context rules:
Enforcement: After generating any output artifact, verify it against all skill-context rules. If any rule is violated — fix the output before presenting it to the user.
Analyze Changes
git status to see staged filesgit diff --cached to see staged changesResolve Active Plan Context (Read-Only, Optional)
@<plan-file-or-directory> argument, when the argument starts with @paths.planspaths.plans, or a single ultra bundle therepaths.plan@, keep treating it as commit scope/context.@<plan-file> syntax remains valid; the broader form additionally
accepts an ultra directory or its index.md.git branch --show-current when git.enabled = true/ with - to get <branch-stem>workflow.plan_id_format = sequential, use Glob for both
paths.plans/[0-9][0-9][0-9][0-9]_<branch-stem>.md and
paths.plans/[0-9][0-9][0-9][0-9]_<branch-stem>/index.mdindex.md
contains exactly one <!-- aif:plan-mode:ultra -->WARN [aif-commit] when
multiple valid candidates exist; if both shapes share the highest prefix,
prefer ultrapaths.plans/<branch-stem>/index.md then
paths.plans/<branch-stem>.md; Read the directory entrypoint before
selection, ignore it unless it contains exactly one ultra marker, and
warn and prefer ultra if both valid shapes exist*.md full plans plus direct child */index.md
entrypoints containing <!-- aif:plan-mode:ultra -->; exclude the resolved fast-plan
path and do not count phase files.index.md as ultra, Read it and require exactly one
<!-- aif:plan-mode:ultra -->; otherwise STOP with a plan-integrity error.<!-- aif:plan-mode:ultra -->; ignore unrelated */index.md files.## Commit Plan nor explicit task-based commit tasks, keep current staged-diff behavior unchanged.## Commit Plan sectionCommit changes with message "..."Use Commit Plan Grouping When Available
If invoked by /aif-implement with an explicit task-bound commit request,
treat the supplied plan path, commit task ID, dependency task IDs, exact
message, and file/hunk map as the selected group. This mode takes
precedence over ordinary grouping prompts: do not offer "Commit everything
together" or expand the group to other plan tasks.
Classic-group task-bound mode: /aif-implement may invoke this mode
for exactly one group from a classic ## Commit Plan, using the explicit
classic-group mode and supplying the exact resolved plan path, group
number/name as written, complete task range, exact planned commit message,
task IDs/descriptions and their Files:/hunk ownership evidence, plus the
current HANDOFF_MODE value. This is task-bound mode, not ordinary
plan-aware grouping. It does not require a commit-task ID or dependency
list. Resolve the supplied path and verify the selected group exists in
that plan; its group number/name, task range, and message must match the
plan exactly. Reject missing, duplicate, ambiguous, or mismatched group
metadata before changing the index. Re-read and map the exact task range
from the plan; caller-supplied task/file evidence is a scope hint, not
authority to expand the group. Never select adjacent groups or offer
"Commit everything together."
Before changing the index, capture the complete outstanding change set
against HEAD for the selected group, including staged, unstaged, and
untracked changes. Use git status --porcelain -uall and
git ls-files --others --exclude-standard to enumerate untracked paths;
inspect each candidate's content and prove its ownership before staging.
Map changes at hunk level when files overlap groups. This captured set is
the completeness baseline for both task-based and classic-group
task-bound execution.
Compare the selected group against both staged and unstaged changes.
Commit only changes proven to belong to that group. Leave unrelated
staged and unstaged changes untouched. Preserve unrelated staged and
unstaged changes. Do not run git add ., unstage unrelated changes, or
commit a pre-existing staged change outside the selected group.
If staged changes include unrelated work, the selected group overlaps other task work in a way that cannot be separated confidently, or any staged/unstaged hunk has unclear ownership, stop before changing the index and report the exact ambiguity. The caller must leave the plan commit task incomplete.
Stage every remaining proven change in the captured selected-group set, whether the index started empty or partially staged. Whole-file staging is allowed only for a disjoint group file with no unrelated unstaged edits; otherwise use hunk-level staging or stop. Explicitly stage selected, proven untracked files and verify they are no longer untracked. Before committing, verify that the staged diff contains the complete captured selected-group set, including the contents of originally untracked files, and no changes outside it. If either scope or completeness cannot be proven, stop without committing.
If invoked in classic-group task-bound mode, resolve only the caller-
selected ## Commit Plan entry and validate its group number/name, task
range, and exact message against the saved plan. Do not run the ordinary
multi-group flow.
Otherwise, if active plan contains ## Commit Plan, parse:
after tasks 1-3 or tasks 4-6Else if the active plan uses workflow.plan_structure: task-based or contains explicit commit tasks in ## Tasks, parse task-based commit entries instead:
<!-- aif:task-kind:commit --> immediately before the task lineCommit changes with message "feat: implement user service"Commit changes with message; do not treat ordinary "commit" wording elsewhere as a commit taskRead the plan's ## Tasks or ## Implementation Tasks section to map task ranges to task descriptions and any Files: hints.
For an ultra plan, resolve every task in the current commit group to its
Phase Index/details link, read each corresponding phase file, and build the
staged-path mapping from its ## Files to Change table plus the complete
## Task N specifications. Reading only index.md is insufficient.
If one phase contains tasks from multiple commit groups, use the individual
## Task N sections to distinguish file/hunk ownership; do not assign the
phase's entire file table to every group without task-level evidence.
Compare staged files/hunks with planned groups before changing staging:
git diff --cached --name-onlygit diff --cached when a file may span multiple groupsFiles: hints are guidance, not executable instructionsIf files cannot be mapped to groups, stop and ask the user to adjust grouping.
Before using whole-file staging, compare grouped files with unstaged worktree paths from git diff --name-only.
Only use git add <files> when each planned group has a disjoint file set and no grouped file appears in git diff --name-only.
When one file spans multiple planned groups, use hunk-level staging (git add -p or git apply --cached) for each group.
If grouped files overlap unstaged worktree paths, preserve and apply the original cached patch per group (git diff --cached + git apply --cached), use hunk-level staging, or stop before changing staging.
If hunk-level staging cannot be applied confidently, stop before changing staging. In ordinary mode, ask the user to adjust grouping or choose one commit; in task-bound mode, do not widen the selected group.
When a usable grouping exists in ordinary (non-task-bound) mode, ask:
AskUserQuestion: Active plan contains a commit grouping. How should these staged changes be committed?
Options:
1. Follow Commit Plan
2. Commit everything together
3. Adjust groupingFollow Commit Plan → confirm the planned groups and messages, then proceed through user-confirmed multi-commit staging/commit flow.
Commit everything together → ignore plan grouping for this run and continue with the current single-message flow.
Adjust grouping → ask the user for the adjusted grouping, then validate it against staged files before committing.
Task-based commit plans are treated as valid planning metadata when the user selected a task-based plan structure or when commit task patterns are present; they do not require a separate ## Commit Plan section.
Run Context Gates (Read-Only)
paths.rules_file + rules.base + named rules.<area>) for commit conventionsROADMAP.md, RULES.md) are WARN, not blockers/aif-rules-check; keep /aif-commit gate labels at WARN / ERRORDetermine Commit Type
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Code style (formatting, semicolons)refactor: Code change that neither fixes a bug nor adds a featureperf: Performance improvementtest: Adding or modifying testsbuild: Build system or dependenciesci: CI configurationchore: Maintenance tasksIdentify Scope
src/auth/ → auth)Generate Message
<type>(<scope>): <subject>
<body>
<footer>Simple feature:
feat(auth): add password reset functionalityBug fix with body:
fix(api): handle null response from payment gateway
The payment API can return null when the gateway times out.
Added null check and retry logic.
Fixes #123Breaking change:
feat(api)!: change response format for user endpoint
BREAKING CHANGE: user endpoint now returns nested profile objectWhen invoked:
Check for staged changes
Analyze the diff content
Resolve optional active plan context and use either the classic ## Commit Plan or explicit task-based commit entries when available
Run read-only context gates and summarize findings as WARN/ERROR
If commit type is feat/fix/perf and roadmap exists, check milestone linkage; if missing, warn and suggest adding linkage in commit body/footer
Propose a commit message
Confirm with the user before committing:
Task-bound mode with HANDOFF_MODE=1: /aif-implement's explicit
authorization for the selected commit task or classic group authorizes
committing only that group; do not prompt and use the exact planned
message.
Task-bound mode in a manual session: show the exact planned message and selected task/group, then offer only:
Options:
1. Commit this group
2. CancelOrdinary mode: use the standard confirmation below:
AskUserQuestion: Proposed commit message:
<type>(<scope>): <subject>
Options:
1. Commit as is
2. Edit message
3. CancelHandle user response:
HANDOFF_MODE=1, proceed to step 9 with the exact planned
message and no prompt.AskUserQuestion, then
return to step 7; Cancel → stop, do NOT commit.Execute git commit with the confirmed message
--no-verify, disable their environment, or use
blanket staging to make a failed hook pass. Suggest /aif-quality-setup only
when the user wants checks/hooks configured; ordinary commits do not run setup./aif-implement; return the resulting commit hash and
success or failure explicitly so /aif-implement can verify and persist
task/group state.Post-commit push handling:
In task-bound HANDOFF_MODE=1, do not prompt or push; finish after the
successful local commit.
If git.skip_push_after_commit = true in resolved config:
Otherwise (default behavior), offer to push:
git status -sbgit push -u origin <branch>git pushAskUserQuestion: Push to remote?
Options:
1. Push now
2. Skip pushgit push -u origin <branch>git pushIf argument provided (e.g., /aif-commit auth):
/aif-commit classic-group is a reserved task-bound mode selector when the
invocation also supplies the complete classic-group payload described in Step
3. If that payload is missing or invalid, stop; do not reinterpret the mode
token as an ordinary commit scope.
/aif-commit has no implicit strict mode — context gates are warning-first unless user explicitly requests blocking behavior## Commit Plan section nor explicit task-based commit tasks, keep current staged-diff behavior unchanged.## Commit Plan; never fall back to ordinary grouping when this mode was requested.Show which files/hunks belong to which commit
Confirm split plan with the user:
AskUserQuestion: Split into separate commits?
Options:
1. Yes, split as suggested
2. No, commit everything together
3. Let me adjust the groupingHandle user response:
AskUserQuestion, then return to step 2 with the new planBefore changing staging, confirm whether each planned group has a disjoint file set, whether any file spans multiple groups, and whether grouped files overlap unstaged worktree paths from git diff --name-only.
If every group has a disjoint file set and no grouped file appears in git diff --name-only, unstage all with git reset HEAD, then stage and commit each group separately using git add <files> + git commit.
If grouped files overlap unstaged worktree paths, preserve each group's original cached patch before unstaging and re-apply only that patch with git apply --cached; otherwise use hunk-level staging or stop before changing staging.
If one file spans multiple groups, use hunk-level staging for each group: stage only that group's hunks with git add -p or git apply --cached, commit, then repeat for the next group.
If hunk-level staging or cached-patch application cannot be applied confidently, stop before changing staging and ask the user to adjust grouping or commit everything together.
Offer to push only after all commits are done
Co-Authored-By or any other trailer attributing authorship to the AI. Commits must not contain AI co-author lineslee-to/ai-factory
9771b77
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.