Skip to content

Repository files navigation

gitgist

Turn a range of git commits into release notes your users will actually read. Point gitgist at everything since your last tag and it returns clean, grouped Markdown — written by Claude, with the internal noise stripped out.

Your git commits (v1.4.0…HEAD) → gitgist · Claude reads the range's actual code diff, groups by theme, and filters the noise → release notes as grouped Markdown. No API key — runs on your signed-in claude CLI, or --no-ai for offline grouping.

Why gitgist

  • AI-written, sections that adapt. Claude groups commits into whatever sections fit the actual work — Features, Bug Fixes, Performance, Breaking Changes, … — and rewrites terse commit subjects into user-facing lines.
  • Grounded in the real diff, not the commit log. gitgist reads the actual code change for the range and treats it as the source of truth — so a feature buried under chore: tidy up still gets described, and a claim the code doesn't support gets dropped (how it works).
  • Noise filtered automatically. Refactors, test-only changes, CI tweaks, dependency bumps, and ticket IDs don't make the cut. Lockfiles and build output are kept out of the model's diff budget without hiding that they changed.
  • No API key required. By default gitgist runs on your signed-in claude CLI — zero config. Prefer the API? Set ANTHROPIC_API_KEY.
  • Summarize uncommitted work too. Point it at your staged/unstaged/untracked changes (--staged, --working, …) to preview notes for work that isn't committed yet — or add --commit-message to draft a Conventional Commit message straight from the staged diff.
  • Every bullet can name its commit. --link-commits ends each line with the commit it came from — a link straight to the commit page when your remote is GitHub, GitLab, or Bitbucket (docs).
  • Bring your own template. --template notes.md shapes the output to your team's house style — fixed section set, order, emoji, and per-section AI guidance — via a simple Markdown-with-frontmatter file.
  • Configure once, not per command. Drop a gitgist.config.json in the repo (or a gitgist key in package.json) and CI stops repeating flags (docs).
  • Works offline too. --no-ai groups by Conventional Commit type with no network, no key, and fully deterministic output.
  • Resilient by default. If a provider errors or returns nothing useful for a range that clearly has commits, gitgist retries with a fallback provider/model you choose (--fallback-provider, --fallback-model) and ultimately drops to deterministic grouping — so a release never blocks on one flaky backend.
  • CLI and library. Use the gitgist bin, or call generateReleaseNotes() from your release tooling.
  • Nine pluggable providers, CLI-first. No-key agent CLIs — Claude (claude -p), OpenAI Codex, Google Antigravity (agy), and OpenCode — plus the Anthropic and OpenAI APIs by key, any local OpenAI-compatible endpoint (Ollama / LM Studio), and on-device Apple Foundation Models. --provider auto picks the best one you already have, and never a paid API over a sign-in you own. Cursor is on the way.

See it

AI release notesgitgist v1.0.0..HEAD --title "v1.5.0"

gitgist v1.0.0..HEAD --title v1.5.0 produces grouped Markdown: Breaking Changes (Node 18 dropped), Features (--watch flag, streamed diffs), Performance (cached config ~3x faster startup), Bug Fixes (expired tokens, empty range) — refactor/test/chore commits filtered out.

Every line, traceablegitgist v1.0.0..HEAD --link-commits

gitgist v1.0.0..HEAD --link-commits produces the same grouped Markdown with every bullet ending in a link to the commit it came from — Breaking Changes (Node 18 dropped), Features (--watch flag, streamed diffs), Bug Fixes (expired tokens, empty range), Performance (cached config ~3x), Documentation — each hash a github.com/acme/acme/commit/… URL derived automatically from the origin remote.

Your house style, every releasegitgist v1.0.0..HEAD --template release-notes.md

gitgist v1.0.0..HEAD --template release-notes.md shapes the same commits to a fixed house style: emoji sections in a set order — ⚠️ Breaking Changes (Node 18 dropped), 🚀 Features (streamed diffs, --watch), 🐛 Bug Fixes (empty range), ⚡ Performance (cached config ~3x) — with refactor/test/chore noise filtered out per the template's guidance.

