Commit Changes
Introduction
Stage and commit the current changes onto a safe working branch. This skill enforces branch discipline: when the current branch is unsafe to commit to (the canonical rules live in step 2 below), it proposes a new fix/, feat/, docs/, etc. branch and switches to it after approval. It works equally well for brand-new work and for additional commits on an existing feature branch. If the user passes push, the branch is pushed upstream after the commit.
Arguments
$ARGUMENTS
Supported arguments:
push — After committing, push the branch upstream (git push -u origin <branch> on first push, otherwise git push).
Main Tasks
1. Assess Current State
- Run
git status to see staged, unstaged, and untracked files.
- Run
git branch --show-current to identify the current branch.
- Run
git diff --stat and git diff --cached --stat to summarise the change footprint.
- If there are no changes to commit (working tree clean, nothing staged) — STOP and tell the user there's nothing to commit. Do not create an empty commit.
- If a merge, rebase, or cherry-pick is in progress (
git status reports it, or .git/MERGE_HEAD / .git/rebase-* / .git/CHERRY_PICK_HEAD exist) — STOP and surface it to the user rather than committing into the middle of that operation.
2. Branch Safety — Never Commit to a Protected or Placeholder Branch
A branch is unsafe to commit to if any of the following hold:
- It is the repository's default branch (resolve with
git symbolic-ref refs/remotes/origin/HEAD --short 2>/dev/null | sed 's@^origin/@@', falling back to git remote show origin | sed -n 's/ *HEAD branch: //p').
- It is a long-standing integration branch by name:
main, master, stable, develop, dev, trunk.
- It is a release branch: matches
release/*, release-*, or is otherwise clearly named release-something (e.g. release-2026.05, releases/v3).
- It is a placeholder / scratch branch generated by the harness or a worktree — specifically the auto-generated
adjective-animal pattern (e.g. wary-cuckoo, lumbar-gorilla, wacky-otter, silent-fox), where the second word is an animal. These exist only to host a session and should not be committed to directly. Be careful not to over-match: legitimate two-word branches like dark-mode, rate-limit, cache-layer, or user-auth are real feature branches, not scratch branches. When a name is ambiguous (two hyphenated words but not clearly adjective-animal), do not assert it is unsafe — instead ask the user "this looks like it might be a generated scratch branch — is it, or is it a real branch you want to commit to?" and proceed on their answer.
If the current branch is unsafe by any of those rules:
- Do NOT commit on the current branch.
- Analyse the changes (diffs from step 1) to understand whether the work is a bug fix or new/extended behaviour.
- Propose a branch name using the conventional prefix that matches the change:
- Bug fix →
fix/<short-description> (e.g. fix/graphql-codegen-missing-types).
- New feature or enhancement →
feat/<short-description> (e.g. feat/add-commit-skill).
- Docs-only, chore, refactor, etc. → mirror the conventional-commit type:
docs/<…>, chore/<…>, refactor/<…>.
- Use a concise kebab-case slug. If the repo has a visible naming convention in
git branch -a or in AGENTS.md / CONTRIBUTING.md, follow that instead.
- Present the proposed branch name to the user and wait for explicit approval (the user may suggest a different name).
- After approval, create and switch to the branch:
git checkout -b <branch-name>. The uncommitted changes carry across automatically.
If the current branch is already a real feature branch (i.e. not in any of the unsafe categories above), continue on it. Do not create a new branch unless the user explicitly asks for one.
3. Stage Changes
- Review what will be staged. Prefer adding files explicitly by path rather than
git add -A or git add ., especially when untracked files are present — this avoids accidentally committing secrets (.env, credentials, key files) or large/generated artefacts.
- If staged changes already exist (the user pre-staged), respect that staging and only add additional files when it's clearly intended.
- Warn the user and require explicit confirmation before staging any file that looks sensitive (
.env*, *secret*, *credential*, *.key, *.pem) or generated/large (node_modules/, build artefacts, dist/, __pycache__/, lockfiles changed unexpectedly).
4. Draft the Commit Message
Follow the repo's conventional-commit style (visible in git log):
- Use a type prefix:
feat:, fix:, refactor:, docs:, test:, chore:, ci:, etc.
- Optional scope in parentheses:
feat(backend): ..., fix(e2e): ....
- Subject line under ~72 characters, imperative mood, no trailing period.
- Focus on the why — what changed in terms of behaviour or capability, not a file list.
- For multi-area changes, add a short body explaining the motivation.
- Respect any repo or harness commit-trailer convention (e.g. a
Co-Authored-By trailer the harness expects to append). Don't strip trailers that are already part of the project's workflow.
- Never write a session-link trailer into the commit — strip it if the harness added one. Some harnesses append a line pointing at the private agent session, e.g.
Claude-Session: https://claude.ai/code/session_… (or any trailer carrying a URL to an agent, chat, or coding session). These leak an internal, usually unshareable URL into the project's permanent — often public — git history, and they reference session state no future reader can open, so they're pure noise at best and a disclosure at worst. This is the one exception to "don't strip trailers" above: if the harness has inserted such a line, remove it before committing, and never author one yourself. Legitimate project trailers (Co-Authored-By, Signed-off-by, Reviewed-by, etc.) still stay.
Inspect the most recent ~20 commits with git log --oneline -20 and mirror the style you see (scope conventions, capitalisation, whether bodies are used). Generic examples:
fix: correct off-by-one in pagination cursor
docs: archive completed specs and extract durable knowledge
feat: add commit skill for safe branch discipline
Present the proposed commit message to the user before committing. Adjust based on feedback.
5. Create the Commit
Run git commit -m "<message>". For multi-line messages, use a HEREDOC:
git commit -m "$(cat <<'EOF'
<subject>
<body>
EOF
)"
Do NOT pass --no-verify — let pre-commit hooks run. If a hook fails:
- Read the hook output carefully.
- Fix the underlying issue (formatting, lint, etc.) rather than bypassing.
- Re-stage the fixed files and create a NEW commit so each fix stays traceable. (Don't reach for
--amend to absorb hook fixes — only amend a commit you deliberately intend to rewrite.)
Run git status after the commit to confirm a clean tree and verify success.
Run git log -1 --stat so the user can see what landed.
6. Push Upstream (only when push argument is provided)
Skip this phase entirely if push was NOT passed.
When push IS provided:
- Re-verify the branch is not unsafe per the rules in step 2 (defence in depth, though step 2 should have prevented this).
- Check whether the branch already tracks a remote:
git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null
- If no upstream exists:
git push -u origin <branch-name>.
- If an upstream exists:
git push.
- Never use
--force or --force-with-lease unless the user explicitly asks for it. Regular git push will fail if the remote has diverged — surface that error to the user instead of overwriting.
- Report the push result and, if a remote URL is configured (
git config --get remote.origin.url), the branch URL the user can open.
Notes
Branch Safety:
- The canonical list of unsafe branches lives in step 2 — that is the single source of truth; don't re-derive it from memory.
- If asked to override the rule, refuse and explain — the user can switch branches themselves first if they truly intend to commit there (in which case this skill no longer applies).
This is a discipline skill — hold the line under pressure. Refusing to commit to a protected branch is the whole point, and the excuses below will appear. None of them change where the commit should land:
| Excuse / pressure |
Reality |
| "It's urgent / it's an emergency, just commit to main." |
Urgency doesn't change where the commit lands. A feat//fix/ branch takes seconds and is just as fast to merge. |
| "Just this once, skip the branch." |
There is no "just once" — the rule exists precisely for the tempting one-off. Propose a branch. |
| "It's a tiny change, the branch is overkill." |
Size is irrelevant to branch safety; a one-line fix on main is still a direct commit to a protected branch. |
"The hook is failing, just use --no-verify." |
Fix the violation instead. Bypassing the hook defeats its purpose. |
"The remote diverged, just --force." |
Never force-push unless the user explicitly asks. Surface the divergence instead. |
Red-flags self-check — if you catch yourself thinking any of these, STOP and re-read step 2:
- "This branch is probably fine to commit to."
- "I'll commit here and sort the branch out later."
- "The user clearly wants this on
main, so the rule doesn't apply."
Secret Hygiene:
- Prefer explicit
git add <path> over wholesale git add -A.
- Warn before staging anything that looks like a secret or credential.
- A session-link trailer (
Claude-Session: / any agent-session URL) is a disclosure too — strip it from the commit message before committing, per step 4.
Hook Discipline:
- Pre-commit hooks exist for good reasons. Fix violations rather than bypassing with
--no-verify.
Idempotency:
- Safe to invoke repeatedly. With no changes to commit, the skill exits cleanly without creating an empty commit.
Expected Outcome
- All staged/unstaged changes that the user wanted to capture are committed on a safe working branch.
- The branch is named meaningfully (existing real feature branch preserved, or a new
fix/<…> / feat/<…> / docs/<…> / etc. name approved by the user).
- The commit message follows the repo's existing conventional-commit style.
- If
push was provided, the branch is pushed upstream.
- Every branch deemed unsafe in step 2 is left untouched in all cases.
1---2name: commit3description: Stages and commits the current changes onto a safe working branch, enforcing branch discipline and optionally pushing upstream. TRIGGER when: the user wants to commit, save, or check in the current changes. DO NOT TRIGGER when: opening a pull request → pr.4---56# Commit Changes78## Introduction910Stage and commit the current changes onto a safe working branch. This skill enforces branch discipline: when the current branch is unsafe to commit to (the canonical rules live in **step 2** below), it proposes a new `fix/`, `feat/`, `docs/`, etc. branch and switches to it after approval. It works equally well for brand-new work and for additional commits on an existing feature branch. If the user passes `push`, the branch is pushed upstream after the commit.1112## Arguments1314<arguments> $ARGUMENTS </arguments>1516**Supported arguments:**1718- `push` — After committing, push the branch upstream (`git push -u origin <branch>` on first push, otherwise `git push`).1920## Main Tasks2122### 1. Assess Current State23241. Run `git status` to see staged, unstaged, and untracked files.252. Run `git branch --show-current` to identify the current branch.263. Run `git diff --stat` and `git diff --cached --stat` to summarise the change footprint.274. If there are no changes to commit (working tree clean, nothing staged) — STOP and tell the user there's nothing to commit. Do not create an empty commit.285. If a merge, rebase, or cherry-pick is in progress (`git status` reports it, or `.git/MERGE_HEAD` / `.git/rebase-*` / `.git/CHERRY_PICK_HEAD` exist) — STOP and surface it to the user rather than committing into the middle of that operation.2930### 2. Branch Safety — Never Commit to a Protected or Placeholder Branch3132A branch is **unsafe to commit to** if any of the following hold:3334- It is the repository's default branch (resolve with `git symbolic-ref refs/remotes/origin/HEAD --short 2>/dev/null | sed 's@^origin/@@'`, falling back to `git remote show origin | sed -n 's/ *HEAD branch: //p'`).35- It is a long-standing integration branch by name: `main`, `master`, `stable`, `develop`, `dev`, `trunk`.36- It is a release branch: matches `release/*`, `release-*`, or is otherwise clearly named `release-something` (e.g. `release-2026.05`, `releases/v3`).37- It is a placeholder / scratch branch generated by the harness or a worktree — specifically the auto-generated **`adjective-animal`** pattern (e.g. `wary-cuckoo`, `lumbar-gorilla`, `wacky-otter`, `silent-fox`), where the second word is an animal. These exist only to host a session and should not be committed to directly. Be careful **not** to over-match: legitimate two-word branches like `dark-mode`, `rate-limit`, `cache-layer`, or `user-auth` are real feature branches, not scratch branches. When a name is ambiguous (two hyphenated words but not clearly `adjective-animal`), do not assert it is unsafe — instead ask the user "this looks like it might be a generated scratch branch — is it, or is it a real branch you want to commit to?" and proceed on their answer.3839If the current branch is unsafe by any of those rules:40411. Do NOT commit on the current branch.422. Analyse the changes (diffs from step 1) to understand whether the work is a bug fix or new/extended behaviour.433. Propose a branch name using the conventional prefix that matches the change:44 - **Bug fix** → `fix/<short-description>` (e.g. `fix/graphql-codegen-missing-types`).45 - **New feature or enhancement** → `feat/<short-description>` (e.g. `feat/add-commit-skill`).46 - **Docs-only, chore, refactor, etc.** → mirror the conventional-commit type: `docs/<…>`, `chore/<…>`, `refactor/<…>`.47 - Use a concise kebab-case slug. If the repo has a visible naming convention in `git branch -a` or in `AGENTS.md` / `CONTRIBUTING.md`, follow that instead.484. Present the proposed branch name to the user and wait for explicit approval (the user may suggest a different name).495. After approval, create and switch to the branch: `git checkout -b <branch-name>`. The uncommitted changes carry across automatically.5051If the current branch is already a real feature branch (i.e. not in any of the unsafe categories above), continue on it. Do not create a new branch unless the user explicitly asks for one.5253### 3. Stage Changes54551. Review what will be staged. Prefer adding files explicitly by path rather than `git add -A` or `git add .`, especially when untracked files are present — this avoids accidentally committing secrets (`.env`, credentials, key files) or large/generated artefacts.562. If staged changes already exist (the user pre-staged), respect that staging and only add additional files when it's clearly intended.573. Warn the user and require explicit confirmation before staging any file that looks sensitive (`.env*`, `*secret*`, `*credential*`, `*.key`, `*.pem`) or generated/large (`node_modules/`, build artefacts, `dist/`, `__pycache__/`, lockfiles changed unexpectedly).5859### 4. Draft the Commit Message6061Follow the repo's conventional-commit style (visible in `git log`):6263- Use a type prefix: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`, `ci:`, etc.64- Optional scope in parentheses: `feat(backend): ...`, `fix(e2e): ...`.65- Subject line under ~72 characters, imperative mood, no trailing period.66- Focus on the *why* — what changed in terms of behaviour or capability, not a file list.67- For multi-area changes, add a short body explaining the motivation.68- Respect any repo or harness commit-trailer convention (e.g. a `Co-Authored-By` trailer the harness expects to append). Don't strip trailers that are already part of the project's workflow.69- **Never write a session-link trailer into the commit — strip it if the harness added one.** Some harnesses append a line pointing at the private agent session, e.g. `Claude-Session: https://claude.ai/code/session_…` (or any trailer carrying a URL to an agent, chat, or coding session). These leak an internal, usually unshareable URL into the project's permanent — often public — git history, and they reference session state no future reader can open, so they're pure noise at best and a disclosure at worst. This is the one exception to "don't strip trailers" above: if the harness has inserted such a line, remove it before committing, and never author one yourself. Legitimate project trailers (`Co-Authored-By`, `Signed-off-by`, `Reviewed-by`, etc.) still stay.7071Inspect the most recent ~20 commits with `git log --oneline -20` and mirror the style you see (scope conventions, capitalisation, whether bodies are used). Generic examples:7273- `fix: correct off-by-one in pagination cursor`74- `docs: archive completed specs and extract durable knowledge`75- `feat: add commit skill for safe branch discipline`7677Present the proposed commit message to the user before committing. Adjust based on feedback.7879### 5. Create the Commit80811. Run `git commit -m "<message>"`. For multi-line messages, use a HEREDOC:8283 ```bash84 git commit -m "$(cat <<'EOF'85 <subject>8687 <body>88 EOF89 )"90 ```91922. Do NOT pass `--no-verify` — let pre-commit hooks run. If a hook fails:93 - Read the hook output carefully.94 - Fix the underlying issue (formatting, lint, etc.) rather than bypassing.95 - Re-stage the fixed files and create a NEW commit so each fix stays traceable. (Don't reach for `--amend` to absorb hook fixes — only amend a commit you deliberately intend to rewrite.)963. Run `git status` after the commit to confirm a clean tree and verify success.974. Run `git log -1 --stat` so the user can see what landed.9899### 6. Push Upstream (only when `push` argument is provided)100101**Skip this phase entirely if `push` was NOT passed.**102103When `push` IS provided:1041051. Re-verify the branch is not unsafe per the rules in step 2 (defence in depth, though step 2 should have prevented this).1062. Check whether the branch already tracks a remote:107 - `git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null`1083. If no upstream exists: `git push -u origin <branch-name>`.1094. If an upstream exists: `git push`.1105. **Never use `--force` or `--force-with-lease`** unless the user explicitly asks for it. Regular `git push` will fail if the remote has diverged — surface that error to the user instead of overwriting.1116. Report the push result and, if a remote URL is configured (`git config --get remote.origin.url`), the branch URL the user can open.112113## Notes114115**Branch Safety:**116117- The canonical list of unsafe branches lives in **step 2** — that is the single source of truth; don't re-derive it from memory.118- If asked to override the rule, refuse and explain — the user can switch branches themselves first if they truly intend to commit there (in which case this skill no longer applies).119120**This is a discipline skill — hold the line under pressure.** Refusing to commit to a protected branch is the whole point, and the excuses below will appear. None of them change where the commit should land:121122| Excuse / pressure | Reality |123|-------------------|---------|124| "It's urgent / it's an emergency, just commit to main." | Urgency doesn't change where the commit lands. A `feat/`/`fix/` branch takes seconds and is just as fast to merge. |125| "Just this once, skip the branch." | There is no "just once" — the rule exists precisely for the tempting one-off. Propose a branch. |126| "It's a tiny change, the branch is overkill." | Size is irrelevant to branch safety; a one-line fix on `main` is still a direct commit to a protected branch. |127| "The hook is failing, just use `--no-verify`." | Fix the violation instead. Bypassing the hook defeats its purpose. |128| "The remote diverged, just `--force`." | Never force-push unless the user explicitly asks. Surface the divergence instead. |129130Red-flags self-check — if you catch yourself thinking any of these, STOP and re-read step 2:131132- "This branch is *probably* fine to commit to."133- "I'll commit here and sort the branch out later."134- "The user clearly wants this on `main`, so the rule doesn't apply."135136**Secret Hygiene:**137138- Prefer explicit `git add <path>` over wholesale `git add -A`.139- Warn before staging anything that looks like a secret or credential.140- A session-link trailer (`Claude-Session:` / any agent-session URL) is a disclosure too — strip it from the commit message before committing, per step 4.141142**Hook Discipline:**143144- Pre-commit hooks exist for good reasons. Fix violations rather than bypassing with `--no-verify`.145146**Idempotency:**147148- Safe to invoke repeatedly. With no changes to commit, the skill exits cleanly without creating an empty commit.149150## Expected Outcome151152- All staged/unstaged changes that the user wanted to capture are committed on a safe working branch.153- The branch is named meaningfully (existing real feature branch preserved, or a new `fix/<…>` / `feat/<…>` / `docs/<…>` / etc. name approved by the user).154- The commit message follows the repo's existing conventional-commit style.155- If `push` was provided, the branch is pushed upstream.156- Every branch deemed unsafe in step 2 is left untouched in all cases.