
Commit
- 143 installs
- 213 repo stars
- Updated August 4, 2026
- yonatangross/orchestkit
Craft atomic conventional commits with clear scopes and messages while implementing features in orchestkit-driven agent workflows.
About
Orchestkit commit skill guides agents and developers to produce small, reviewable commits with consistent conventional messages and scopes. It enforces atomic diffs, links work to tickets, and keeps history readable for bisect, changelog generation, and safer rollbacks across SaaS and API repos.
- conventional commit format
- atomic change grouping
- scope-aware messages
- clean git history
- agent workflow handoff
Commit by the numbers
- 143 all-time installs (skills.sh)
- Ranked #189 of 733 Git & Pull Requests skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yonatangross/orchestkit --skill commitAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 143 |
|---|---|
| repo stars | ★ 213 |
| Last updated | August 4, 2026 |
| Repository | yonatangross/orchestkit ↗ |
What it does
Craft atomic conventional commits with clear scopes and messages while implementing features in orchestkit-driven agent workflows.
Files
Smart Commit
Simple, validated commit creation. Run checks locally, no agents needed for standard commits.
Note: If disableSkillShellExecution is enabled (CC 2.1.91), the git repository check won't run. This skill requires a git repository.Quick Start
/ork:commit
/ork:commit fix typo in auth moduleArgument Resolution
COMMIT_MSG = "$ARGUMENTS" # Optional commit message, e.g., "fix typo in auth module"
# If provided, use as commit message. If empty, generate from staged changes.
# $ARGUMENTS[0] is the first token (CC 2.1.59 indexed access)STEP 0: Choose Commit Mode (AskUserQuestion — M118 #1465)
Default is "new commit", but voice-flow needs explicit choice when amend / push / stash is wanted:
# Skip when a flag in the invocation makes the mode unambiguous:
# /ork:commit --amend → skip, mode=amend
# /ork:commit --push → skip, mode=new+push
# /ork:commit --stash → skip, mode=stash-first
# ORK_COMMIT_DEFAULT_MODE=new (or amend|push|stash) → skip, use env value
#
# Otherwise, ask:
AskUserQuestion(questions=[{
"question": "How should this commit land?",
"header": "Commit mode",
"options": [
{"label": "New commit (default)", "description": "Create a new commit, leave HEAD intact"},
{"label": "Amend HEAD", "description": "Fold staged changes into the last commit (LOCAL ONLY — refuses if HEAD is published)"},
{"label": "New commit + push", "description": "Commit then `git push` (refuses on protected branches)"},
{"label": "Stash first", "description": "Stash unrelated working-tree changes, then commit only what was already staged"}
]
}])Mode-specific guards:
- Amend HEAD — verify HEAD is not on origin (
git rev-list HEAD..origin/<branch>empty); if it is published, refuse and recommend "New commit" instead. - New commit + push — re-check the protected-branch rule from Phase 1 before pushing; if HEAD's branch is
main/master/dev, abort. - Stash first —
git stash push -k -m "ork:commit autostash"(keep-index), commit, thengit stash popafter push success.
Workflow
Phase 1: Pre-Commit Safety Check
# CRITICAL: Verify we're not on dev/main
BRANCH=$(git branch --show-current)
if [[ "$BRANCH" == "dev" || "$BRANCH" == "main" || "$BRANCH" == "master" ]]; then
echo "STOP! Cannot commit directly to $BRANCH"
echo "Create a feature branch: git checkout -b issue/<number>-<description>"
exit 1
fiPhase 2: Run Validation Locally
Run every check that CI runs:
# Backend (Python)
poetry run ruff format --check app/
poetry run ruff check app/
poetry run mypy app/
# Frontend (Node.js)
npm run format:check
npm run lint
npm run typecheckFix any failures before proceeding.
Phase 3: Review Changes
git status
git diff --staged # What will be committed
git diff # Unstaged changesPhase 3b: Agent Attribution (automatic)
Before committing, check for the branch activity ledger at .claude/agents/activity/{branch}.jsonl. If it exists and has entries since the last commit, include them in the commit message:
1. Read .claude/agents/activity/{branch}.jsonl (one JSON object per line) 2. Filter entries where ts is after the last commit timestamp (git log -1 --format=%cI) 3. Skip agents with duration_ms < 5000 (advisory-only agents go in PR, not commits) 4. Add an "Agents Involved:" section between the commit body and the Co-Authored-By trailer 5. Add per-agent Co-Authored-By trailers: Co-Authored-By: ork:{agent} <noreply@orchestkit.dev>
If the ledger doesn't exist or is empty, skip this step — commit normally.
Phase 4: Stage and Commit
CC 2.1.113 idiom: Multi-line Bash with leading# intent:comments now shows the full command in the transcript — prefix complex scripts with a one-line intent comment so future readers (and/recapscans) can grep the transcript for what happened without re-reading the diff.
# intent: stage the hook change + its test + built artifacts
# Stage files
git add <files>
# Or all: git add .
# Commit with conventional format (with agent attribution if ledger exists)
git commit -m "<type>(#<issue>): <brief description>
- [Change 1]
- [Change 2]
Agents Involved:
backend-system-architect — API design + data models (2m14s)
security-auditor — Dependency audit (0m42s)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ork:backend-system-architect <noreply@orchestkit.dev>
Co-Authored-By: ork:security-auditor <noreply@orchestkit.dev>"
# Verify
git log -1 --statCC 2.1.183 — `attribution.sessionUrl`: In web and Remote Control sessions, CC appends a claude.ai session link to commit/PR attribution. Setattribution.sessionUrl: false(/config attribution.sessionUrl=false) to omit it — useful for public repos where the session link should not leak. TheCo-Authored-Bytrailers above are unaffected.
Handoff File
After successful commit, write handoff:
Write(".claude/chain/committed.json", JSON.stringify({
"phase": "commit", "sha": "<commit-sha>",
"message": "<commit-message>", "branch": "<branch>",
"files": [<staged-files>]
}))Commit Types
| Type | Use For |
|---|---|
feat | New feature |
fix | Bug fix |
refactor | Code improvement |
docs | Documentation |
test | Tests only |
chore | Build/deps/CI |
Quick Rules
1. Run validation locally - Don't spawn agents to run lint/test 2. NO file creation - Don't create MD files or documentation 3. One logical change per commit - Keep commits focused 4. Reference issues - Use #123 format in commit message 5. Subject line < 72 chars - Keep it concise
Quick Commit
For trivial changes (typos, single-line fixes):
git add . && git commit -m "fix(#123): Fix typo in error message
Co-Authored-By: Claude <noreply@anthropic.com>"Verification Gate
Before committing, apply the 5-step gate: Read("${CLAUDE_PLUGIN_ROOT}/skills/shared/rules/verification-gate.md"). Run tests fresh. Read the output. Only commit if tests pass. "Should be fine" is not evidence.
Related Skills
ork:create-pr: Create pull requests from commitsork:review-pr: Review changes before committingork:fix-issue: Fix issues and commit the fixesork:issue-progress-tracking: Auto-updates GitHub issues with commit progress
Rules
Each category has individual rule files in rules/ loaded on-demand:
| Category | Rule | Impact | Key Pattern |
|---|---|---|---|
| Atomic Commits | ${CLAUDE_SKILL_DIR}/rules/atomic-commit.md | CRITICAL | One logical change per commit, atomicity test |
| Branch Protection | ${CLAUDE_SKILL_DIR}/rules/branch-protection.md | CRITICAL | Protected branches, required PR workflow |
| Commit Splitting | ${CLAUDE_SKILL_DIR}/rules/commit-splitting.md | HIGH | git add -p, interactive staging, separation strategies |
| Conventional Format | ${CLAUDE_SKILL_DIR}/rules/conventional-format.md | HIGH | type(scope): description, breaking changes |
| History Hygiene | ${CLAUDE_SKILL_DIR}/rules/history-hygiene.md | HIGH | Squash WIP, fixup commits, clean history |
| Issue Reference | ${CLAUDE_SKILL_DIR}/rules/issue-reference-required.md | HIGH | Reference issue #N in commits on issue branches |
| Merge Strategy | ${CLAUDE_SKILL_DIR}/rules/merge-strategy.md | HIGH | Rebase-first, conflict resolution, force-with-lease |
| Stacked PRs | ${CLAUDE_SKILL_DIR}/rules/stacked-pr-workflow.md | HIGH | Stack planning, PR creation, dependency tracking |
| Stacked PRs | ${CLAUDE_SKILL_DIR}/rules/stacked-pr-rebase.md | HIGH | Rebase management, force-with-lease, retargeting |
Total: 9 rules across 8 categories
References
Load on demand with Read("${CLAUDE_SKILL_DIR}/references/<file>"):
| File | Content |
|---|---|
references/conventional-commits.md | Conventional commits specification |
references/recovery.md | Recovery procedures |
Conventional Commits
Format
<type>(<scope>): <description>
[optional body]
[optional footer(s)]Types
| Type | Description | Bumps |
|---|---|---|
feat | New feature for users | MINOR |
fix | Bug fix for users | PATCH |
docs | Documentation only | - |
style | Formatting, no code change | - |
refactor | Code change, no feature/fix | - |
perf | Performance improvement | PATCH |
test | Adding/fixing tests | - |
chore | Build process, deps | - |
ci | CI configuration | - |
revert | Revert previous commit | - |
Breaking Changes
Add ! after type or BREAKING CHANGE: in footer:
feat!: drop support for Node 14
BREAKING CHANGE: Node 14 is no longer supportedScope Examples
feat(auth): add OAuth2 supportfix(api): handle null responsedocs(readme): update install stepsrefactor(core): extract helper functions
Good Examples
feat(#123): add user profile page
- Create ProfilePage component
- Add profile API endpoint
- Include unit tests
Co-Authored-By: Claude <noreply@anthropic.com>fix(#456): prevent XSS in comment display
Sanitize HTML in user comments before rendering.
Co-Authored-By: Claude <noreply@anthropic.com>Git Recovery
Committed to Wrong Branch
# Save work to new branch
git checkout -b issue/<number>-<description>
# Reset original branch
git checkout dev
git reset --hard origin/dev
# Return to feature branch
git checkout issue/<number>-<description>Undo Last Commit (Keep Changes)
git reset --soft HEAD~1Undo Last Commit (Discard Changes)
git reset --hard HEAD~1Amend Last Commit
# Fix message only
git commit --amend -m "new message"
# Add forgotten files
git add forgotten-file.txt
git commit --amend --no-editRevert Published Commit
git revert <commit-hash>
git pushUnstage Files
git restore --staged <file>Discard Local Changes
# Single file
git restore <file>
# All files
git restore .Rule Categories
1. Atomic Commits (atomic) — CRITICAL — 1 rule
The foundational principle: one logical change per commit. Violations make history unusable for bisect, revert, and review.
atomic-commit.md— What makes a commit atomic, detection heuristics, examples
2. Commit Splitting (splitting) — HIGH — 1 rule
When a commit is too large or mixes concerns, how to split it into atomic units.
commit-splitting.md— Interactive staging, hunk splitting, separation strategies
3. Conventional Format (format) — HIGH — 1 rule
Message format rules that enable automated changelog generation and semantic versioning.
conventional-format.md— Type/scope/description format, breaking changes, co-author attribution
4. Issue Reference (issue-ref) — HIGH — 1 rule
When on an issue branch, commit messages must reference the issue number for GitHub auto-linking.
issue-reference-required.md— When to include #N, branch-based detection, soft enforcement via hook
[Rule Name]
[Brief description — 1-2 sentences.]
Incorrect:
// Bad patternCorrect:
// Good patternKey rules:
- [Rule 1]
- [Rule 2]
- [Rule 3]
Reference: [link]
Atomic Commit Rules
A commit is atomic when it contains exactly ONE logical change that can be understood, reviewed, and reverted independently.
The Atomicity Test
A commit is atomic if ALL of these are true:
[x] Does ONE logical thing
[x] Leaves the codebase in a working state (tests pass)
[x] Commit message doesn't need "and" in the title
[x] Can be reverted independently without breaking other features
[x] A reviewer can understand the full change without external contextDetection Heuristics
Directory Spread — Changes spanning unrelated directories signal mixed concerns:
# ATOMIC: Related files in same domain
src/auth/login.ts
src/auth/login.test.ts
src/auth/types.ts
# NOT ATOMIC: Unrelated directories
src/auth/login.ts ← auth feature
src/billing/invoice.ts ← billing feature
config/webpack.config.js ← build configCommit Type Mixing — A single commit shouldn't mix types:
# NOT ATOMIC: feat + fix in one commit
feat: Add user dashboard
fix: Resolve login timeout ← separate commit
# NOT ATOMIC: feat + chore in one commit
feat: Add API caching
chore: Update eslint config ← separate commitFile Count Threshold — More than 10 staged files warrants inspection. Not always wrong, but should be verified:
# OK: 15 files, all test fixtures for one feature
tests/fixtures/user-*.json (15 files)
# NOT OK: 12 files across 6 unrelated modules"And" Test — If describing the commit requires "and", it's two commits:
# Fails "and" test → split it
"Add user authentication AND fix logging format"
# Passes "and" test → atomic
"Add JWT token validation for login endpoint"Common Atomic Patterns
| Pattern | Files | Why Atomic |
|---|---|---|
| Feature + its tests | feature.ts + feature.test.ts | Tests validate the feature |
| Migration + model update | migration.sql + model.ts | Schema change is one concern |
| Refactor across files | Multiple files, same pattern | One refactoring decision |
| Config change | .env.example + config.ts | One configuration concern |
| Dependency update | package.json + package-lock.json | One dependency decision |
Common Non-Atomic Patterns
| Pattern | Problem | Fix |
|---|---|---|
| Feature + unrelated fix | Two concerns | Two separate commits |
| Code change + formatting | Formatting is noise | Format first, then change |
| Multiple features | Can't revert independently | One commit per feature |
| Feature + config change | Different review concerns | Separate unless config IS the feature |
Incorrect — non-atomic commit mixing concerns:
# Mixed commit spanning unrelated areas
git add src/auth/login.ts \
src/billing/invoice.ts \
config/webpack.config.js
git commit -m "feat: Add login AND fix invoice AND update webpack"
# Three unrelated changes - can't revert independently!Correct — atomic commits with single concerns:
# Commit 1: Auth feature + its tests (related)
git add src/auth/login.ts src/auth/login.test.ts
git commit -m "feat(#123): Add JWT token validation for login endpoint"
# Commit 2: Billing feature + its tests (related)
git add src/billing/invoice.ts src/billing/invoice.test.ts
git commit -m "feat(#124): Add invoice generation service"
# Commit 3: Config change (separate concern)
git add config/webpack.config.js
git commit -m "chore: Update webpack for tree shaking"Key Rules
- One logical change per commit — if you say "and", split it
- Tests belong with the code they test — same commit
- Formatting/linting changes are separate commits
- Database migrations go with the code that uses them
- Never mix feature work with unrelated refactoring
Branch Protection Rules
Protected branches are the deployment pipeline. Never commit or push directly to them.
Protected Branches
| Branch | Purpose | Direct Commit | Force Push |
|---|---|---|---|
main | Production-ready code | BLOCKED | BLOCKED |
master | Legacy production | BLOCKED | BLOCKED |
dev | Integration branch | BLOCKED | BLOCKED |
release/* | Release candidates | BLOCKED | BLOCKED |
Branch Naming Convention
# Issue-linked (preferred)
issue/<number>-<brief-description>
issue/123-add-user-auth
# Type-based (when no issue exists)
feature/<description>
fix/<description>
hotfix/<description>Incorrect — Direct commit to main:
git checkout main
git commit -m "quick fix"
git push origin mainCorrect — Feature branch workflow:
git checkout -b fix/issue-123
git commit -m "fix(#123): Resolve auth bug"
git push -u origin fix/issue-123
gh pr create --base mainKey Rules
- Never commit directly to main, dev, or release branches
- Always use feature branches with descriptive names
- All changes reach protected branches through PRs only
- Force push is only allowed on your own feature branches with
--force-with-lease - Delete feature branches after merge
Commit Splitting Strategies
When you have mixed changes in your working directory, use these strategies to create atomic commits.
Strategy 1: Interactive Staging (git add -p)
Stage changes hunk-by-hunk to separate concerns:
# Stage changes interactively
git add -p
# Options at each hunk:
# y - stage this hunk
# n - skip this hunk
# s - split into smaller hunks (if hunk has gaps)
# e - manually edit the hunk boundaries
# q - quit, leave remaining unstaged
# Review what's staged vs unstaged
git diff --staged # Will be committed
git diff # Won't be committed
# Commit the staged portion
git commit -m "feat(#123): Add user validation"
# Repeat for next logical change
git add -p
git commit -m "fix(#456): Resolve timeout in auth"Strategy 2: File-Based Splitting
When changes are in separate files, stage by file:
# Stage only auth-related files
git add src/auth/login.ts src/auth/login.test.ts
git commit -m "feat(#123): Add login validation"
# Stage only billing-related files
git add src/billing/invoice.ts src/billing/invoice.test.ts
git commit -m "feat(#124): Add invoice generation"Strategy 3: Stash-Based Splitting
For complex mixed changes, use stash to isolate:
# Stash everything
git stash
# Apply and stage only what you need
git stash pop
git add -p # Stage only feature A
git stash # Re-stash the rest
git commit -m "feat: Feature A"
# Recover remaining changes
git stash pop
git add -p # Stage feature B
git commit -m "feat: Feature B"Strategy 4: Pre-Commit Formatting Split
Always format BEFORE making logical changes:
# Step 1: Format first (separate commit)
npx prettier --write src/
git add -A
git commit -m "style: Format files with prettier"
# Step 2: Now make your logical changes
# ... edit files ...
git add -p
git commit -m "feat(#123): Add user dashboard"When to Split
| Signal | Action |
|---|---|
git diff --staged shows > 10 files | Review if all related |
| Commit message needs "and" | Split into separate commits |
| Changes span > 3 unrelated directories | Split by directory/concern |
| Mix of feat + fix + chore | One commit per type |
| Formatting mixed with logic changes | Format first, then logic |
Incorrect — staging everything at once, mixed concerns:
# Staging all files including mixed changes
git add .
git commit -m "feat: Add login and fix billing and update config"
# Unreviewable, can't revert parts!Correct — interactive staging for separate atomic commits:
# Stage auth changes interactively
git add -p src/auth/login.ts
# y - stage login validation hunks
# n - skip other hunks
git add src/auth/login.test.ts
git commit -m "feat(#123): Add login validation"
# Stage billing changes interactively
git add -p src/billing/invoice.ts
git add src/billing/invoice.test.ts
git commit -m "fix(#456): Resolve invoice calculation bug"
# Stage config separately
git add config/webpack.config.js
git commit -m "chore: Update webpack config"Key Rules
- Use
git add -pas the default — stage interactively, notgit add . - Format changes always go in their own commit
- Test files go with the code they test, not in separate commits
- When in doubt, split — smaller commits are always safer
- Each commit should pass tests independently
Conventional Commit Format
All commits must follow the Conventional Commits specification for automated tooling.
Format
<type>(<scope>): <description>
[optional body]
[optional footer]
Co-Authored-By: Claude <noreply@anthropic.com>Types
| Type | When | Bumps |
|---|---|---|
feat | New feature or capability | MINOR |
fix | Bug fix | PATCH |
refactor | Code restructuring, no behavior change | — |
docs | Documentation only | — |
test | Adding or fixing tests | — |
chore | Build, deps, CI, tooling | — |
style | Formatting, whitespace, semicolons | — |
perf | Performance improvement | PATCH |
ci | CI/CD configuration | — |
build | Build system changes | — |
Scope
Optional, identifies the area of change:
# Issue reference (preferred)
feat(#123): Add user authentication
# Module name
fix(auth): Resolve token expiration
# No scope (acceptable for small changes)
chore: Update dependenciesBreaking Changes
Use ! after type/scope OR BREAKING CHANGE: footer:
# With ! marker (bumps MAJOR)
feat(api)!: Change authentication endpoint structure
# With footer
feat(api): Change auth endpoints
BREAKING CHANGE: /api/auth/login now requires email instead of usernameTitle Rules
[x] Imperative mood ("Add feature" not "Added feature")
[x] No period at end
[x] < 72 characters (< 50 preferred)
[x] Lowercase after colon
[x] Meaningful — describes WHY, not just WHATIncorrect:
Fixed the bug. # Past tense, period, no type
feat: stuff # Vague
feat: Add user authentication and fix billing # Two concerns
FEAT: Add Auth # UppercaseCorrect:
feat(#123): Add JWT token validation for login
fix(#456): Resolve race condition in payment processing
refactor: Extract database connection pool to shared moduleBody (Optional)
Use for context that doesn't fit in the title:
git commit -m "$(cat <<'EOF'
feat(#123): Add rate limiting to API endpoints
Applied token bucket algorithm with 100 req/min per user.
Redis-backed for distributed deployments.
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"Key Rules
- Type is mandatory — no untyped commits
- Scope with issue number when available (
#123) - Title < 72 chars, imperative mood, no period
- One type per commit — if you need
featANDfix, make two commits - Always include
Co-Authored-Bywhen Claude assists - Breaking changes must use
!orBREAKING CHANGE:footer
History Hygiene Rules
A clean git history makes debugging (bisect), code review, and onboarding dramatically easier.
Before Pushing: Clean Up
# Squash WIP commits before pushing
git rebase -i HEAD~3
# In the editor:
pick abc1234 feat(#123): Add user validation
fixup def5678 WIP: more validation
fixup ghi9012 fix typoFixup Commits (During Development)
git commit --fixup HEAD # Auto-squash into previous
git commit --fixup HEAD~2 # Auto-squash into specific commit
# Before pushing, auto-squash all fixups
git rebase -i --autosquash HEAD~5What to Squash
| Squash | Keep Separate |
|---|---|
| WIP commits | Each logical feature |
| "Fix typo" after feature | Bug fixes (different concern) |
| "Address review feedback" | Refactoring (different intent) |
| Multiple attempts at same thing | Test additions (reviewable unit) |
Incorrect — Dirty WIP history:
abc1234 WIP
def5678 fix
ghi9012 more fixesCorrect — Cleaned history:
git rebase -i --autosquash HEAD~4
# Result: One clean commit
abc1234 feat(#123): Add user validation with edge case handlingKey Rules
- Clean up history before pushing — squash WIP and fixup commits
- Each commit in final history should be meaningful and atomic
- Use
--fixupduring development,--autosquashbefore pushing - Never rewrite published history (commits others have pulled)
Issue Reference Required
When on an issue branch (issue/*, fix/*, feat/*), commit messages MUST reference the issue number using #N format.
Why
- Links commits to issues automatically in GitHub
- Enables automated issue closing via
Closes #NorFixes #N - Provides traceability for code review and auditing
Good Examples
# Issue number in scope
git commit -m "fix(#42): resolve null pointer in auth handler"
# Issue number in body
git commit -m "feat(auth): add OAuth2 support
Implements #42"
# Closing reference
git commit -m "fix(api): validate input length
Closes #42"Bad Examples
# No issue reference on an issue branch
git commit -m "fix: resolve null pointer in auth handler"
# Issue number without # prefix
git commit -m "fix(42): resolve null pointer"When to Apply
- Always when the branch name contains an issue number (e.g.,
issue/42-fix-auth,fix/42-null-pointer) - Recommended for any branch linked to a known GitHub issue
- Skip for branches unrelated to issues (e.g.,
chore/update-deps)
Incorrect — missing issue reference on issue branch:
# On branch: issue/42-fix-auth
# No issue reference - breaks traceability!
git commit -m "fix: resolve null pointer in auth handler"Correct — issue reference in commit message:
# On branch: issue/42-fix-auth
# Issue number in scope
git commit -m "fix(#42): resolve null pointer in auth handler"
# Or in body
git commit -m "fix(auth): resolve null pointer in auth handler
Fixes #42"Soft Rule
This is a soft rule enforced by the issue-reference-checker hook, which nudges the developer to add the reference. The commit will not be blocked if the reference is missing.
Merge Strategy Rules
Use rebase-first workflow to maintain clean, linear history on feature branches.
Decision Table
| Scenario | Strategy | Command |
|---|---|---|
| Update feature branch with main | Rebase | git rebase origin/main |
| Merge PR into main | Squash merge or merge commit | Via GitHub PR |
| Shared feature branch | Merge (preserve history) | git merge origin/main |
Rebase-First Workflow
git fetch origin
git rebase origin/main
# If conflicts: resolve, stage, continue
git add <resolved-files>
git rebase --continue
# If rebase goes wrong
git rebase --abortForce Push Safety
# SAFE: Force push your own feature branch
git push --force-with-lease origin issue/123-feature
# DANGEROUS: Never force push protected branches
git push --force origin main # NEVER DO THISIncorrect — Merge main into feature:
git checkout feature-branch
git merge origin/main # Creates noisy merge commitsCorrect — Rebase onto main:
git checkout feature-branch
git rebase origin/main
git push --force-with-leaseKey Rules
- Rebase feature branches onto main — don't merge main into feature branches
- Use
--force-with-leaseinstead of--forcefor rebased branches - Resolve conflicts during rebase, not with merge commits
- Test after every conflict resolution
Stacked PR Rebase Management
Keep stacked PR branches synchronized after feedback, merges, or base branch changes.
Incorrect — merging main into feature branches:
git checkout feature/auth-service
git merge main # Creates unnecessary merge commitCorrect — rebase after base PR feedback:
# Rebase dependent branches in order:
git checkout feature/auth-service
git rebase feature/auth-base
git push --force-with-lease
git checkout feature/auth-ui
git rebase feature/auth-service
git push --force-with-leaseAfter base PR merges to main:
git checkout main && git pull origin main
# Retarget PR #2 to main
gh pr edit 102 --base main
# Rebase PR #2 on updated main
git checkout feature/auth-service
git rebase main
git push --force-with-leaseKey rules:
- Always rebase, never merge main into feature branches
- Use
--force-with-lease(never--force) to prevent overwriting others' work - Rebase in dependency order: base first, then each dependent branch
- After a base PR merges, retarget the next PR to
mainviagh pr edit
Stacked PR Workflow
Break large features into small, dependent PRs that merge in sequence.
Incorrect — single massive PR:
# One 1500-line PR that takes days to review
git checkout -b feature/auth
gh pr create --title "feat: Add complete auth system"Correct — stacked PRs with clear dependencies:
# PR 1: User model (base) — targets main
git checkout -b feature/auth-base
gh pr create --base main --title "feat(#100): Add User model [1/3]"
# PR 2: Auth service — targets PR 1's branch
git checkout -b feature/auth-service
gh pr create --base feature/auth-base --title "feat(#100): Add auth service [2/3]"
# PR 3: Login UI — targets PR 2's branch
git checkout -b feature/auth-ui
gh pr create --base feature/auth-service --title "feat(#100): Add login UI [3/3]"Key rules:
- Keep each PR under 400 lines for effective review
- Number PRs clearly:
[1/3],[2/3],[3/3] - Each PR should be independently reviewable and leave tests passing
- Use draft PRs for incomplete stack items
- Do not stack more than 4-5 PRs deep
- Never merge out of order
#!/bin/bash
# Generated by OrchestKit Claude Plugin
# Created: 2026-02-14
# Validate Conventional Commit Message
# Checks commit messages against the Conventional Commits specification.
#
# Usage: ./validate-conventional.sh [OPTIONS]
# echo "feat: add login" | ./validate-conventional.sh
# ./validate-conventional.sh --message "feat: add login"
#
# Options:
# --message MSG Commit message to validate (alternative to stdin)
# --help Show this help message
#
# Exit codes:
# 0 = valid conventional commit
# 1 = invalid commit message
# 2 = usage error (no input provided)
set -euo pipefail
# =============================================================================
# CONFIGURATION
# =============================================================================
# Conventional commit types
VALID_TYPES="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
# Maximum subject line length
MAX_SUBJECT_LENGTH=72
MESSAGE=""
# =============================================================================
# ARGUMENT PARSING
# =============================================================================
while [[ $# -gt 0 ]]; do
case "$1" in
--message)
if [[ -z "${2:-}" ]]; then
echo "Error: --message requires a value" >&2
exit 2
fi
MESSAGE="$2"
shift 2
;;
--help|-h)
echo "Validate Conventional Commit Message"
echo ""
echo "Usage:"
echo " echo \"feat: add login\" | $0"
echo " $0 --message \"feat: add login\""
echo ""
echo "Options:"
echo " --message MSG Commit message to validate"
echo " --help Show this help message"
echo ""
echo "Valid types: ${VALID_TYPES//|/, }"
echo ""
echo "Exit codes:"
echo " 0 = valid conventional commit"
echo " 1 = invalid commit message"
echo " 2 = usage error"
exit 0
;;
*)
echo "Error: Unknown option '$1'. Use --help for usage." >&2
exit 2
;;
esac
done
# Read from stdin if no --message provided
if [[ -z "$MESSAGE" ]]; then
if [[ -t 0 ]]; then
echo "Error: No message provided. Use --message or pipe via stdin." >&2
echo "Run '$0 --help' for usage." >&2
exit 2
fi
MESSAGE=$(cat)
fi
if [[ -z "$MESSAGE" ]]; then
echo "Error: Empty commit message" >&2
exit 1
fi
# =============================================================================
# VALIDATION
# =============================================================================
ERRORS=()
SUBJECT_LINE=$(echo "$MESSAGE" | head -1)
# 1. Check type prefix
if ! echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})(\(.+\))?!?:"; then
ERRORS+=("Missing or invalid type prefix. Valid types: ${VALID_TYPES//|/, }")
fi
# 2. Check colon+space separator
if echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})" && ! echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})(\(.+\))?!?: .+"; then
ERRORS+=("Must have a space after the colon (e.g., 'feat: description')")
fi
# 3. Check subject length
subject_text=$(echo "$SUBJECT_LINE" | sed -E "s/^(${VALID_TYPES})(\([^)]*\))?!?: //")
if [[ ${#SUBJECT_LINE} -gt $MAX_SUBJECT_LENGTH ]]; then
ERRORS+=("Subject line too long (${#SUBJECT_LINE} > ${MAX_SUBJECT_LENGTH} chars)")
fi
# 4. Check for trailing period
if [[ "$SUBJECT_LINE" =~ \.$ ]]; then
ERRORS+=("Subject line should not end with a period")
fi
# 5. Check for uppercase after colon (first letter of description)
if echo "$subject_text" | grep -qE "^[A-Z]"; then
ERRORS+=("Description should start with lowercase letter")
fi
# 6. Check scope format (if present)
if echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})\("; then
scope=$(echo "$SUBJECT_LINE" | sed -E "s/^(${VALID_TYPES})\(([^)]*)\).*/\2/")
if [[ -z "$scope" ]]; then
ERRORS+=("Empty scope in parentheses")
fi
fi
# 7. Check body format (blank line between subject and body)
line_count=$(echo "$MESSAGE" | wc -l | tr -d ' ')
if [[ "$line_count" -gt 1 ]]; then
second_line=$(echo "$MESSAGE" | sed -n '2p')
if [[ -n "$second_line" ]]; then
ERRORS+=("Must have a blank line between subject and body")
fi
fi
# =============================================================================
# OUTPUT
# =============================================================================
if [[ ${#ERRORS[@]} -eq 0 ]]; then
echo "Valid conventional commit"
exit 0
else
echo "Invalid commit message:"
for err in "${ERRORS[@]}"; do
echo " - $err"
done
exit 1
fi
{
"skill": "commit",
"version": "1.0.0",
"testCases": [
{
"id": "conventional-format",
"rule": "conventional-format",
"query": "Commit my authentication changes with a proper message",
"expectedBehavior": [
"Uses conventional commit format: type(scope): description",
"Includes Co-Authored-By trailer in the commit message footer",
"Keeps subject line under 72 characters for readability",
"References issue number with # prefix"
]
},
{
"id": "atomic-commit",
"rule": "atomic-commit",
"query": "I changed the API and updated the docs, commit everything",
"expectedBehavior": [
"Verifies each commit does ONE logical thing",
"Ensures codebase remains working after commit",
"Commit message does not need 'and' in title",
"Each commit can be reverted independently"
]
},
{
"id": "commit-splitting",
"rule": "commit-splitting",
"query": "I have changes to the database schema and the UI, how should I commit?",
"expectedBehavior": [
"Recommends splitting unrelated changes into separate atomic commits",
"Suggests using git add -p for interactive staging",
"Separates unrelated changes into distinct commits",
"Reviews staged vs unstaged changes with git diff"
]
},
{
"id": "quick-commit",
"rule": "conventional-format",
"query": "Fix a typo in the error message",
"expectedBehavior": [
"Uses quick commit pattern for trivial changes",
"Uses fix type prefix for the conventional commit format",
"Includes Co-Authored-By trailer appended to commit metadata",
"Does not spawn agents for simple changes"
]
},
{
"id": "branch-protection",
"rule": "atomic-commit",
"query": "Commit directly to main branch",
"expectedBehavior": [
"Verifies commit is atomic and does not mix unrelated changes on protected branches",
"Refuses to commit to main or dev branches",
"Suggests creating a feature branch first",
"Uses issue/<number>-<description> branch naming convention for traceability"
]
},
{
"id": "issue-reference-required",
"rule": "issue-reference-required",
"query": "I'm committing code for issue #42 but I keep forgetting to add the issue reference. What's required?",
"expectedBehavior": [
"Requires issue number reference in every commit message using the hash-number prefix format",
"Formats commit as type(#42): description following conventional commit with issue reference",
"Warns that commits without issue references break traceability and auto-close linking",
"Enables automatic issue-to-commit linking for progress tracking and audit trail purposes"
]
}
]
}