Commit message from your staged diffgitgist --staged --commit-message

gitgist --staged --commit-message reads the staged diff and writes a Conventional Commit message: feat(auth): reject expired tokens during verification, with a wrapped body explaining the exp-claim check and the 401 AuthError it now throws.

Offline modegitgist v1.0.0..HEAD --no-ai

gitgist v1.0.0..HEAD --no-ai groups every commit by Conventional Commit type — Breaking Changes, Features, Bug Fixes, Performance, Documentation, Refactoring, Tests, Chores — deterministically and offline.

Install

npm install -g gitgist     # or: npx gitgist …

Usage

# Release notes from a tag to HEAD
gitgist v2.0 HEAD

# Range form, with a version heading
gitgist v1.4.0..HEAD --title "v1.5.0"

# No range given → from the latest tag (or full history) to HEAD
gitgist

# Summarize uncommitted work (no range)
gitgist --staged          # just the staged diff
gitgist --working         # staged + unstaged + untracked

# Draft a Conventional Commit message from the staged diff
gitgist --staged --commit-message

# Fold pending changes into a range's notes
gitgist v1.4.0..HEAD --untracked

# Use a local model (Ollama / LM Studio) — free, private, no API key
gitgist v1.4.0..HEAD --provider local --model llama3.2

# Retry on a primary error or empty/suspect result with a second provider
gitgist v1.4.0..HEAD --provider local --model llama3.2 --fallback-provider anthropic-api

# Shape the output to your team's template (sections, order, guidance)
gitgist v1.4.0..HEAD --template release-notes.md

# End each bullet with the commit it came from (linked, if the remote is known)
gitgist v1.4.0..HEAD --link-commits

# Offline, no AI — group by Conventional Commit type
gitgist --no-ai

A template is a Markdown file whose headings define the section order and whose optional YAML frontmatter / <!-- comments --> steer the AI — see docs/4-templates.md and the example template.

