Generate git commit messages using AI — the only dependency-light, hook-chain-compatible tool that doesn't stomp on your workflow.
- 2 production dependencies. No bloat. Competitors ship 12–20+ transitive deps; commai ships chalk and commander.
- Hook chain compatible. Works with husky, commitlint,
.git/hooks/. Most tools overwrite your hooks; commai chains to them. - AI errors don't block. Network timeout? API down? Exit 0. Your commit proceeds. No friction.
- Multi-provider. Claude and OpenAI. Model name tells us which API to hit—no config wiring needed.
- Native fetch, no SDKs. Explicit HTTP calls over bloated SDK clients. Fast, predictable, lean.
Requires Node 18+.
# Global (recommended)
npm install -g @luctst/commai
# Per-project
npm install --save-dev @luctst/commai
pnpm add -D @luctst/commai# Claude (Anthropic)
export ANTHROPIC_API_KEY=sk-ant-...
# OpenAI
export OPENAI_API_KEY=sk-...Or store in ~/.commai/.env or .env (project root) to persist across sessions. See Environment Variables for details.
cd your-project
commai install --model sonnet@latestStores config to .commai/.config, chains to husky/.git/hooks/, sets core.hooksPath.
git add .
git commitInteractive prompt:
Generated commit message:
────────────────────────────────────────
feat: add user authentication
────────────────────────────────────────
(a) Accept
(r) Regenerate
(c) Cancel
>
- a — Accept and commit
- r — Regenerate with optional custom instructions
- c — Cancel; edit and retry
Graceful: No staged changes? User message already typed? Merge/amend context? commai skips generation. Your workflow, uninterrupted.
Most AI commit tools pull in 12–20+ transitive packages. commai uses two: chalk (color output) and commander (CLI parsing). That's it.
Why it matters: smaller attack surface, faster installs, fewer breakage vectors when deps update.
Your repo likely already has hooks. husky, commitlint, custom scripts in .git/hooks/. commai chains to them instead of replacing:
.commai/prepare-commit-msg
├─ Run `commai generate`
├─ Then check `.husky/prepare-commit-msg`
└─ Then check `.git/hooks/prepare-commit-msg`
If commai isn't installed, those tools still run. If you uninstall commai, they continue working. No cleanup, no breakage.
Network timeout? API rate-limit? Invalid key? commai logs the error and exits 0. Your commit still proceeds. You're never stuck.
This is intentional. AI is best-effort—comments, linting, tests all block commits; message generation shouldn't.
Pass --model sonnet@latest or --model gpt-4-turbo. commai infers the provider from the model name:
sonnet,haiku,opus→ Anthropic APIgpt,o→ OpenAI API
No separate config, no API URL wiring, no provider plugins. The model string tells us everything.
commai uses fetch directly instead of @anthropic-sdk/sdk or openai. Fewer layers, explicit HTTP, faster debugging. You can read the source and understand exactly what's hitting the API.
Only the key for your chosen provider is required. commai infers the provider from the model family in --model.
| Variable | Required for | Description |
|---|---|---|
ANTHROPIC_API_KEY |
Claude models | Anthropic API key (starts with sk-ant-). Get one here. |
OPENAI_API_KEY |
OpenAI models | OpenAI API key (starts with sk-). Get one here. |
commai loads environment variables in this order (shell always wins):
~/.commai/.env— global, applied first (lower precedence).envin your project root — applied second, overrides global- Shell environment — always wins over both
Example ~/.commai/.env (global, covers all your projects):
ANTHROPIC_API_KEY=sk-ant-abc123...
OPENAI_API_KEY=sk-xyz789...Example project .env (project-specific override):
ANTHROPIC_API_KEY=sk-ant-project-specific...Install the prepare-commit-msg hook and write the runtime config to .commai/.config.
commai install --model sonnet@latest
commai install --model haiku@latest --interactive --auto-commitOptions:
| Flag | Default | Description |
|---|---|---|
--model <model> |
Required | Model to use, in <family>@<version> format (e.g., sonnet@latest, haiku@4.0.25). See Model Selection. |
--interactive |
true |
Show the accept/regenerate/cancel prompt on each commit. |
--auto-commit |
false |
Run git commit -m '<message>' automatically after accepting. |
Effects:
- Creates
.commai/directory at repo root - Writes
.commai/prepare-commit-msg(marked with# managed-by-commai) - Writes
.commai/.config(JSON) withmodel,interactive,autoCommit, and the previouscore.hooksPathvalue - Sets
git config core.hooksPath .commai - Creates forwarder scripts for all 12 git hooks (chains to
.husky/and.git/hooks/)
To change options (e.g., switch model), re-run commai install --model <new-model>. Do not edit .commai/.config manually.
Idempotent: Running install again safely overwrites the hook if it was created by commai. Exits 1 if .commai/ exists but wasn't created by commai (foreign directory — refuses to overwrite).
Remove the commai hook from the current repository.
commai uninstallEffects:
- Removes
.commai/directory entirely - Restores
core.hooksPathto its previous value, or unsets it if it was previously empty - Preserves user's
.husky/and.git/hooks/directories
Safety: Checks for the # managed-by-commai marker in .commai/prepare-commit-msg. Exits 1 if the marker is absent (refuses to uninstall a foreign hook directory).
Generate a commit message from staged changes. Normally called by the prepare-commit-msg hook; rarely invoked directly.
Arguments:
<file>— Path to the commit message file (usually.git/COMMIT_EDITMSG, provided by git)
All runtime options (model, interactive, autoCommit) are read from .commai/.config. To change them, re-run commai install --model <model> [--interactive] [--auto-commit].
Example:
commai generate .git/COMMIT_EDITMSGExit codes:
0— Success, or non-fatal failure (AI error, network timeout, user cancelled). Commit is never blocked.1— Configuration error (missing API key,commai installnot run, not a git repo, unknown model family).
Models are specified as <family>@<version>. The family determines both the provider and the model series. Raw model IDs are also accepted.
Claude (Anthropic):
| Alias | Description |
|---|---|
sonnet@latest |
Latest Claude Sonnet — best quality |
haiku@latest |
Latest Claude Haiku — fastest and cheapest |
opus@latest |
Latest Claude Opus — highest capability |
haiku@4.0.25 |
Specific Claude version |
claude-3-5-sonnet-20241022 |
Raw model ID |
OpenAI:
| Alias | Description |
|---|---|
gpt@latest |
Latest GPT model |
o@latest |
Latest OpenAI reasoning model (o-series) |
gpt@4-turbo |
Specific GPT version |
gpt-4-turbo |
Raw model ID |
The provider is resolved from the model family — no extra config needed:
| Family | Provider | API key required |
|---|---|---|
sonnet, haiku, opus |
Claude (Anthropic) | ANTHROPIC_API_KEY |
gpt, o |
OpenAI | OPENAI_API_KEY |
- Extract the family from
<family>@<version>(or scan the raw ID for a known family substring) - Look up the provider from the family map above
- Query the provider's
models.list()API and filter by family (case-insensitive) - If
versionislatest, pick the most recently created match; otherwise filter by version string (dots → dashes) - Fall back to the input as-is if no match is found or the API call fails
Claude:
curl https://api.anthropic.com/v1/models \
-H "api-key: $ANTHROPIC_API_KEY" | jq '.data[].id'See the Anthropic models page for up-to-date availability.
OpenAI:
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY" | jq '.data[].id'See the OpenAI models page for up-to-date availability.
[git commit] → [prepare-commit-msg hook]
↓
[commai generate]
├─ Read options from .commai/.config (model, interactive, autoCommit)
├─ Read staged diff via `git diff --cached`
├─ Check: existing user content? (skip if yes)
├─ Check: changes to stage? (skip if no)
├─ Create AI service (resolve model, load API key)
├─ Generate message via AI provider API (Claude or OpenAI)
├─ Interactive prompt (accept/regenerate/cancel)
└─ Write to commit file or run `git commit -m`
↓
[commit proceeds or is cancelled]
commai respects other git tooling by chaining hooks:
.commai/prepare-commit-msg
├─ Run `commai generate`
├─ Then check `.husky/prepare-commit-msg` (run if executable)
└─ Then check `.git/hooks/prepare-commit-msg` (run if executable)
This allows commai to coexist with husky, commitlint, and other pre-commit tooling.
- Don't delete
.commai/— Runcommai uninstallinstead - Don't edit
.commai/— Hook scripts and.commai/.configare auto-generated. To change options, re-runcommai install --model <model> - Safe to delete:
.git/hooks/prepare-commit-msg(if not created by you), or third-party hooks if you're sure they're no longer needed
"ANTHROPIC_API_KEY environment variable is not set" / "OPENAI_API_KEY environment variable is not set"
The hook can't find the API key for the configured model's provider.
Fixes:
- Check which provider your model uses — see the Provider Auto-Detection table
- Check
.envin your project root contains the right key (ANTHROPIC_API_KEYorOPENAI_API_KEY) - Check
~/.commai/.envexists if using a global key - Verify shell environment:
echo $ANTHROPIC_API_KEYorecho $OPENAI_API_KEY - If the
.envis in a shared repo, make sure it's in.gitignoreto avoid committing secrets
The model <family>@<version> didn't match any models in the provider's API.
Fixes:
- Verify the family name — Claude:
sonnet,haiku,opus; OpenAI:gpt,o(case-insensitive) - Check for typos in the version:
latestis the safest default - Check the API key for the correct provider is set and valid
- Use the raw model ID as a fallback (e.g.,
claude-3-5-sonnet-20241022orgpt-4-turbo)
Check if commai is installed:
git config core.hooksPath
# Should output: .commaiIf empty or different, run commai install again.
Also note: commai intentionally skips generation in these cases:
- No staged changes (
git addnothing) - User already typed a message (commai respects manual input)
- Merge/amend/squash commits (special git contexts where auto-generation is risky)
Likely trying to run commai outside a git repository.
# Fix: cd into a git repo
cd /path/to/project
commai installAfter installing, the hook script should be executable.
# Check
ls -l .commai/prepare-commit-msg
# Should show: -rwxr-xr-x (or similar, with x bits set)
# Fix if needed
chmod +x .commai/prepare-commit-msgNetwork issues or API errors. commai logs the error and exits 0 (non-fatal) — your commit will still proceed.
Debug (Claude):
curl https://api.anthropic.com/v1/messages \
-H "api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-3-5-haiku-20241022","max_tokens":100,"messages":[{"role":"user","content":"hi"}]}'Debug (OpenAI):
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","max_tokens":100,"messages":[{"role":"user","content":"hi"}]}'If either call fails, the issue is your API key or network connectivity.
MIT. See LICENSE for full text.
Questions? Check the Troubleshooting section or open an issue on GitHub.