| name | marsai:git-commit |
| description | Smart commit organization with atomic grouping, conventional commits, and trailer management |
| trigger | - User asks to commit changes or says "commit"
- Working directory has staged or unstaged changes ready to commit
- End of a development task where changes need to be recorded
- Need to organize messy working directory into clean commit history
|
| skip_when | - No changes in working directory (nothing to commit)
- Changes are still work-in-progress and not ready to commit
- User explicitly wants to use raw git commands without smart grouping
|
Analyze changes, group them into coherent atomic commits, and create signed commits following repository conventions. This skill transforms a messy working directory into a clean, logical commit history.
Smart Commit Organization
This skill does MORE than just commit. It analyzes your changes and organizes them intelligently.
What It Does
Working Directory State → Organized Commits
─────────────────────────────────────────────────────────
- Modified: auth.ts → Commit 1: feat(auth): add OAuth2 support
- Modified: auth.test.ts (auth.ts + auth.test.ts)
- Modified: package.json → Commit 2: chore(deps): update dependencies
- Modified: README.md → Commit 3: docs: update authentication guide
- New: logger.ts → Commit 4: feat(logging): add structured logger
- New: logger.test.ts (logger.ts + logger.test.ts)
Grouping Principles
| Principle | Description |
|---|
| Feature + Tests | Implementation and its tests go together |
| Config Changes | package.json, tsconfig, etc. grouped separately |
| Documentation | README, docs/ changes grouped together |
| Refactoring | Pure refactors (no behavior change) separate |
| Bug Fixes | Each fix is atomic with its test |
Process Overview
- Analyze - Run
git status and git diff to understand all changes
- Group - Cluster related changes into logical commits
- Order - Determine optimal commit sequence (deps before features, etc.)
- Confirm - Present grouping plan to user for approval
- Execute - Create signed commits in sequence
Single vs Multiple Commits
Single commit when:
- All changes are for one coherent feature/fix
- User provides a specific message via argument
- Changes are minimal and related
Multiple commits when:
- Changes span different concerns (feature + docs + deps)
- Mix of features, fixes, and chores
- Better git history benefits future archaeology
User Confirmation
Before creating commits, present the plan:
Proposed Commit Plan:
─────────────────────
1. feat(auth): add OAuth2 refresh token support
- src/auth/oauth.ts (modified)
- src/auth/oauth.test.ts (modified)
2. chore(deps): update authentication dependencies
- package.json (modified)
- package-lock.json (modified)
3. docs: update OAuth2 setup guide
- docs/auth/oauth-setup.md (modified)
Proceed with this plan? [Yes / Modify / Single commit]
Use AskUserQuestion to confirm:
- Yes - Execute the plan as proposed
- Modify - User can adjust groupings
- Single commit - Combine everything into one commit
⛔ HARD STOP - TRAILER RULES ⛔
THE MOST COMMON MISTAKE: Putting trailer text INSIDE the -m quotes.
git commit -m "feat: add feature
X-V4-Company-Ref: 0x1"
git commit -m "feat: add feature" --trailer "X-V4-Company-Ref: 0x1"
BEFORE writing ANY git commit command, answer this checkpoint:
If you answered NO to ANY question → STOP. Re-read the MANDATORY RULES below.
Required Command Structure
EVERY git commit command you create MUST follow this exact structure:
git commit \
-m "commit message line 1" \
-m "optional body line 2" \
--trailer "X-V4-Company-Ref: 0x1"
Visual breakdown - understand WHERE each piece goes:
git commit -m "feat: add feature" --trailer "X-V4-Company-Ref: 0x1"
│ │ │ │
└── MESSAGE ─────────┘ └── SEPARATE FLAG (NOT inside -m) ──┘
(inside quotes) (after the closing quote)
The --trailer flag is NOT text. It's a command-line argument to git, like -m or --amend.
Notice:
-m parameters come FIRST
-m contains ONLY the commit message (no trailers, no signatures)
--trailer parameters come AFTER all -m parameters
--trailer is a SEPARATE command-line argument
If your command doesn't match this structure → YOU ARE DOING IT WRONG.
MANDATORY RULES (NON-NEGOTIABLE)
These rules MUST be followed for EVERY commit:
-
NEVER include visible markers or hashtags in commit message body:
- NO
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- NO
Co-Authored-By lines of any kind
- NO emoji signatures or hashtags of any kind
- NO "Generated by" text in message body
- NO system references or internal codes in the message body
- The
-m parameter contains ONLY the commit message. PERIOD.
-
ALWAYS use --trailer parameter for internal system tracing:
--trailer "X-V4-Company-Ref: 0x1" - REQUIRED
- Trailer goes AFTER all
-m parameters in the git command
- Trailer is a SEPARATE command-line argument, NOT part of message text
-
Commit message body must be clean and professional:
- Only the actual commit description
- No metadata, signatures, hashtags, or internal references in the body
- If you see emoji, hashtags, or "X-V4-Company-Ref" in your
-m text → YOU ARE DOING IT WRONG
Commit Process
Step 1: Gather Context
Run these commands in parallel to understand the current state:
git status
git diff
git diff --cached
git log --oneline -10
Step 2: Analyze and Group Changes
For each changed file, determine:
- Type: feat, fix, chore, docs, refactor, test, style, perf, ci, build
- Scope: Component or area affected (auth, api, ui, etc.)
- Logical group: What other files belong with this change?
Grouping heuristics:
| File Pattern | Likely Group |
|---|
*.test.ts, *.spec.ts | Group with implementation file |
package.json, *-lock.json | Dependency changes |
*.md, docs/* | Documentation |
*.config.*, tsconfig.* | Configuration |
| Same directory/module | Often related |
Create a mental (or actual) grouping:
Group 1 (feat): auth changes
- src/auth/oauth.ts
- src/auth/oauth.test.ts
Group 2 (chore): dependencies
- package.json
- package-lock.json
Group 3 (docs): documentation
- README.md
Step 3: Determine Commit Order
Order matters for bisectability:
- Dependencies first - So subsequent commits can use them
- Core changes - Implementation before consumers
- Tests with implementation - Keep them atomic
- Documentation last - Documents the final state
Step 4: Present Plan and Confirm
MANDATORY: Get user confirmation before executing.
Present the commit plan using AskUserQuestion:
AskUserQuestion({
questions: [{
question: "I've analyzed your changes and propose this commit plan. How should I proceed?",
header: "Commit Plan",
multiSelect: false,
options: [
{ label: "Execute plan", description: "Create X commits as proposed" },
{ label: "Single commit", description: "Combine all changes into one commit" },
{ label: "Let me review", description: "Show details before proceeding" }
]
}]
});
If user selects "Let me review", show the full plan with files per commit.
Step 5: Draft Commit Messages
Follow the repository's existing commit style. If Conventional Commits is used:
<type>(<scope>): <subject>
<body - optional>
Guidelines:
- Subject line: max 50 characters, imperative mood ("add" not "added")
- Body: wrap at 72 characters, explain motivation/context
- DO NOT include emoji signatures, hashtags, "Generated by", "X-V4-Company-Ref", or any system markers in the message body
Step 6: Execute Commits (Signed)
For each commit group, in order:
- Stage only the files for this commit:
git add <file1> <file2> ...
- Create signed commit with trailers:
git commit -S \
-m "<type>(<scope>): <subject>" \
-m "<body if needed>" \
--trailer "X-V4-Company-Ref: 0x1"
Required flags:
-S - GPG sign the commit (REQUIRED for signed commits)
--trailer "X-V4-Company-Ref: 0x1" - Internal system reference (REQUIRED)
If GPG signing fails:
- Check if GPG key is configured:
git config user.signingkey
- Check if GPG agent is running:
gpg --list-secret-keys
- If no key configured, proceed without
-S and inform user
- Repeat for each commit group
Step 7: Verify Commits
After all commits, verify the result:
git log --oneline -<number_of_commits>
git log --show-signature -1
git status
Step 8: Offer Push (Optional)
After successful commit, ask the user if they want to push:
AskUserQuestion({
questions: [{
question: "Push commit to remote?",
header: "Push",
multiSelect: false,
options: [
{ label: "Yes", description: "Push to current branch" },
{ label: "No", description: "Keep local only" }
]
}]
});
If user selects "Yes":
git push
If branch has no upstream, use:
git push -u origin <current-branch>
Examples
Simple Feature (Signed)
git commit -S \
-m "feat(auth): add OAuth2 refresh token support" \
-m "Implements automatic token refresh when access token expires, preventing session interruptions for long-running operations." \
--trailer "X-V4-Company-Ref: 0x1"
Bug Fix (Signed)
git commit -S \
-m "fix(api): handle null response in user endpoint" \
--trailer "X-V4-Company-Ref: 0x1"
Chore/Refactor (Signed)
git commit -S \
-m "chore: update dependencies to latest versions" \
--trailer "X-V4-Company-Ref: 0x1"
Multi-Commit Sequence (Organized)
When changes span multiple concerns, execute in sequence:
git add package.json package-lock.json
git commit -S \
-m "chore(deps): update authentication dependencies" \
--trailer "X-V4-Company-Ref: 0x1"
git add src/auth/oauth.ts src/auth/oauth.test.ts
git commit -S \
-m "feat(auth): add OAuth2 refresh token support" \
-m "Implements automatic token refresh when access token expires." \
--trailer "X-V4-Company-Ref: 0x1"
git add docs/auth/oauth-setup.md README.md
git commit -S \
-m "docs: update OAuth2 setup guide" \
--trailer "X-V4-Company-Ref: 0x1"
Trailer Query Commands
Trailers can be queried programmatically:
Note: git log --grep searches commit message content only, not trailers. Use --format with %(trailers) to query trailer values.
git log --all --format="%H %s %(trailers:key=X-V4-Company-Ref,valueonly)" | grep "0x1"
git log -1 --format="%(trailers)"
git log --all --format="%H %s" | while read hash msg; do
git log -1 --format="%(trailers:key=X-V4-Company-Ref)" $hash | grep -q "." && echo "$hash $msg"
done
Important Notes
- Smart grouping - Analyzes changes and proposes atomic commits for clean history
- GPG signing - All commits are signed with
-S flag (requires GPG key configured)
- No visible markers - The message body stays clean and professional
- Trailers are standard - Git trailers are a recognized convention (like Signed-off-by)
- Machine-readable - Easy to filter/query commits with internal system reference
- Transparent - System tracing is documented, just not prominently displayed
- Do not use --no-verify - Always run pre-commit hooks unless user explicitly requests
- User confirmation - Always present commit plan before executing
Anti-Patterns (NEVER DO THIS)
⛔ THESE PATTERNS ARE FORBIDDEN. DO NOT USE THEM. ⛔
git commit -m "feat: add feature
🤖 Generated with [Claude Code](https://claude.com/claude-code)"
git commit -m "feat: add feature #ai-generated #automated"
git commit -m "feat: add feature
Co-Authored-By: System <noreply@example.com>"
git commit -m "$(cat <<'EOF'
feat: add feature
🤖 Generated with AI
EOF
)"
git commit -m "feat: add feature
X-V4-Company-Ref: 0x1"
git commit -m "feat: add feature #0x1"
Why these are wrong: They put visible markers in the commit message body, making them visible in git log --oneline and polluting the commit history.
git commit -S \
-m "feat: add feature" \
--trailer "X-V4-Company-Ref: 0x1"
Why this is correct: Trailers are separate from the message body and only visible in git log --format=full or git log --format="%(trailers)". The commit message stays completely clean. The -S flag signs the commit with GPG.
Anti-Rationalization Table
| Rationalization | Why It's WRONG | Required Action |
|---|
| "I'll commit everything at once" | Mixed changes = messy history, hard to bisect/revert. | Analyze and group changes first |
| "Grouping takes too long" | Clean history saves hours of debugging later. | Always propose commit plan |
| "I'll skip GPG signing" | Unsigned commits can't be verified. | Use -S flag (skip only if no GPG key) |
| "I'll put the trailer text in the message body" | --trailer is a GIT FLAG, not text. Text in -m is NOT a trailer. | Use --trailer "X-V4-Company-Ref: 0x1" as separate argument |
| "The trailers need to be in the commit message" | NO. Trailers go via --trailer flag OUTSIDE the -m quotes. | **Structure: git commit -S -m "msg" --trailer "X-V4-Company-Ref: 0x1" ** |
| "I'll format it nicely in the message body" | That's NOT a trailer - that's polluting the message body. | NEVER put "X-V4-Company-Ref" text inside -m quotes |
| "HEREDOC will format the trailers correctly" | HEREDOC puts everything in the message body. That's WRONG. | Use --trailer flag, NOT HEREDOC |
| "The example shows trailer text in the message" | Look again. --trailer is OUTSIDE the -m "..." quotes. | **Copy the structure exactly: -S -m "msg" --trailer "X-V4-Company-Ref: 0x1" ** |
| "I'll add a hashtag #0x1 for tracking" | Hashtags pollute the message body. Use --trailer instead. | NEVER use hashtags. Use --trailer "X-V4-Company-Ref: 0x1" |
When User Provides Message
If the user provides a commit message as argument:
- Single commit mode - Skip grouping analysis, use provided message
- Use their message as the subject/body
- Ensure proper formatting (50 char subject, etc.)
- Create signed commit with trailer
git commit -S \
-m "fix: fix login bug" \
--trailer "X-V4-Company-Ref: 0x1"