Flag Description
--staged, --cached Include staged changes (git diff --staged).
--unstaged Include unstaged changes to tracked files (git diff).
--untracked Include untracked (new) files.
--working, --uncommitted Include all uncommitted work (staged + unstaged + untracked).
--format <notes|commit> Output shape: themed notes (default) or a Conventional Commit message.
--commit-message Shorthand for --format commit (requires AI).
--template <file> Shape the notes with a Markdown template (docs).
--no-ai Group commits by Conventional Commit type instead (offline).
--no-diff Skip reading the range's code diff; summarize from commit messages alone (docs).
--max-diff-chars <n> Character budget for diff material — range patch and working-tree diffs alike. Defaults to the provider's own budget, sized to its context window (docs).
--exclude <pathspec> Hold a path's diff body back from the model, on top of the built-in list. Repeatable (docs).
--no-default-excludes Drop the built-in exclude list (lockfiles, dist/, vendor/, …), keeping only your --exclude patterns.
--no-attribution Skip the per-commit file lists that let the model attribute and group changes (docs).
--link-commits End each bullet with the commit it came from — linked when the remote host is known (docs).
--commit-url <template> URL for --link-commits, containing {hash}. Overrides the auto-detected one.
--no-config Ignore gitgist.config.json / package.json#gitgist (docs).
--provider <name> auto | claude-cli | codex | antigravity | gemini | opencode | anthropic-api | openai-api | local | apple (default: auto). gemini is legacy — see below.
--endpoint <url> Base URL for --provider local (default: Ollama's …:11434/v1).
--model <id> Model for the chosen provider — every backend honours it. anthropic-api (default claude-opus-4-8), openai-api ($GITGIST_OPENAI_MODEL, else gpt-5), the agent CLIs (claude-cli/antigravity --model, codex/gemini/opencode -m), or the local model name. Ids aren't portable between providers.
--fallback-provider <name> Retry with this provider when the primary errors or returns an empty/suspect result (docs).
--fallback-endpoint <url> --endpoint for the fallback provider.
--fallback-model <id> --model for the fallback provider.
--language <name|auto> Language hint for the apple provider's prompt (default: system language; auto omits it).
--max-tokens <n> Max output tokens for the anthropic-api provider (default: 16000).
--title <text> Render <text> as a top-level heading above the notes.
--cwd <path> Run against the git repository at <path>.
-h, --help Show help.

Working-tree flags summarize uncommitted changes. With no range they summarize only the pending changes (great for a commit message); with a range they're folded in alongside the commits.

Project config

Pin the settings that belong to the repository instead of repeating flags in every CI job — gitgist.config.json at the repo root, or a gitgist key in package.json:

{
  "exclude": ["*.pb.py", "migrations/*"],
  "provider": "claude-cli",
  "maxDiffChars": 150000,
  "linkCommits": true
}

Command-line flags win over the file; --exclude patterns are appended to its list rather than replacing them. --no-config ignores it. Unknown keys are rejected rather than silently dropped. Full reference: docs/12-config.md.

AI providers & API keys

gitgist prefers zero-config CLI backends that need no API key — the same approach the related tools take with claude -p. The backends that ship today:

  1. claude-cli — your locally installed, signed-in claude CLI. No API key — it reuses the CLI's own auth.
  2. codex / antigravity / opencode — the other signed-in agent CLIs, also no API key (they reuse each CLI's own auth): OpenAI Codex (codex exec), Google Antigravity (agy -p), and OpenCode (opencode run). Select with --provider <name>; pick the model with --model (-m). See docs/5-providers.md.
    gemini is legacy. Google retired the Gemini CLI for Google AI Pro/Ultra and free-tier accounts on 2026-06-18 in favour of Antigravity; --provider gemini still ships (Gemini Code Assist Standard/Enterprise licensees keep access) but individual accounts now get an IneligibleTierError. Use --provider antigravity instead.
  3. anthropic-api — the Anthropic API via the official SDK. Set ANTHROPIC_API_KEY in your environment.
    openai-api — the OpenAI chat-completions API. Set OPENAI_API_KEY (and OPENAI_BASE_URL for Azure or a proxy). Implemented over plain fetch, so it adds no dependency. Mainly for CI, where no interactive CLI sign-in exists — otherwise prefer codex, which reaches the same models with no key.
  4. local — any OpenAI-compatible endpoint (Ollama, LM Studio, llama.cpp, vLLM, …) for free, private, on-device generation. Opt-in with --provider local; configure with --endpoint ($GITGIST_LOCAL_ENDPOINT, default http://localhost:11434/v1) and --model ($GITGIST_LOCAL_MODEL, else the endpoint's first model). No API key.
  5. apple — on-device Apple Foundation Models (macOS 26+ on Apple Silicon with Apple Intelligence). Free, private, no API key. Powered by the apple-fm package, a gitgist dependency that bundles a Developer-ID-signed, notarized helper binary, so it works out of the box — no toolchain required. Point gitgist at a custom helper build with APPLE_FM_BIN. The on-device model runs a language guardrail over the prompt, so gitgist prefixes it with a short Treat the following as <language>: lead-in (default: your system language; override with --language <name|code>, or --language auto to disable it).

With --provider auto (the default), gitgist tries the signed-in agent CLIs first — claude-cli, then codex, antigravity, gemini, opencode — falls back to the hosted APIs when ANTHROPIC_API_KEY or OPENAI_API_KEY is set, and then to on-device Apple Foundation Models when the device and model are available (a no-op when they aren't). The local provider is never auto-selected (so a normal run doesn't probe localhost) — request it explicitly. Force any with --provider <name>. If no provider is available, use --no-ai for offline Conventional Commits grouping.

Graceful degradation. When the chosen provider errors — or returns the empty-notes sentinel for a range that clearly has commits — gitgist treats it as suspect rather than trusting it. If you've configured a fallback (--fallback-provider / --fallback-endpoint / --fallback-model), it retries there first; otherwise (or if that also comes up empty) it falls back to the deterministic --no-ai grouping, warning on stderr. A model id and local endpoint are provider-specific, so they're inherited from the primary only when the fallback is the same provider. See docs/6-fallback.md.

One provider is still planned, and follows the same CLI-first, no-key pattern: Cursor agent (cursor-agent). The API-key fallbacks that used to sit here are settled — OpenAI shipped as openai-api above, and the Google one was dropped as redundant once antigravity covered that vendor without a key. The provider layer is pluggable, and CLI backends share a small createCliProvider() helper.

Choosing a provider

The backends differ in output quality as well as cost, privacy, and latency. As a rule of thumb, larger models categorize and filter noise more reliably:

Provider Quality Cost Privacy Notes
claude-cli / anthropic-api Best CLI: included with your plan · API: per-token Sent to Anthropic Cleanest grouping; Breaking Changes surfaced first; refactor/test/chore noise dropped.
openai-api Not yet measured Per-token Sent to OpenAI The keyed path to OpenAI, for CI where a CLI sign-in isn't possible. No SDK dependency. Prefer codex when you can sign in.
codex / antigravity / opencode Very good Included with your CLI sign-in (no key) Sent to that vendor No-key agent CLIs; quality tracks the underlying model. --model picks it (opencode uses provider/model; antigravity uses agy models ids like Gemini 3.6 Flash (High)).
gemini Legacy. Retired for individual tiers on 2026-06-18; use antigravity. Still works with a Gemini Code Assist Standard/Enterprise license.
local (Ollama / LM Studio) Very good Free On-device Same shape as Claude on a capable model; minor ordering differences, and it may drop a section Claude keeps. Quality tracks the model you load.
apple (Foundation Models) Usable, weaker Free On-device Smallest model, and the most variable run to run — can miscategorize (a fix: under Breaking Changes, chore:/test: under Bug Fixes), keep every internal commit, invent sections, or leave raw feat(ui): prefixes and commit hashes in the bullets. Free, private, fast.
--no-ai Deterministic Free No network Conventional-Commits grouping; keeps every commit, no rewriting. The offline baseline.

Pick by what you care about most: best notes → Claude; private/free with good quality → local with a capable model; private/free/fast on a Mac with nothing to install → apple; reproducible and offline → --no-ai.

See it: the same 10 commits through four backends (one real npm run compare run)

The history mixes real user-facing work (a breaking feat!: drop Node 18, two features, two fixes, a perf win, a docs: commit that adds a quickstart) with internal churn that good notes should drop (a refactor:, a test:, a chore: dep bump). Every commit carries real file content, so these runs are diff-grounded the way gitgist runs by default — the AI backends describe what the code does, not just what the subject line claimed.

All four blocks come from a single run. AI output is non-deterministic, so your own npm run compare will word things differently — the tendencies each backend shows here are the stable part, not the exact prose.

claude-cli (Claude) — tightest. Breaking Changes first, and the bullets name things no commit subject mentions (cursor / limit, the { rows, nextCursor } shape, the 401 AuthError, the debounce) because they come from the diff. The refactor:, test:, and chore: commits are dropped as internal churn:

## Breaking Changes
- Node 18 is no longer supported; Node 20 or newer is required.

## Features
- The list endpoint now takes `cursor` and `limit` options and returns `{ rows, nextCursor }` for cursor-based pagination (default page size 50).
- New dark-mode toggle on the settings page.

## Bug Fixes
- Expired tokens are now rejected with a 401 `AuthError` instead of failing with a 500.
- The sidebar no longer flickers on window resize — resize measurement is debounced.

## Performance
- Compiled regexes are cached, cutting cold-start time by roughly 3x.

## Documentation
- Added a README with a quickstart showing a tag-to-`HEAD` range example.

local (Ollama, gemma4:12b) — close, on a capable model. Same editorial instinct: the same six user-facing changes, the same refactor: / test: / chore: churn dropped. Two differences — Performance lands ahead of Bug Fixes, and it dropped the docs: quickstart too, where Claude kept it as Documentation. The bullets are a step less specific (no option names):

## Breaking Changes
- Minimum supported Node.js version updated to v20.

## Features
- Added a dark mode toggle on the settings page.
- Introduced cursor-based pagination for the list endpoint.

## Performance
- Improved startup performance by caching compiled regular expressions.

## Bug Fixes
- Fixed sidebar flickering when resizing the window.
- Corrected expired token handling to return 401 status codes instead of internal server errors.

apple (on-device Foundation Models) — the smallest model, and it shows. This run filtered nothing (all ten commits survive — chore: and test: among them, under Bug Fixes), filed the fix(auth) commit under Breaking Changes, left the raw feat(ui): / perf: prefixes in the bullets, and appended commit hashes nothing asked for. Free, private, and fast — but read it before you ship it:

## Breaking Changes

- **feat!: drop Node 18; the minimum supported version is now Node 20** (af3127e)
- **fix(auth): reject expired tokens instead of returning a 500** (aaf85a7)

## Features

- **feat(ui): add a dark-mode toggle to the settings page** (bdfb99f)
- **feat(api): add cursor-based pagination to the list endpoint** (27b2aae)
- **docs: expand the quickstart with a tag-to-HEAD example** (1c0fdd8)
- **perf: cache compiled regexes — about 3x faster cold start** (1962afb)
- **refactor: split the loader into smaller modules** (5ae1775)

## Bug Fixes

- **fix: stop the sidebar from flickering on window resize** (5792a6b)
- **chore: bump eslint to v10** (e817147)
- **test: add coverage for the range parser** (01a89db)

--no-ai — deterministic baseline. Keeps every commit verbatim with its hash, no rewriting and no noise-filtering — so the breaking change appears under both Breaking Changes and Features, and the refactor/test/chore commits stay:

## ⚠ BREAKING CHANGES
- drop Node 18; the minimum supported version is now Node 20 (`af3127e`)

## Features
- drop Node 18; the minimum supported version is now Node 20 (`af3127e`)
- **ui:** add a dark-mode toggle to the settings page (`bdfb99f`)
- **api:** add cursor-based pagination to the list endpoint (`27b2aae`)

## Bug Fixes
- stop the sidebar from flickering on window resize (`5792a6b`)
- **auth:** reject expired tokens instead of returning a 500 (`aaf85a7`)

## Performance
- cache compiled regexes — about 3x faster cold start (`1962afb`)

## Refactoring
- split the loader into smaller modules (`5ae1775`)

## Documentation
- expand the quickstart with a tag-to-HEAD example (`1c0fdd8`)

## Tests
- add coverage for the range parser (`01a89db`)

## Chores
- bump eslint to v10 (`e817147`)

Want to judge for yourself? npm run compare runs the same fixed history through every backend available on your machine and prints the results side by side (see scripts/compare-providers.mjs).

Library

import { generateReleaseNotes } from 'gitgist';

// AI-organized notes
const notes = await generateReleaseNotes({
  from: 'v1.0.0',
  to: 'HEAD',
  title: 'v1.1.0',
});
console.log(notes);

// Deterministic, offline grouping (no AI)
const changelog = await generateReleaseNotes({ from: 'v1.0.0', ai: false });

Every stage of the pipeline is exported, so a wrapping tool can reuse gitgist's own rules rather than reimplementing them:

  • Commits and rangesreadCommits, resolveCommitRange, parseCommit.
  • The diff layerreadRangeDiff, readCommitFiles, buildExcludePathspecs. The per-file budget allocation is applied for you when you read a range.
  • Prompt assembly and output cleanup — the prompt builders, cleanModelOutput, stripUnrequestedHashes.
  • Config and argsloadConfig, parseConfig, applyConfig, parseArgs, with the same flag-over-config precedence the CLI uses.
  • ProvidersresolveProvider and the registry, plus the pieces to build your own: createCliProvider for a headless CLI and the shared OpenAI-protocol client (chatCompletion, listModels) for anything speaking that wire format.
  • Deterministic outputbuildChangelog, renderMarkdown.

See docs/ for the architecture and requirements.

Development

npm install
npm test          # unit + integration tests with coverage
npm run lint
npm run typecheck
npm run build
npm run check:features   # every documented behavior has an asserting test
npm run demo      # re-capture the README demo SVGs (assets/demos/)
npm run diagram   # re-capture the README flow diagram (assets/diagram.svg)
npm run compare   # run the same changes through every available provider, side by side

License

MIT © Brian Westphal

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages