Skip to main content

commitstash

AI-powered git commit message generator — reads your staged diff, writes the commit for you

Python License PyPI


The Problem

Writing good commit messages is tedious. Most developers either:

  • Write vague messages like fix bug or update stuff
  • Spend more time on the message than the actual change
  • Skip conventions entirely under time pressure

The Solution

commitstash reads your staged diff and generates a precise, conventional commit message using Claude or GPT — in under 3 seconds. No API key? Run it fully offline with --no-ai and it builds a message straight from the diff, or point it at a local model with Ollama.

It does more than messages:

  • Blocks secrets — every commit is scanned for API keys, tokens, and credentials in your staged changes. Leaks are stopped before they land.
  • Reviews your diff — commitstash review flags bugs and issues before you commit.
  • Writes your PR — commitstash pr drafts a title and description from your branch's commits and diff.
git add orders/views.py orders/serializers.py

commitstash
Staged (2 files):
  · orders/views.py
  · orders/serializers.py

╭─ Suggested commit message ────────────────────────────────────╮
│ feat(orders): add bulk export endpoint with date range filters │
╰───────────────────────────────────────────────────────────────╯

[Enter] commit   e edit   r regenerate   q quit
>
✓ Committed successfully

Installation

pip install commitstash

Setup

# Anthropic Claude (default)
export ANTHROPIC_API_KEY=sk-ant-...

# Or OpenAI
export OPENAI_API_KEY=sk-...

Add the export to your ~/.zshrc or ~/.bashrc so it persists.

No API key? Skip setup entirely and use offline mode — see No-AI mode below.


Quick Start

# Stage your changes
git add <files>

# Generate and commit
commitstash

That's it. Press Enter to accept, e to edit, r to regenerate, q to quit.


Usage

# Stage everything, then generate
commitstash -a

# Auto-accept without prompting (CI / hooks)
commitstash -a -y

# Change style for one commit
commitstash --style simple
commitstash --style angular

# Add emoji prefix  (✨ feat, 🐛 fix, ♻️ refactor...)
commitstash --emoji

# Include a commit body explaining WHY
commitstash --body

# Switch provider for one commit
commitstash --provider openai

# No API key — generate offline from the diff
commitstash --no-ai

No-AI (offline) mode

Don't have an API key, working offline, or just want zero-cost commits? Add --no-ai and commitstash builds the message locally by analyzing your staged diff — no network, no key, no SDK required.

commitstash --no-ai        # generate offline
commitstash --no-ai -a -y  # stage all, offline, auto-accept

It inspects the diff to pick a sensible message:

What it detects Example output
Brand-new file(s) feat(auth): add login
Docs / README changes docs: update README
Test files test(tests): add test_llm
Config / build files chore: update pyproject
Mostly deletions refactor(api): remove legacy client
File removals chore: remove old_helper

The type (feat/fix/docs/test/chore/refactor), scope (derived from the common directory), and emoji all respect your configured style. It's a heuristic, not a mind reader — press e to tweak anything before committing.

Make it the default so you never pass the flag:

commitstash configure   # choose "local" when prompted for provider

Secret Scanning

Before every commit, commitstash scans your staged changes for secrets — AWS keys, GitHub tokens, Anthropic/OpenAI keys, Slack/Stripe/Google keys, private key blocks, JWTs, and hardcoded password/api_key/token assignments. If it finds one, the commit is blocked and the finding is shown with the secret redacted:

╭──────────────── Secrets detected (1) ────────────────╮
│ AWS access key ID  config.py:12                      │
│     AKIAIOSF…MPLE                                     │
╰──────────────────────────────────────────────────────╯

Only added lines are scanned, so pre-existing secrets in unrelated files don't block you. Obvious placeholders (your_key_here, xxxx, ${VAR}, changeme) are ignored.

Run the scan on its own — it exits non-zero when anything is found, so it drops straight into a pre-commit hook or CI step:

commitstash scan

Turn the automatic commit-time gate off in commitstash configure (or set "scan_secrets": false in your config).


Review

Get a review of your staged diff before you commit:

commitstash review            # AI review with your configured provider
commitstash review --no-ai    # offline pattern checks only

With an AI provider it looks for bugs, security issues, and clear mistakes in the changed lines. Offline mode is deterministic — it flags leftover debug statements (print, console.log, breakpoint()), merge-conflict markers, and new TODO/FIXME comments — and tells you it isn't a correctness review.


Pull Requests

Draft a PR title and description from the commits and diff on your current branch:

commitstash pr                    # base branch autodetected (origin/HEAD, then main/master)
commitstash pr --base develop     # compare against a specific branch
commitstash pr --no-ai            # assemble from commit subjects, no API key

Output is a title plus a ## Summary / ## Changes / ## Testing markdown body — paste it straight into GitHub.


Commit Styles

