git blame tells you who. git motive tells you why.
gitmotive records the prompt and reasoning behind every line an AI coding agent writes, then gives them back when you ask about that line. It runs on your machine. No LLM, no cloud, no account.
src/fetch.pygit blame
134d8dd9 alex 10-2931import time8c41e07a alex 09-14328c41e07a alex 09-1433from .http import _get134d8dd9 alex 10-2934from .http_errors import UpstreamBusy8c41e07a alex 09-14358c41e07a alex 09-14368c41e07a alex 09-1437def fetch(url, attempts=3):134d8dd9 alex 10-2938 for attempt in range(attempts):134d8dd9 alex 10-2939 try:134d8dd9 alex 10-2940 return _get(url, timeout=10)134d8dd9 alex 10-2941 except UpstreamBusy:134d8dd9 alex 10-2942 time.sleep(2 ** attempt)134d8dd9 alex 10-2943 raise TimeoutError(url)8c41e07a alex 09-1444
intent for line 42git motive
git motive src/fetch.py:42
src/fetch.py:42
| time.sleep(2 ** attempt)
commit 134d8dd9e6 alex 2026-10-29 add retry
edited 2026-10-29 06:19 by Edit session 3f9a2c1e [same commit, line text in edit] via claude model claude-sonnet-4-5
prompt
add retry with exponential backoff to fetch()
reasoning
Wrapping the call in a retry loop; 3 attempts with backoff since the upstream flakes
under load.
also changed for same prompt
src/http_errors.py
tests/test_fetch.py
The why ends with the session
AI agents now write more code than reviewers can absorb. Every line came from a prompt and a chain of reasoning, but that context lives in a chat window. When the session ends, it is gone.
Weeks later, git blame points to a commit and a person, who may not know why the line is there either. The commit message is one sentence. The thinking that produced the code was never saved.
@@ session 3f9a2c1e ended @@ time.sleep(2 ** attempt)- prompt add retry with exponential backoff to fetch()- reasoning 3 attempts with backoff; upstream flakes under load- session 3f9a2c1e claude 2026-10-29 06:19
gitmotive keeps those deleted lines.
How it works
-
Install the CLI
pipx install gitmotivePython 3.10 or newer. No runtime dependencies.
-
Hook up your agent, once per repo
gitmotive install --agent claudeAdds the agent's hooks and a git
post-commithook, and keeps.gitmotive/out of git. Then use your agent as usual. -
Ask any line why it exists
git motive path/to/file.py:42Prints the prompt, the agent's reasoning, the session, the model and the commit. If no hook saw the edit, it says
none recorded
instead of guessing.
Install
With pipx
pipx install gitmotive
Without pipx
curl -fsSL https://gitmotive.tech/install.sh | sh
Creates a venv in ~/.gitmotive/venv and puts gitmotive and git-motive in ~/.local/bin. Read the script first if you like; it is plain shell.
Agents
| Agent | --agent | Status |
|---|---|---|
| Claude Code | claude | Supported |
| Cursor | cursor | Supported |
| GitHub Copilot CLI | copilot | Experimental |
| oh-my-pi | omp | Experimental |
Experimental agents record prompts and edits only; their hook payloads are not fully documented yet.
Nothing is guessed
- deterministic
- Lines are matched to edits through
git blameand the recorded edit text. No model reads your code. - local
- Events are append-only JSONL in
.gitmotive/, or under~/.gitmotive/with--scope user. No network calls, no telemetry. - open source
- MIT licensed. Read the code, file an issue or send a patch on GitHub.
See it on its own source
The demo is gitmotive's own repository, blamed line by line with the prompts that wrote it. Pick a line and read why it exists.