ring/default/skills/git-commit/SKILL.md
Fred Amaral fa6c4c87e8
docs(frontmatter): create canonical schema to standardize component metadata
feat(hooks): add schema validator and enhance skill generation
refactor(*): align all components with the new frontmatter schema
refactor(commands): replace arguments object with simple argument-hint
refactor(agents): remove invalid version field from agent frontmatter
test(hooks): add unit tests for frontmatter validation and generation
2026-04-06 09:52:28 -07:00

490 lines
16 KiB
Markdown

---
name: ring: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
1. **Analyze** - Run `git status` and `git diff` to understand all changes
2. **Group** - Cluster related changes into logical commits
3. **Order** - Determine optimal commit sequence (deps before features, etc.)
4. **Confirm** - Present grouping plan to user for approval
5. **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.
```bash
# ❌ WRONG - "X-Lerian-Ref" text is INSIDE the -m quotes
git commit -m "feat: add feature
X-Lerian-Ref: 0x1"
# ✅ CORRECT - --trailer is a SEPARATE command-line argument OUTSIDE quotes
git commit -m "feat: add feature" --trailer "X-Lerian-Ref: 0x1"
```
**BEFORE writing ANY git commit command, answer this checkpoint:**
- [ ] Does my `-m "..."` contain ONLY the commit message? (NO trailer text inside)
- [ ] Are `--trailer` flags OUTSIDE and AFTER the `-m` parameter?
- [ ] Is my command structured as: `git commit -m "msg" --trailer "key: value"`?
**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:**
```bash
git commit \
-m "commit message line 1" \
-m "optional body line 2" \
--trailer "X-Lerian-Ref: 0x1"
```
**Visual breakdown - understand WHERE each piece goes:**
```
git commit -m "feat: add feature" --trailer "X-Lerian-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:**
1. **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.**
2. **ALWAYS use `--trailer` parameter for internal system tracing:**
- `--trailer "X-Lerian-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
3. **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-Lerian-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:
```bash
# Check staged and unstaged changes
git status
# View ALL changes (staged and unstaged)
git diff
git diff --cached
# View recent commits for style reference
git log --oneline -10
```
### Step 2: Analyze and Group Changes
**For each changed file, determine:**
1. **Type**: feat, fix, chore, docs, refactor, test, style, perf, ci, build
2. **Scope**: Component or area affected (auth, api, ui, etc.)
3. **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:**
1. **Dependencies first** - So subsequent commits can use them
2. **Core changes** - Implementation before consumers
3. **Tests with implementation** - Keep them atomic
4. **Documentation last** - Documents the final state
### Step 4: Present Plan and Confirm
**MANDATORY: Get user confirmation before executing.**
Present the commit plan using `AskUserQuestion`:
```javascript
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-Lerian-Ref", or any system markers in the message body
### Step 6: Execute Commits (Signed)
**For each commit group, in order:**
1. **Stage only the files for this commit:**
```bash
git add <file1> <file2> ...
```
2. **Create signed commit with trailers:**
```bash
git commit -S \
-m "<type>(<scope>): <subject>" \
-m "<body if needed>" \
--trailer "X-Lerian-Ref: 0x1"
```
**Required flags:**
- `-S` - GPG sign the commit (REQUIRED for signed commits)
- `--trailer "X-Lerian-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
3. **Repeat for each commit group**
### Step 7: Verify Commits
After all commits, verify the result:
```bash
# Show all new commits
git log --oneline -<number_of_commits>
# Verify signatures (if signed)
git log --show-signature -1
# Confirm clean state
git status
```
### Step 8: Offer Push (Optional)
After successful commit, ask the user if they want to push:
```javascript
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":
```bash
git push
```
If branch has no upstream, use:
```bash
git push -u origin <current-branch>
```
## Examples
### Simple Feature (Signed)
```bash
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-Lerian-Ref: 0x1"
```
### Bug Fix (Signed)
```bash
git commit -S \
-m "fix(api): handle null response in user endpoint" \
--trailer "X-Lerian-Ref: 0x1"
```
### Chore/Refactor (Signed)
```bash
git commit -S \
-m "chore: update dependencies to latest versions" \
--trailer "X-Lerian-Ref: 0x1"
```
### Multi-Commit Sequence (Organized)
When changes span multiple concerns, execute in sequence:
```bash
# Commit 1: Dependencies first
git add package.json package-lock.json
git commit -S \
-m "chore(deps): update authentication dependencies" \
--trailer "X-Lerian-Ref: 0x1"
# Commit 2: Feature implementation with tests
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-Lerian-Ref: 0x1"
# Commit 3: Documentation last
git add docs/auth/oauth-setup.md README.md
git commit -S \
-m "docs: update OAuth2 setup guide" \
--trailer "X-Lerian-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.
```bash
# Find all commits with specific X-Lerian-Ref trailer value
git log --all --format="%H %s %(trailers:key=X-Lerian-Ref,valueonly)" | grep "0x1"
# Show all trailers for a commit
git log -1 --format="%(trailers)"
# Filter commits by trailer existence (any value)
git log --all --format="%H %s" | while read hash msg; do
git log -1 --format="%(trailers:key=X-Lerian-Ref)" $hash | grep -q "." && echo "$hash $msg"
done
```
## Important Notes
1. **Smart grouping** - Analyzes changes and proposes atomic commits for clean history
2. **GPG signing** - All commits are signed with `-S` flag (requires GPG key configured)
3. **No visible markers** - The message body stays clean and professional
4. **Trailers are standard** - Git trailers are a recognized convention (like Signed-off-by)
5. **Machine-readable** - Easy to filter/query commits with internal system reference
6. **Transparent** - System tracing is documented, just not prominently displayed
7. **Do not use --no-verify** - Always run pre-commit hooks unless user explicitly requests
8. **User confirmation** - Always present commit plan before executing
## Anti-Patterns (NEVER DO THIS)
**⛔ THESE PATTERNS ARE FORBIDDEN. DO NOT USE THEM. ⛔**
```bash
# ❌ WRONG - emoji or hashtags in message body
git commit -m "feat: add feature
🤖 Generated with [Claude Code](https://claude.com/claude-code)"
# ❌ WRONG - hashtags in message body
git commit -m "feat: add feature #ai-generated #automated"
# ❌ WRONG - Co-Authored-By in message body
git commit -m "feat: add feature
Co-Authored-By: System <noreply@example.com>"
# ❌ WRONG - HEREDOC with markers in message body
git commit -m "$(cat <<'EOF'
feat: add feature
🤖 Generated with AI
EOF
)"
# ❌ WRONG - Trailer text inside -m parameter
git commit -m "feat: add feature
X-Lerian-Ref: 0x1"
# ❌ WRONG - System reference as hashtag in message body
git commit -m "feat: add feature #0x1"
# ❌ WRONG - ANY attempt to include trailers, hashtags, or system markers in message body
# The message body (-m parameter) must ONLY contain the commit description
# NO trailers, NO signatures, NO emoji, NO hashtags, NO system markers of any kind
```
**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.
```bash
# ✅ CORRECT - signed commit with trailer via --trailer parameter
git commit -S \
-m "feat: add feature" \
--trailer "X-Lerian-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-Lerian-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-Lerian-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-Lerian-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-Lerian-Ref: 0x1"` ** |
| "I'll add a hashtag #0x1 for tracking" | Hashtags pollute the message body. Use --trailer instead. | **NEVER use hashtags. Use `--trailer "X-Lerian-Ref: 0x1"`** |
## When User Provides Message
If the user provides a commit message as argument:
1. **Single commit mode** - Skip grouping analysis, use provided message
2. Use their message as the subject/body
3. Ensure proper formatting (50 char subject, etc.)
4. Create signed commit with trailer
```bash
# User says: /ring:commit "fix login bug"
git commit -S \
-m "fix: fix login bug" \
--trailer "X-Lerian-Ref: 0x1"
```