aif-commit
GitHub基于 Conventional Commits 规范生成语义化 Git 提交信息。支持读取项目配置与上下文规则,适配经典及任务型工作流,确保提交格式符合团队约定。
Trigger Scenarios
Install
npx skills add lee-to/ai-factory --skill aif-commit -g -y
SKILL.md
Frontmatter
{
"name": "aif-commit",
"description": "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\".",
"allowed-tools": "Read Glob Bash(git *) AskUserQuestion Questions",
"argument-hint": "[scope or context]",
"disable-model-invocation": false
}
Conventional Commit Generator
Shared project skill-context
Before 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.
Workflow
FIRST: Read .ai-factory/config.yaml if it exists to resolve:
- Paths:
paths.description,paths.architecture,paths.rules_file,paths.roadmap,paths.rules,paths.plan, andpaths.plans - Language:
language.uifor prompts and commit message conventions - Workflow:
workflow.plan_id_formatfor read-only active plan discovery (slugdefault;sequentialuses numbered full-plan lookup) andworkflow.plan_structurefor commit-layout detection (classicdefault;task-basedmeans commits are explicit tasks inside the main task list) - Git preference:
git.enabled,git.create_branches, andgit.skip_push_after_commitfor active plan discovery and post-commit push behavior - Rules hierarchy:
rules.baseplus any namedrules.<area>entries
If config.yaml doesn't exist, use defaults:
- Paths:
.ai-factory/for context artifacts,.ai-factory/PLAN.mdforpaths.plan,.ai-factory/plans/forpaths.plans - Language:
en(English) - Workflow:
workflow.plan_id_format: slug,workflow.plan_structure: classic - Git:
git.enabled: true,git.create_branches: true - Git preference:
skip_push_after_commit: false
Read .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:
- Treat them as project-level overrides for this skill's general instructions
- When a skill-context rule conflicts with a general rule written in this SKILL.md, the skill-context rule wins (more specific context takes priority — same principle as nested CLAUDE.md files)
- When there is no conflict, apply both: general rules from SKILL.md + project rules from skill-context
- Do NOT ignore skill-context rules even if they seem to contradict this skill's defaults — they exist because the project's experience proved the default insufficient
- CRITICAL: skill-context rules apply to ALL outputs of this skill — including the commit message format and conventions. If a skill-context rule says "commits MUST follow format X" or "message MUST include Y" — you MUST comply. Generating a commit message that violates skill-context rules is a bug.
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
- Run
git statusto see staged files - Run
git diff --cachedto see staged changes - In ordinary mode, if nothing is staged, show a warning and suggest staging
- In task-bound mode, if nothing is staged, continue to map and selectively stage only the supplied group's proven changes as described below
- Run
-
Resolve Active Plan Context (Read-Only, Optional)
- Resolve active plan using this read-only priority:
@<plan-file-or-directory>argument, when the argument starts with@- branch-based full plan or ultra bundle in
paths.plans - single full plan in
paths.plans, or a single ultra bundle there - fast plan at
paths.plan
- If the argument does not start with
@, keep treating it as commit scope/context. - Legacy
@<plan-file>syntax remains valid; the broader form additionally accepts an ultra directory or itsindex.md. - For branch-based full plan lookup:
- get current branch with
git branch --show-currentwhengit.enabled = true - replace every
/with-to get<branch-stem> - when
workflow.plan_id_format = sequential, useGlobfor bothpaths.plans/[0-9][0-9][0-9][0-9]_<branch-stem>.mdandpaths.plans/[0-9][0-9][0-9][0-9]_<branch-stem>/index.md - Read every directory candidate and retain it only when
index.mdcontains exactly one<!-- aif:plan-mode:ultra --> - use the highest-numbered valid artifact and emit
WARN [aif-commit]when multiple valid candidates exist; if both shapes share the highest prefix, prefer ultra - if no valid sequential match exists, check
paths.plans/<branch-stem>/index.mdthenpaths.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
- get current branch with
- If git mode is off, branch lookup cannot resolve, or no branch-based plan
exists, count root
*.mdfull plans plus direct child*/index.mdentrypoints containing<!-- aif:plan-mode:ultra -->; exclude the resolved fast-plan path and do not count phase files. - Before normalizing an explicit ultra directory or treating an explicit
index.mdas ultra, Read it and require exactly one<!-- aif:plan-mode:ultra -->; otherwise STOP with a plan-integrity error. - An automatically discovered directory entrypoint counts only when it
contains
<!-- aif:plan-mode:ultra -->; ignore unrelated*/index.mdfiles. - If no active plan resolves, or the active plan has neither a classic
## Commit Plannor explicit task-based commit tasks, keep current staged-diff behavior unchanged. - If an active plan resolves, inspect it for both supported structures:
- classic
## Commit Plansection - task-based plan structure with explicit commit tasks such as
Commit changes with message "..."
- classic
- If neither format is found, keep current staged-diff behavior unchanged.
- Never modify the active plan from this command.
- Resolve active plan using this read-only priority:
-
Use Commit Plan Grouping When Available
-
If invoked by
/aif-implementwith 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-implementmay invoke this mode for exactly one group from a classic## Commit Plan, using the explicitclassic-groupmode and supplying the exact resolved plan path, group number/name as written, complete task range, exact planned commit message, task IDs/descriptions and theirFiles:/hunk ownership evidence, plus the currentHANDOFF_MODEvalue. 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
HEADfor the selected group, including staged, unstaged, and untracked changes. Usegit status --porcelain -uallandgit ls-files --others --exclude-standardto 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 Planentry 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:- commit group number/name
- task range, such as
after tasks 1-3ortasks 4-6 - suggested conventional commit message
-
Else if the active plan uses
workflow.plan_structure: task-basedor contains explicit commit tasks in## Tasks, parse task-based commit entries instead:- detect commit tasks using the stable marker
<!-- aif:task-kind:commit -->immediately before the task line - treat the commit task as the commit boundary for the tasks it depends on
- extract the commit message from the task description, for example
Commit changes with message "feat: implement user service" - if the plan is legacy and lacks the marker, use the text fallback only when the task description clearly starts with
Commit changes with message; do not treat ordinary "commit" wording elsewhere as a commit task - use the dependent task chain as the grouped scope for commit intent when the commit task marker/message is clear
- detect commit tasks using the stable marker
-
Read the plan's
## Tasksor## Implementation Taskssection to map task ranges to task descriptions and anyFiles: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 Changetable plus the complete## Task Nspecifications. Reading onlyindex.mdis insufficient. -
If one phase contains tasks from multiple commit groups, use the individual
## Task Nsections 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:
- use staged file paths from
git diff --cached --name-only - use staged hunk evidence from
git diff --cachedwhen a file may span multiple groups - task ranges and
Files:hints are guidance, not executable instructions
- use staged file paths from
-
If 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 ingit diff --name-only. -
When one file spans multiple planned groups, use hunk-level staging (
git add -porgit 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 grouping -
Follow 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 Plansection.
-
-
Run Context Gates (Read-Only)
- Check the resolved architecture and description artifacts (use paths from config) to catch obvious scope/boundary drift
- Check the resolved RULES.md and roadmap artifacts (use paths from config) to catch rule and milestone alignment issues
- Check rules hierarchy (resolved
paths.rules_file+rules.base+ namedrules.<area>) for commit conventions - Missing optional files (
ROADMAP.md,RULES.md) areWARN, not blockers - Never modify context artifacts from this command
- If the user wants a standalone rules-only pass, suggest
/aif-rules-check; keep/aif-commitgate labels atWARN/ERROR
-
Determine 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 tasks
-
Identify Scope
- From file paths (e.g.,
src/auth/→auth) - From argument if provided
- Optional - omit if changes span multiple areas
- From file paths (e.g.,
-
Generate Message
- Keep subject line under 72 characters
- Use imperative mood ("add" not "added")
- Don't capitalize first letter after type
- No period at end of subject
Format
<type>(<scope>): <subject>
<body>
<footer>
Examples
Simple feature:
feat(auth): add password reset functionality
Bug 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 #123
Breaking change:
feat(api)!: change response format for user endpoint
BREAKING CHANGE: user endpoint now returns nested profile object
Behavior
When invoked:
-
Check for staged changes
-
Analyze the diff content
-
Resolve optional active plan context and use either the classic
## Commit Planor explicit task-based commit entries when available -
Run read-only context gates and summarize findings as
WARN/ERROR -
If commit type is
feat/fix/perfand roadmap exists, check milestone linkage; if missing, warn and suggest adding linkage in commit body/footer -
Propose a commit message
- In either task-bound mode, use the exact message verified against the selected saved-plan entry; do not generate or edit a replacement 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. Cancel -
Ordinary mode: use the standard confirmation below:
AskUserQuestion: Proposed commit message: <type>(<scope>): <subject> Options: 1. Commit as is 2. Edit message 3. Cancel -
-
Handle user response:
- In task-bound
HANDOFF_MODE=1, proceed to step 9 with the exact planned message and no prompt. - In task-bound manual mode, Commit this group → proceed to step 9 with the exact planned message; Cancel → stop, do NOT commit.
- In ordinary mode, Commit as is → proceed to step 9; Edit message
→ ask the user for the corrected message via
AskUserQuestion, then return to step 7; Cancel → stop, do NOT commit.
- In task-bound
-
Execute
git commitwith the confirmed message- Before running Git, retain the analyzed staged scope/content and parent HEAD (or unborn state), including unrelated unstaged work. Do not reconfigure or manually duplicate quality checks here; Git runs the installed hooks.
- A failed hook or selected fix-and-stop mode stops the commit workflow. Inspect current HEAD, index and working tree before retrying: determine whether a commit was actually created, preserve fixes and unrelated hunks, then re-analyze the current staged diff. Update the message/confirmation if content or scope changed; reuse existing authorization only when it still covers the actual changes.
- Successful selected fix-and-stage may allow the commit to finish. Inspect the actual created commit against the analyzed scope, report hook changes and check that the message still fits before push handling, even when push is disabled. Unexpected changes require a user decision; never automatically amend, reset, repeat a successful commit or push it to repair the mismatch.
- Never auto-bypass hooks with
--no-verify, disable their environment, or use blanket staging to make a failed hook pass. Suggest/aif-quality-setuponly when the user wants checks/hooks configured; ordinary commits do not run setup. - In task-bound mode, use the exact message verified against the saved plan
and supplied by
/aif-implement; return the resulting commit hash and success or failure explicitly so/aif-implementcan verify and persist task/group state. - For task-bound mode, verify after committing that the commit's complete diff equals the captured selected-group change set: no captured group change is missing and no unrelated change is included. Check paths and hunks/content, not only that committed paths are a subset of planned paths. Leave unrelated changes in the index or worktree untouched. If equality cannot be proven, report failure and do not report the group as committed.
-
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 = truein resolved config:- Skip push prompt entirely
- End workflow after successful local commit
-
Otherwise (default behavior), offer to push:
- Show branch/ahead status:
git status -sb - If the branch has no upstream, use:
git push -u origin <branch> - Otherwise:
git push
AskUserQuestion: Push to remote? Options: 1. Push now 2. Skip push- Push now → execute push command based on upstream status:
- if branch has no upstream →
git push -u origin <branch> - otherwise →
git push
- if branch has no upstream →
- Skip push → end the workflow
- Show branch/ahead status:
If argument provided (e.g., /aif-commit auth):
- Use it as the scope
- Or as context for the commit message
/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.
Important
- Never commit secrets or credentials
- Review large diffs carefully before committing
/aif-commithas no implicit strict mode — context gates are warning-first unless user explicitly requests blocking behavior- Treat the resolved architecture, roadmap, RULES.md, description, and plan artifacts as read-only context in this command
- If no active plan resolves or the active plan has neither a
## Commit Plansection nor explicit task-based commit tasks, keep current staged-diff behavior unchanged. - Classic-group task-bound mode requires one group validated against the exact saved
## Commit Plan; never fall back to ordinary grouping when this mode was requested. - For ordinary (non-task-bound) invocations only, if staged changes contain unrelated work (e.g., a feature + a bugfix, or changes to independent modules), suggest splitting into separate commits:
-
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 grouping -
Handle user response:
- Yes, split as suggested → proceed to step 4
- No, commit everything together → proceed to step 5 (propose single commit message)
- Let me adjust the grouping → ask the user for the adjusted grouping via
AskUserQuestion, then return to step 2 with the new plan
-
Before 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 withgit reset HEAD, then stage and commit each group separately usinggit 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 -porgit 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
-
- NEVER add
Co-Authored-Byor any other trailer attributing authorship to the AI. Commits must not contain AI co-author lines
Version History
-
2.21.0
Current 2026-11-02 19:42
新增共享项目 skill-context 层级以支持更灵活的项目级规则覆盖;增强对 task-based 计划结构下提交任务的识别与支持。
- 2.18.1 2026-08-16 02:39
- 2.17.0 2026-07-24 12:20


