| name | git:commit |
| description | Use when the user asks to create/make/save a commit in ANY language (English/Spanish/paraphrase). Follows Conventional Commits with JIRA ticket detection. |
| metadata | {"version":"1.1","scope":["git","vcs"],"trigger":"User requests creating a new commit, in any language or paraphrase","auto_invoke":"Invoke by INTENT not literal phrase. EN: \"commit\", \"commit my changes\", \"create/make a commit\", \"save as commit\", \"ship this as a commit\". ES: \"haz commit\", \"crea un commit\", \"mete commit\", \"guarda en commit\", \"genera el commit\". Skip for history reads (\"show last commit\", \"what was in commit X\")."} |
| allowed-tools | ["Read","Grep","Glob","Write","AskUserQuestion","Bash(git:*)","Bash(pwd)","Bash(find:*)","mcp__atlassian__jira_get_issue"] |
| model | haiku |
Smart Commit
Dynamic Context (pre-resolved)
- CWD: !
pwd
- Is git repo: !
git rev-parse --is-inside-work-tree 2>/dev/null || echo "__NO_GIT__"
Heavy git context (branch, status, diff, log) is resolved in Step 0 below using git -C <target_path> after the target repo is determined. This avoids frontmatter pre-execution failures when CWD is a workspace, not a repo.
Overview
This skill automates the creation of git commits following the Conventional Commits specification with optional JIRA ticket integration. Analyze local changes, determine commit type and scope, detect breaking changes, and create properly formatted commits automatically.
When to Invoke
Invoke this skill whenever the user asks you to create a commit, in any language or paraphrase. Match by intent, not by literal phrase:
- English: "commit", "commit my changes", "create a commit", "make a commit", "commit this", "save as commit", "let's commit", "ship it as a commit"
- Spanish: "haz commit", "hazme un commit", "commit de esto", "mete commit", "crea un commit", "genera el commit", "guarda en commit", "vamos con el commit"
- Indirect cues: the user pivots to "push this", "ship this", or "save progress" right after changes — confirm intent to commit, then invoke.
Do NOT invoke for history reads or amendments ("show me the last commit", "what was in commit X", "amend the previous commit"). The trigger is creating a new commit on top of working-tree changes.
Configuration
This skill reads config.json from its own directory for project-specific settings:
default_base_branch — Base branch for comparisons (default: "main")
jira_project_prefix — Expected JIRA project prefix for branch detection (optional, e.g., "BUYERS")
workspace — Workspace-aware target resolution. See Step 0 below for the schema and resolution algorithm.
If config.json is not present or has empty values, the skill falls back to auto-detection from git context.
Configuration write-back (opt-in)
The skill may propose updates to config.json (via Write tool) when it learns something new — e.g., discovers repos in a workspace, detects a recurring JIRA prefix, or the user asks to "always" target a specific repo. Write-back is always opt-in: the skill asks via AskUserQuestion before persisting, never overwrites a non-empty value silently, and only modifies its own config.json.
Step 0: Resolve Target Repository
This skill must work in two scenarios: (a) CWD is a git repository (direct mode) and (b) CWD is a workspace containing one or more git repositories nested inside (workspace mode). Resolve the target repo before running any git command.
Inputs:
Resolution algorithm:
- Read
config.json from this skill's directory.
- Repo mode detection: if
Is git repo == true AND workspace.mode != "multi-repo" → set target_path = ".", skip to step 6 (direct mode).
- Workspace mode: resolve target by priority:
a. Explicit user argument — if the user named a repo, match against
known_repos[].name first, else against known_repos[].path, else against any directory at <CWD>/<arg> containing a .git/ entry.
b. workspace.default_target — if non-empty AND the resolved path exists AND contains .git/, use it.
c. Single known repo — if known_repos.length == 1 AND the path is valid, use it.
d. Multiple known repos — call AskUserQuestion listing known_repos[].name as options. Add an "Other / scan again" option.
e. Empty known_repos — scan with find . -maxdepth 2 -name .git -type d 2>/dev/null | grep -v "/worktrees/" | grep -v "/.claude/". Each match's parent directory is a repo. Populate a discovery list with {name: <basename>, path: <relative>}. If exactly one → use it. If many → AskUserQuestion. If none → report "no git repository found" and stop.
- Store the choice in two variables for the rest of the skill:
target_path — relative or absolute path to the repo (input to git -C)
target_owner_repo — owner/repo string for gh (compute via git -C <target_path> remote get-url origin, parse SSH or HTTPS form, e.g., git@github.com:owner/repo.git → owner/repo). Not used by git:commit directly but kept for parity across skills.
- Configuration write-back (opt-in only): if any of these conditions hold, propose a write-back via
AskUserQuestion. Never write silently; never overwrite a non-empty value without explicit confirmation:
- Step 3.e populated new
known_repos from a scan → "Save these N repos to known_repos so I don't re-scan?"
- User chose a repo via 3.d that's not yet in
known_repos → "Add it to known_repos?"
- User chose a repo and the conversation suggests permanence ("always", "default") → "Set as
default_target?"
- The skill detected a recurring JIRA prefix in the last 10 commits and
jira_project_prefix is empty → "Save jira_project_prefix: <PREFIX>?"
On confirmation, use the Write tool to update config.json (preserve all other fields, write the file atomically).
- From this point on, every git command in this skill uses
git -C <target_path> <subcommand>. Never cd <target_path> && git ... — Claude Code's anti-pattern alert blocks compound cd && git even with allowlists.
Anti-patterns:
- 🚫
cd <target_path> && git <cmd> — blocked by Claude Code, prompts user, cannot be silenced.
- 🚫 Pre-resolving git state in frontmatter (
!``) without || echo "__NO_GIT__" — fails skill loading when CWD is not a git repo.
- 🚫 Silently writing to
config.json based on a single signal — always confirm with the user before persisting.
Commit Format
All commits must follow this format:
[JIRA-ID] <type>(<scope>): <description>
[optional body]
[optional footer(s)]
Breaking changes use this format:
[JIRA-ID] <type>(<scope>)!: <description>
Workflow
Quick path: If the branch name does not contain a JIRA-like pattern ([A-Z]+-\d+) AND no JIRA ID is found in recent commits, skip JIRA context enrichment (steps 1-2) and proceed directly to change analysis (step 3).
Step 1: Extract JIRA ID from Branch Name
Extract the JIRA ticket ID from the current git branch name.
Branch naming convention:
<type>/<JIRA-ID>-<description>
Examples:
feature/PROJ-123-user-authentication → PROJ-123
bugfix/PROJ-456-fix-validation → PROJ-456
refactor/APP-789-improve-performance → APP-789
Commands:
git -C <target_path> rev-parse --abbrev-ref HEAD
Extraction pattern:
- Find the first occurrence of uppercase letters followed by hyphen and numbers
- Pattern:
[A-Z]+-[0-9]+
Handle edge case: If no JIRA ID is found in branch name, skip the JIRA ID prefix in the commit message and proceed without JIRA context.
A helper script scripts/branch-to-jira.sh is available for reliable JIRA ID extraction from branch names. Usage: bash scripts/branch-to-jira.sh [branch-name] — returns the JIRA ID or empty string. If no argument is provided, it reads the current branch from git automatically.
Step 2: Fetch JIRA Ticket Information
Once the JIRA ID is extracted, fetch the ticket details to enrich the commit message with context.
Use the JIRA MCP tool:
mcp__atlassian__jira_get_issue
Parameters:
issue_key: The extracted JIRA ID (e.g., "PROJ-456")
fields: "summary,description,issuetype,labels"
Extract relevant information:
- Summary: The ticket title/summary - use this to understand the high-level goal
- Issue Type: Bug, Story, Task, Epic, etc. - helps determine commit type
- Description: Detailed context about what needs to be done
- Labels: Additional context about the feature area
Mapping JIRA Issue Type to Commit Type:
| JIRA Issue Type | Suggested Commit Type | Notes |
|---|
| Bug, Defect | fix | Bug fixes |
| Story, User Story | feat | New features |
| Task | feat or refactor | Depends on the nature of work |
| Technical Debt | refactor | Code improvements |
| Epic | feat | Large features (usually) |
| Spike | docs or refactor | Research work |
How to use JIRA context:
- Use the summary as guidance for the commit description
- Check issue type to help determine the correct commit type
- Review description to understand if it's breaking, adds features, or fixes bugs
- Consider labels for determining scope (e.g., "backend", "api", "domain")
Example:
JIRA ID: PROJ-456
Summary: "Migrate external service integration to v2"
Issue Type: Task
Description: "Update integration with external service to use new v2 API..."
→ This suggests:
- Type: `feat` (new integration version)
- Scope: `infrastructure` (external service integration)
- Description should mention "migrate" and "v2"
Handle errors gracefully:
- If JIRA API call fails (network, permissions, invalid ticket), log a warning and continue without JIRA context
- Do NOT block the commit if JIRA is unavailable
- The git diff analysis should still be the primary source of truth
Step 3: Analyze Local Changes
Analyze the current git diff to understand what has changed.
Commands:
git -C <target_path> diff --name-status
git -C <target_path> diff
git -C <target_path> diff --stat
Analyze the diff output to identify:
- Files changed: Which files were modified, added, or deleted
- Change magnitude: How many lines added/removed
- Change location: Which modules/packages affected (domain, application, infrastructure, api-rest, etc.)
- Change nature: What kind of changes (new features, bug fixes, refactoring, etc.)
Combine with JIRA context:
- The git diff shows WHAT was actually changed in code
- The JIRA ticket shows WHY and the intended outcome
- Use BOTH sources to create an accurate commit message
- If there's a mismatch (e.g., JIRA says "bug" but code shows new features), trust the git diff but consider mentioning the JIRA context
Step 4: Determine Commit Type
Based on the analyzed changes, determine the commit type using these patterns:
| Type | When to Use | Keywords in Changes |
|---|
feat | New functionality or feature | "add", "implement", "introduce", "create" |
fix | Bug fix or error correction | "fix", "resolve", "correct", "repair", "patch" |
refactor | Code restructuring without behavior change | "refactor", "rename", "extract", "move", "simplify" |
docs | Documentation only changes | Changes only to .md files, docstrings, comments |
test | Test additions or modifications | Changes only to test files (*_test.go, *Test.java, *.test.ts, etc.) |
style | Code formatting, no logic change | "format", "style", "lint", whitespace only |
perf | Performance improvements | "cache", "optimize", "performance", "efficient" |
build | Build system or dependencies | Changes to build config (pom.xml, go.mod, package.json, Makefile, etc.) |
ci | CI/CD pipeline changes | Changes to .github/workflows, pipelines |
chore | Maintenance tasks | Configuration updates, cleanup |
Priority when multiple types apply:
- Breaking changes (always mark with '!')
feat (new functionality)
fix (bug fixes)
perf (performance)
refactor (code improvements)
- Other types
Combine git diff analysis with JIRA issue type:
- Start with the JIRA issue type suggestion (from Step 2)
- Validate against the actual code changes in git diff
- Final decision: git diff takes priority, but JIRA provides context
- Example: JIRA says "Task" but code adds new API endpoints → use
feat
Reference: For detailed detection patterns and examples, see commit-patterns.md when needed.
Step 5: Determine Scope
Extract the scope from the changed files to indicate which part of the codebase is affected.
Scope detection strategies:
Strategy 1: By Module (preferred for layered/hexagonal architectures)
- Changes in
domain/ or models/ → domain
- Changes in
application/ or services/ → application
- Changes in
infrastructure/ or adapters/ → infrastructure
- Changes in
api/ or controllers/ or routes/ → api
- Changes in
config/ or bootstrap/ → config
Strategy 2: By Domain Concept
- Extract common prefix from changed files:
OrderService.java, OrderRepository.java → order
UserEntity.java, UserMapper.java → user
PaymentProcessor.java, PaymentValidator.java → payment
Strategy 3: By Feature Area
- Authentication-related files →
auth
- Validation-related files →
validation
- Security-related files →
security
Strategy 4: Multiple Scopes
- If changes affect multiple unrelated areas, either:
- Omit scope entirely
- Use the most significant scope
- Consider this indicates multiple commits might be needed
Examples:
domain/entities/Order.java → scope: domain or order
api-rest/controllers/UserController.java → scope: api or user
infrastructure/repositories/ProductRepositoryImpl.java → scope: infrastructure or product
Consider JIRA labels for scope:
- If JIRA ticket has labels like "backend", "api", "infrastructure", use them to validate scope
- Labels can help when changes span multiple modules
Step 6: Detect Breaking Changes
Identify if the changes include breaking changes that require the '!' marker.
Breaking change indicators:
- Removed public API methods or endpoints
- Changed method signatures (parameters, return types)
- Changed API contracts (request/response models)
- Removed or renamed configuration properties
- Changed database schema (breaking migrations)
- Changed behavior that clients depend on
Keywords in diff:
- "remove", "delete" (of public APIs)
- "rename" (for public interfaces)
- "change signature"
- "breaking"
- "incompatible"
If breaking change detected: Add '!' after type and scope:
feat(api)!: remove deprecated endpoint
fix(domain)!: change order status validation
Check JIRA description for breaking change mentions:
- JIRA ticket may explicitly mention "breaking change" or "incompatible"
- Use this as additional signal, but verify with code changes
Step 7: Generate Commit Description
Create a concise, imperative description of the change.
Description guidelines:
- Use imperative mood: "add feature" not "added feature" or "adds feature"
- Start with lowercase letter (exception: proper nouns)
- No period at the end
- Be specific but concise (50 characters or less preferred)
- Focus on WHAT changed, not HOW
Incorporate JIRA summary:
- Use the JIRA summary as inspiration for the description
- Extract key terms from JIRA summary (e.g., "Migrate external service to v2" → "migrate external service integration to v2")
- Combine with git diff insights to be more specific
- Example:
- JIRA: "Update purchase variable integration"
- Git diff: Shows migration from v1 to v2 API
- Result: "migrate external service integration to v2"
Good examples:
add user authentication service
fix null pointer in order validation
refactor payment processing logic
improve query performance with caching
migrate external service integration to v2 (from JIRA + git context)
Bad examples:
Added new stuff (too vague, wrong tense)
Fixed a bug. (too vague, has period)
I have updated the code to use a better algorithm for processing orders (too long, wrong perspective)
Step 8: Create the Commit
Generate the final commit message and create the commit.
Commit message format:
[JIRA-ID] <type>(<scope>): <description>
Examples:
[PROJ-123] feat(domain): add order creation validation
[PROJ-456] fix(api): handle null pointer in user lookup
[APP-789] refactor(infrastructure): simplify repository implementation
[TASK-321] perf(application)!: change caching strategy for performance
Commands to create commit (always with -C from Step 0):
git -C <target_path> status
git -C <target_path> add <file1> <file2> …
git -C <target_path> commit -m "[JIRA-ID] type(scope): description"
git -C <target_path> log -1 --oneline
Important:
- Do NOT include "Co-Authored-By: Claude noreply@anthropic.com" or any references to AI in the commit message
- Do NOT ask for user confirmation, create the commit automatically
- Stage only reviewed files; use
git add . only if all unstaged files have been verified via git status
- Use the exact message format generated
Commit body (optional but recommended for complex changes):
If the change is complex or involves multiple aspects, use the commit body to provide more context:
[JIRA-ID] type(scope): description
- Detail 1 from git diff
- Detail 2 from git diff
- Detail 3 from git diff
Example incorporating JIRA context:
[PROJ-456] feat(infrastructure): migrate external service integration to v2
- Update rest client to use service-rest v2.0.0
- Refactor domain model and mapper for new API contract
- Update repository implementation for v2 endpoints
- Remove deprecated fields from domain model
- Add new configuration properties for v2 endpoints
Step 9: Verify and Report
After creating the commit, verify it was successful and report to the user.
Verification commands:
git -C <target_path> log -1 --format="%h %s"
git -C <target_path> show --stat HEAD
Report to user:
- Confirm commit was created
- Show the commit hash and message
- Show brief statistics of what was committed
Gotchas
- JIRA ID regex: Do not use
[A-Z]+[A-Z]+-[0-9]+ for JIRA ID extraction — it fails on single-letter project keys (e.g., A-123). Always use [A-Z]+-\d+.
- Staging: Do not run
git add . without first reviewing git status — unverified files (.env, credentials, binaries) may be staged accidentally.
- Empty diff: Do not create a commit when
git diff is empty — report "nothing to commit" instead of proceeding.
- AI attribution: Do not include "Co-Authored-By: Claude" or any AI co-authorship lines in the commit message.
- Commit type priority: Do not override the priority order when multiple types apply — breaking changes (
!) always take precedence, then feat, then fix.
- JIRA unavailability: If the JIRA MCP call fails, continue with git diff analysis only — do not block the commit.
Complete Example Workflow
A full end-to-end walkthrough covering branch parsing, JIRA lookup, diff analysis, and commit creation. For the detailed step-by-step execution, see commit-examples.md.
Advanced Scenarios
Covers multiple unrelated changes, breaking changes, missing JIRA IDs, and how JIRA context improves commit messages. For detailed scenarios and examples, see commit-examples.md.
References
- commit-patterns.md - Comprehensive patterns for commit type detection, scope determination, and breaking change identification with real examples
- commit-examples.md - Full end-to-end workflow example and advanced scenario walkthroughs
- git-pull-request - Create a pull request after committing (
git:pull-request)
Best Practices
- Be specific but concise - Describe what changed, not how it was implemented
- Use project conventions - Follow the project's module and directory naming for scopes
- One logical change per commit - If changes are unrelated, suggest separate commits
- Focus on user impact - Describe changes from user/developer perspective
- Detect breaking changes carefully - Only mark as breaking if it truly affects consumers
- Keep scope consistent - Use the same scope naming throughout the project
Anti-patterns to Avoid
- 🚫 Do not use the regex
[A-Z]+[A-Z]+-[0-9]+ for JIRA ID extraction; use [A-Z]+-[0-9]+
- 🚫 Do not stage files with
git add . without first running git status to review
- 🚫 Do not include AI co-authorship lines in the commit message
- 🚫 Do not commit when
git diff is empty — report "nothing to commit" instead
- 🚫 Do not override the commit-type priority order when multiple types apply
Notes
- This skill operates in "local mode" using git commands directly
- No user confirmation is required - analyze and commit automatically
- All changes are staged with
git add . before committing
- JIRA ID in branch names is optional; if not found, the
[JIRA-ID] prefix is omitted from the commit message
- For multi-module projects, prefer module-based scopes (domain, application, infrastructure)
- JIRA integration is optional: If JIRA API is unavailable or fails, the skill continues with git diff analysis only
- Git diff is the source of truth: JIRA provides context and suggestions, but actual code changes determine the final commit type and scope
- The JIRA MCP tool (
mcp__atlassian__jira_get_issue) requires proper authentication and network access to Jira instance