Group your tracked git changes into logical commits with Conventional-Commits messages, written by Claude. Nothing is committed until you approve.
Installs as the command commit (the shorter gca is taken by oh-my-zsh's git plugin).
- Bun >= 1.2 (runs the TypeScript/TSX sources directly — no build step). The UI is built with OpenTUI (React in the terminal), which currently requires Bun.
- The
claudeCLI on yourPATH
chmod +x src/index.ts
ln -s "$PWD/src/index.ts" /opt/homebrew/bin/commit # or ~/bin/commitcommit # collect changes, propose commits, review, then commit
commit --dry-run # show the plan and the git commands; change nothing
commit --apply # skip the review gate and commit the proposed plan (-a)
commit --verbose # add a short body to each commit (-v; default: subject-only)
commit --model claude-opus-4-8 # plan with a specific model (default: claude-sonnet-4-6)
commit --demo # drive the UI with canned fixtures — no tokens, no git
commit --demo list # list the available demo scenarios
commit --help--demo runs the real interactive UI against built-in fixtures — no claude
call (zero tokens), no real git (nothing is committed), and near-instant. It's
for developing and eyeballing the UI without burning tokens on throwaway
commits. Pick a scenario with commit --demo <name> (default, single,
many, renames, long); commit --demo list shows them. A small artificial
delay keeps the planning spinner visible — set COMMIT_DEMO_DELAY=0 (ms) to
remove it. bun run demo is a shortcut for commit --demo.
Model, effort, and verbose can also be changed inside the picker (press c),
then regenerated without restarting — see Review gate.
Your model, effort, and verbose choices persist between runs, validated
with zod and stored via conf. There are two locations:
- The app store — where in-app picker changes are saved by default. It
lives at conf's platform-native config path (on macOS,
~/Library/Preferences/gitcommit-ai/settings.json). - An optional override file at
~/.config/gitcommit-ai/settings.json(honoursXDG_CONFIG_HOME) — hand-editable, Ghostty-style. The app writes it only if it already exists (create it yourself to opt in); its keys win over the app store. Once it exists, picker changes are saved into it.
Precedence is CLI flag / env var > override file > app store > built-in
default. Only the keys you actually set need to appear in the override file —
missing keys fall through to the app store, then the defaults. An invalid value
(e.g. a bad effort) is ignored without discarding the rest of the file.
Because saved verbose feeds the initial plan, turning it on once means every
later run gets bodies from the start (not just after a regenerate).
Planning runs claude as a fast one-shot, not a full agent session:
- Model defaults to
sonnet(good quality, ~7s). Override per-run with--model <m>or globally withCOMMIT_MODEL=<m>. Note: on some accountshaikuis routed slower thansonnet, so faster-sounding isn't always faster. - Low reasoning effort (
--effort low) is the biggest lever — the default (high) reasoning makes planning take ~3× longer for no real benefit here. Override withCOMMIT_EFFORT=medium|highfor trickier groupings. - No MCP servers are loaded (
--strict-mcp-config), and a minimal system prompt replaces Claude Code's default — both cut startup and token overhead. - Output is kept small: subject-only by default (use
-v/--verbosefor bodies), minified fence-free JSON, and the diff is capped (~12k chars) so a large staged change doesn't balloon the request.
While Claude plans the commits, a live status bar (spinner + elapsed seconds) animates on stderr — shown only on a TTY, so piping stays clean.
On a terminal, the proposed commits open in an interactive picker. The focused commit is highlighted; move between them and accept them one at a time:
settings: sonnet · low · subject-only
❯ Commit 1
feat: add greeting
files: hello.txt
Commit 2
docs: update readme
files: readme.md
↑/↓ move · enter accept · a all · e edit · s skip · r regen all · R regen one · c settings · q quit
↑/↓(ork/j) — move focusenter— commit the focused commit now, then continue with the resta— accept and commit all remainings— skip (drop the focused commit without committing)e— edit the focused commit's whole message line, including the tag — changefeat(review): xtofeat(upgrade): x, orfeattodocs. The suggestion is pre-filled and editable;entersaves,esccancels and goes backR— regenerate just the focused commit's message (keeps its files)r— regenerate all commits → chooseg(regroup from scratch) orm(keep the current groups, rewrite each message)c— open the settings pane:↑/↓pick a field,←/→change it (modelsonnet/opus/haiku,effortlow/medium/high,verboseon/off),esccloses. Changes are staged — pressr/Rafterwards to regenerate with them.q/Ctrl-C— quit (commits already made stay)
When stdin is piped (not a TTY), it falls back to a simple line-based prompt.
- Considers tracked modified/deleted/renamed files only (no untracked files).
- Groups whole files into commits (no hunk-level splitting).
- Claude only produces a plan; all
git add/git commitruns locally after approval.
Written in TypeScript + React (OpenTUI), run directly by Bun (no build step).
Source is organized by concern under src/ — core/ is pure logic, git/ is
the only code that talks to git, ai/ calls Claude, tui/ is the React
terminal UI (components + the reducers that drive them), and review-gate.ts
is the plain-text path for pipes.
bun install # deps: @opentui/core, @opentui/react, react (+ typescript)
bun test # bun:test over test/*.test.ts
bun run typecheck # tsc --noEmit (strict)
bun run demo # the picker on canned fixtures — no tokens, no git