Style Example output
conventional (default) feat(auth): add JWT refresh token rotation
angular fix(orders): handle null warehouse on bulk export
simple Fix null check in order serializer

Configure

Run the interactive setup to save your preferences:

commitstash configure

Preferences are saved to ~/.commitstash/config.json. API keys are never written to disk — always read from environment variables.

Manual config (~/.commitstash/config.json)
{
  "provider": "anthropic",
  "style": "conventional",
  "include_scope": true,
  "include_body": false,
  "emoji": false,
  "max_diff_lines": 500,
  "scan_secrets": true,
  "ollama_model": "llama3.2",
  "ollama_host": "http://localhost:11434"
}

Providers

Provider Default Model Env Var
anthropic (default) claude-opus-4-8 ANTHROPIC_API_KEY
openai gpt-4o-mini OPENAI_API_KEY
ollama llama3.2 (local LLM) none
local — (offline heuristic) none

Switch permanently:

commitstash configure   # select openai when prompted

Switch for one commit:

commitstash -p openai

Ollama (local LLM)

Run a real model on your own machine — no API key, no network calls off-box:

ollama serve
ollama pull llama3.2

commitstash -p ollama            # one commit
commitstash configure            # choose "ollama"; set model + host

Model and host are configurable (ollama_model, ollama_host).


Git Hook

Install commitstash as a prepare-commit-msg hook so every git commit auto-generates a message:

commitstash install-hook

To uninstall:

rm .git/hooks/prepare-commit-msg

Commit Splitting

Staged everything at once? commitstash split clusters the staged files into logical commits — source changes by scope, then tests, docs, and config — and commits each group with its own generated message:

git add .
commitstash split

Proposed split (3 commits, AI grouping)

  Commit 1 — auth refactor
    · auth/views.py
    · auth/models.py
  Commit 2 — test changes
    · tests/test_auth.py
  Commit 3 — documentation
    · README.md

Create these commits? [y/N] > y
✓ 1/3  refactor(auth): move JWT validation into middleware
✓ 2/3  test(auth): cover middleware token validation
✓ 3/3  docs: document the new auth flow

AI providers propose the grouping from the diff; the response is strictly validated (every staged file in exactly one group) and falls back to deterministic grouping otherwise — --no-ai uses it directly. Splitting is file-level, so a single file's hunks never end up divided across commits. Files with both staged and unstaged edits abort the split rather than silently dragging unstaged work into a commit.


Explain & Changelog

# Plain-language explanation of the staged diff — what, why, impact, risk
commitstash explain

# Changelog section from conventional commits since the last tag
commitstash changelog

# ...or a labelled release, prepended to CHANGELOG.md
commitstash changelog --label v0.3.0 --write

changelog is deliberately deterministic — the same history always produces the same changelog, so it needs no API key and works in CI.

commitstash also reads your recent commit history when generating messages, so suggestions match the tone and scope conventions your repo already uses.


Custom Providers

Backends are pluggable. Anything that can complete a prompt can drive every feature — subclass, register, done:

from commitstash.providers import LLMProvider, register

class GroqProvider(LLMProvider):
    name = "groq"

    def complete(self, prompt, config, max_tokens=1024):
        ...  # call any API you like

register(GroqProvider())

Commands

Command Description
commitstash Generate from staged diff (interactive)
commitstash -a Stage all changes, then generate
commitstash -y Auto-accept first suggestion
commitstash --no-ai Generate offline, no API key needed
commitstash scan Scan staged changes for secrets (exits 1 on findings)
commitstash review Review the staged diff for bugs and issues
commitstash pr Draft a PR title and description for the branch
commitstash split Split staged changes into a series of atomic commits
commitstash explain Explain the staged diff: what, why, impact, risk
commitstash changelog Generate a changelog from conventional commit history
commitstash configure Interactive setup
commitstash install-hook Install as git hook in current repo
commitstash version Show version

License

MIT

Metadata

Release files for commitstash 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for commitstash 0.5.0
File Size Uploaded
commitstash-0.5.0.tar.gz 36.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for commitstash 0.5.0
File Interpreter ABI Platform
commitstash-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 67.5 kB

Release files / commitstash-0.5.0.tar.gz

Download URL commitstash-0.5.0.tar.gz
Size 36.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7d9a22fa6ae3984698ef53203c3e273a2fdf5cf5e6ccdc0672e6f099fbd5f4d6
BLAKE2b-256 checksum
How to use checksums
43cc59709ce4c332f5bbc1f3ef6830c99166751da2206ba22e33247e6eccbfd6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / commitstash-0.5.0-py3-none-any.whl

Download URL commitstash-0.5.0-py3-none-any.whl
Size 31.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e88f6eae66170a2fde7ca792bf30f8b5faf6faf1d6d13216fae6bbad201dd758
BLAKE2b-256 checksum
How to use checksums
f37e47b3ee123edb677feef2777e3b18383c5be96140ce834bc4587dd0ef5ae4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page