Capture the "why" behind every code change.
git-why is a CLI tool that automatically captures AI reasoning traces — the prompts, thinking, and decisions behind code changes — and stores them alongside your source code. It bridges the gap between git blame (which shows who and when) and the context that explains why.
$ git why show src/auth.py
## 2026-04-11 — Add OAuth2 with refresh tokens
### Prompt
> Replace session-based auth with OAuth2, support refresh tokens
### Reasoning
Chose the authorization code flow over implicit grant because we need
refresh tokens for long-lived sessions. Used PKCE to avoid storing
client secrets in the SPA.
### Changes
- Edit src/auth.py — replaced session middleware with OAuth2 handler
- Edit src/config.py — added OAUTH_* environment variables
- Automatic capture — Pre-commit hook silently records reasoning at commit time
- Tool-agnostic — Plugin system supports Claude Code, Cursor, Copilot, Aider, and more
- Per-file traces — Each source file gets its own
.why/<path>.mdwith full history - Session manifests — Optionally store complete AI conversation transcripts
- Git-native — Clean diffs, union merge strategy,
.whyignorepatterns - Zero dependencies — Just
bash(>=3.2),jq, andgit - Cross-platform — macOS, Linux, Windows (Git Bash / WSL)
brew install hexapode/git-why/git-whycurl -fsSL https://raw.githubusercontent.com/hexapode/git-why/main/install.sh | bashgit clone https://github.com/hexapode/git-why
cd git-why
make install# Initialize in your repo
git why init
# That's it — traces are captured automatically on each commit.
# To capture manually:
git why capture
# View traces
git why show src/auth.py
# Search across all traces
git why search "OAuth"git why init creates a .why/ directory and installs a pre-commit hook. From then on, every commit automatically extracts reasoning from your active AI session and records it.
| Command | Description |
|---|---|
git why init |
Set up .why/ directory and install hooks |
git why capture |
Extract traces from the active AI session |
git why capture -m "reason" |
Record a manual (human-written) trace |
git why show <file> |
Display reasoning history for a file |
git why blame <file> |
Git blame annotated with reasoning |
git why log |
Git log with trace indicators |
git why search <query> |
Full-text search across all traces |
git why status |
Show configuration and state |
AI Session (Claude Code, Cursor, …)
↓
provider detects active session
↓
extracts & normalizes conversation
↓
filters reasoning per changed file
↓
writes .why/<path>.md (newest first)
↓
stages .why/ alongside your commit
Traces are plain Markdown files stored in .why/, mirroring your source tree. They're designed to produce clean git diffs (entries are always prepended, never edited) and merge cleanly across branches (union merge strategy).
Each .why/<path>.md file contains entries like:
<!-- why:entry session="abc-123" date="2026-04-11T19:07:51Z" tool="claude-code" spec="1" -->
## 2026-04-11 — Add retry logic to API client
### Prompt
> Make the API client retry on 5xx errors with exponential backoff
### Reasoning
Added retry with exponential backoff (base 1s, max 30s, 3 attempts).
Chose jitter to avoid thundering herd. Did not retry on 4xx since those
indicate client errors that won't resolve on retry.
### Changes
- Edit src/api.py — added retry wrapper with backoff
<!-- /why:entry -->See RFC-GIT-WHY.md for the full specification.
Exclude files from trace capture using gitignore-style patterns:
generated/
*.min.js
node_modules/
GIT_WHY_SKIP=1 git commit -m "quick fix"git why init auto-detects and configures your hook manager:
- pre-commit framework
- husky
- lefthook
- Raw git hooks (fallback)
git-why uses a provider plugin system so every developer on the team can use their preferred AI coding assistant. The pre-commit hook auto-detects which tool is active and captures reasoning transparently.
| Provider | Status | Session source |
|---|---|---|
| Claude Code | Included | ~/.claude/projects/ JSONL files |
| GitHub Copilot | Included | VS Code workspaceStorage/ JSON/JSONL files |
| OpenAI Codex | Included | ~/.codex/sessions/ JSONL files |
| Cursor | Coming soon | — |
| Aider | Coming soon | — |
| Windsurf | Coming soon | — |
| Manual | Built-in | git why capture -m "reason" |
Different developers can use different tools — traces all land in the same .why/ directory in the same format:
$ git why log
a3f1c9d ✦ Add retry to auth refresh (tool: claude-code, 2 .why files)
b7e2d4a ✦ Refactor API pagination (tool: cursor, 1 .why file)
c91f0e3 ✦ Fix race condition in cache (tool: human, 1 .why file)
d4a8b2c Bump dependencies (no trace)
Every entry records which tool produced it via the tool attribute. Readers don't need to know or care — git why show, blame, and search work the same regardless of the source.
Copy bin/providers/_template.sh and implement 5 functions:
provider_detect— find the tool's active sessionprovider_session_id— return a stable identifierprovider_metadata— extract tool version infoprovider_extract_conversation— parse the full conversationprovider_extract_for_file— filter reasoning for a specific file
See CONTRIBUTING-PROVIDER.md for the full guide with examples.
bash>= 3.2jqgit
MIT