Commit Skill
Turns whatever is uncommitted into a small series of well-formed Conventional Commits — one commit per logical change, not one commit for the whole working tree. By default it commits everything modified or new that it safely can, including untracked files; a repo that wants it to stop and confirm instead sets commit.includeUntracked in .eagerworks/commit.json (references/config.md). It reads the repo's own git history to learn its real type/scope vocabulary rather than assuming the full spec is in use, and it never guesses at a genuine judgment call: an ambiguous file gets one question, not a silent decision.
Mutation posture. Committing is the point of this skill, so git add and git commit don't need a separate confirmation once the user has asked for a commit — but the mandate stops there. It never pushes, amends, rebases, resets, or creates a branch; that's create-pr's job once the commits exist (see docs/decision-records/2026-09-07--create-pr-write-posture.md for the precedent this inherits).
Preflight — Do This First
git status --porcelain=v1 --branch # what's changed; also reveals a rebase/merge in progress
git diff # unstaged content — the input to grouping
git diff --staged # a non-empty index is a deliberate signal, not noise
git log --oneline -20 # the repo's real type/scope vocabulary
git log --name-only -20 # whether recent feat/fix commits bundle their test file — --oneline above never shows this
ls .eagerworks/commit.json AGENTS.md CLAUDE.md 2>/dev/null # stated conventions override defaults
If git status shows a rebase, merge, or cherry-pick in progress, stop and say so — this skill doesn't touch that state.
Grouping
The unit is the file — git add -p is interactive and will hang an agent, so a file with two unrelated changes stays together in one commit rather than being split by hunk. Groups are formed by change intent, not by directory: two files in different folders that implement one behavior belong in the same commit, and two unrelated changes in the same folder don't. An already-staged index is never touched — it's committed first, as-is. A new test defaults to its own commit, separate from the implementation it covers, unless recent history clearly shows this repo bundling them. Full ladder, default ordering, and what never gets staged at all: references/grouping.md.
Message Format
<type>(<scope>): <description> — imperative mood, no trailing period, subject capped at 72 characters. Derive the type and scope vocabulary from git log before falling back to the Conventional Commits default set: a repo that only ever uses feat/fix/docs/chore shouldn't start receiving a style: commit. Full spec, scope rules, and body/footer conventions: references/message-format.md.
Reference Files (read these on demand)
| Task |
Read |
| The grouping ladder, default commit ordering, what never gets staged |
references/grouping.md |
| The Conventional Commits spec, vocabulary inference, body and footer rules |
references/message-format.md |
| End-to-end flow: preflight, group, commit, handle hook outcomes, report |
references/workflow.md |
The optional .eagerworks/commit.json config schema |
references/config.md |
Copyable templates live in assets/:
assets/commit.example.json — starter config, with a Rails and a Node example
Critical Gotchas
- Never
git add -A or git add .. Stage explicit paths, one group at a time, so each commit is exactly what its message says it is.
- Never
--no-verify. A hook that rejects the commit stops the run — report the hook's output verbatim rather than bypassing it.
- A hook that rewrites files (formatter, linter
--fix) is not a failure — re-stage the paths it touched and retry that one commit once, then stop if it still fails.
- Never push, amend, rebase,
reset --hard, or create a branch. Committing is the whole mandate; see create-pr for everything after.
- Never
git add -p. It's interactive and will hang the agent — see "Grouping" above.
- Report a partially-failed series honestly. Name the commits that landed and what's still uncommitted; never claim the whole series succeeded when it didn't.
- Never commit
.env, credentials, node_modules, build output, or screenshots. Exclude them from every group and say why — a skip is never silent.
- Nothing to commit means saying so. Never manufacture a change just to have something to commit.
- Commit message language is configured, not inferred. Write in
commit.language (default English) regardless of what language the conversation is in — see references/config.md.
- Pass the message with a HEREDOC (
git commit -F -). Never -m "...\n..." with escaped newlines — it mangles the body and footers.
1---2name: commit3description: Commits everything modified or new in the working tree by default, grouped into a series of coherent Conventional Commits — one commit per logical change, staged by path, with the type/scope vocabulary inferred from the repo's own git history — instead of sweeping everything into a single commit. Configurable per repo to ask before including new files. Use when asked to "commit this", "commit my changes", "commit everything", "make a commit", "split this into commits", or to write a commit message for work already staged.4---56# Commit Skill78Turns whatever is uncommitted into a small series of well-formed [Conventional Commits](https://www.conventionalcommits.org/) — one commit per logical change, not one commit for the whole working tree. By default it commits **everything** modified or new that it safely can, including untracked files; a repo that wants it to stop and confirm instead sets `commit.includeUntracked` in `.eagerworks/commit.json` (`references/config.md`). It reads the repo's own git history to learn its real type/scope vocabulary rather than assuming the full spec is in use, and it never guesses at a genuine judgment call: an ambiguous file gets one question, not a silent decision.910**Mutation posture.** Committing is the point of this skill, so `git add` and `git commit` don't need a separate confirmation once the user has asked for a commit — but the mandate stops there. It never pushes, amends, rebases, resets, or creates a branch; that's `create-pr`'s job once the commits exist (see `docs/decision-records/2026-09-07--create-pr-write-posture.md` for the precedent this inherits).1112## Preflight — Do This First1314```bash15git status --porcelain=v1 --branch # what's changed; also reveals a rebase/merge in progress16git diff # unstaged content — the input to grouping17git diff --staged # a non-empty index is a deliberate signal, not noise18git log --oneline -20 # the repo's real type/scope vocabulary19git log --name-only -20 # whether recent feat/fix commits bundle their test file — --oneline above never shows this20ls .eagerworks/commit.json AGENTS.md CLAUDE.md 2>/dev/null # stated conventions override defaults21```2223If `git status` shows a rebase, merge, or cherry-pick in progress, stop and say so — this skill doesn't touch that state.2425## Grouping2627The unit is the **file** — `git add -p` is interactive and will hang an agent, so a file with two unrelated changes stays together in one commit rather than being split by hunk. Groups are formed by change intent, not by directory: two files in different folders that implement one behavior belong in the same commit, and two unrelated changes in the same folder don't. An already-staged index is never touched — it's committed first, as-is. A new test defaults to its **own** commit, separate from the implementation it covers, unless recent history clearly shows this repo bundling them. Full ladder, default ordering, and what never gets staged at all: `references/grouping.md`.2829## Message Format3031`<type>(<scope>): <description>` — imperative mood, no trailing period, subject capped at 72 characters. Derive the type and scope vocabulary from `git log` before falling back to the Conventional Commits default set: a repo that only ever uses `feat`/`fix`/`docs`/`chore` shouldn't start receiving a `style:` commit. Full spec, scope rules, and body/footer conventions: `references/message-format.md`.3233## Reference Files (read these on demand)3435| Task | Read |36|---|---|37| The grouping ladder, default commit ordering, what never gets staged | `references/grouping.md` |38| The Conventional Commits spec, vocabulary inference, body and footer rules | `references/message-format.md` |39| End-to-end flow: preflight, group, commit, handle hook outcomes, report | `references/workflow.md` |40| The optional `.eagerworks/commit.json` config schema | `references/config.md` |4142Copyable templates live in `assets/`:43- `assets/commit.example.json` — starter config, with a Rails and a Node example4445## Critical Gotchas46471. **Never `git add -A` or `git add .`.** Stage explicit paths, one group at a time, so each commit is exactly what its message says it is.482. **Never `--no-verify`.** A hook that rejects the commit stops the run — report the hook's output verbatim rather than bypassing it.493. **A hook that rewrites files (formatter, linter `--fix`) is not a failure** — re-stage the paths it touched and retry that one commit once, then stop if it still fails.504. **Never push, amend, rebase, `reset --hard`, or create a branch.** Committing is the whole mandate; see `create-pr` for everything after.515. **Never `git add -p`.** It's interactive and will hang the agent — see "Grouping" above.526. **Report a partially-failed series honestly.** Name the commits that landed and what's still uncommitted; never claim the whole series succeeded when it didn't.537. **Never commit `.env`, credentials, `node_modules`, build output, or screenshots.** Exclude them from every group and say why — a skip is never silent.548. **Nothing to commit means saying so.** Never manufacture a change just to have something to commit.559. **Commit message language is configured, not inferred.** Write in `commit.language` (default English) regardless of what language the conversation is in — see `references/config.md`.5610. **Pass the message with a HEREDOC (`git commit -F -`).** Never `-m "...\n..."` with escaped newlines — it mangles the body and footers.