One Python script turns your local Claude Code transcripts, prompt history and claude.ai export into a single SQLite database with timestamps, models, tool calls and a SHA-256 of each message.
Open-Source Tools · How-To · Dev & ops tools
How to use claude-provenance: an auditable log of every Claude message on your machine
Revised
· v1.0.0 · what changed
Code: github.com/herrrickshaw/claude-provenance
Watch the walkthrough
Watch on YouTube: youtu.be/aENlyT4G1aY
Why it is useful
- Who benefits: people who use Claude Code or claude.ai heavily and need to answer when, with which model, in which folder and on which git branch something was asked or done.
- What it replaces: grepping scattered JSONL transcripts by hand.
- Evidence from the run: a synthetic session of four messages became a queryable table with role, model, tool names, content length and a hash; a second run skipped the unchanged file.
- Audit value: each row stores the source file and line number plus a SHA-256 of the full content, so you can recompute the hash later and detect edits.
- Privacy note built in: the database holds transcript content, so it is meant to stay local and gitignored.
What it is for
claude-provenance reads transcripts that Claude Code already writes under ~/.claude/projects, your prompt history file, and optionally a claude.ai data export, and writes one SQLite file, provenance.db.
Each message row records where it came from (file and line), when (original and ingest timestamps), who (role, model, CLI version, git branch, working folder), what (record type, tool calls, a 300-character preview) and integrity and lineage (SHA-256, message id and parent id).
Re-runs are incremental: unchanged source files are skipped. --summary also writes a markdown summary of counts by source, project and model.
Who it is for
- Teams or individuals who need a record of AI-assisted work
- Researchers measuring their own AI usage
- Anyone debugging which session changed something
- Sharing or publishing: the database and summary can contain echoed credentials and private text. Never commit them
- Proving authorship to a third party: the hash detects edits to your local files, it is not a signature from Anthropic
- Claude chats that exist only on the server and were never exported
What you need
| Requirement | Why | How to get it |
|---|---|---|
| Python 3 | runs provenance_log.py (standard library only) | already installed on macOS and most Linux |
| sqlite3 command-line (optional) | to query provenance.db from the shell | preinstalled on macOS; any SQLite viewer also works |
| Existing Claude Code transcripts | the script reads ~/.claude/projects and ~/.claude/history.jsonl | use Claude Code normally; nothing to install |
| claude.ai export (optional) | to include web and desktop chats | claude.ai, Settings, Privacy, Export data |
Get the code and an AI assistant
You do not have to be a programmer. Get the repository, give it to an AI assistant, and ask in plain language. Any of these routes works:
| Tool | What you need | Best for |
|---|---|---|
| GitHub | Free account to fork or star; git to clone, or the green Code button, then Download ZIP, or open in Codespaces | Getting the code and keeping up with updates |
| Claude Code | Claude subscription or API key; run claude inside the cloned folder | Letting the AI read and run the whole repo |
| Gemini CLI | Google account; run gemini inside the cloned folder | The same hands-on workflow with Gemini |
| Claude.ai, Gemini or ChatGPT in the browser | A chat account; upload README.md and the files you care about (or paste the output of git ls-files) | Understanding the project and asking questions without installing anything |
| Other tools (Copilot Chat, Cursor, Codex CLI) | Open the cloned folder in the tool and point it at README.md first | Editing and extending the code |
git clone https://github.com/herrrickshaw/claude-provenance.git
cd claude-provenance
claude # or: gemini
Install
- Clone the repo
git clone https://github.com/herrrickshaw/claude-provenance.git cd claude-provenance - Make sure provenance.db and PROVENANCE_SUMMARY.md stay out of git (the repo gitignores them in the author's setup; add your own ignore if you copy the script elsewhere)
printf 'provenance.db\nPROVENANCE_SUMMARY.md\n' >> .gitignore
Quick start: commands and what you should see
Ingest everything and write the summary
python3 provenance_log.py --summary
'Parsed N files (...). Ingested M messages this run.' then the database path and the summary path.
Run it again
python3 provenance_log.py
'Parsed 0 files (N unchanged, skipped)': only new or changed transcripts are re-read.
Look at one day or one tool
sqlite3 provenance.db "SELECT ts, role, model, content_preview FROM messages WHERE ts LIKE '2026-10-01%' ORDER BY ts"
The messages of that day in time order.
Include a claude.ai export
python3 provenance_log.py --claude-ai-export /path/to/unzipped-export
Adds source claude-ai-export rows, one per chat message.
Sample outputs
Real output from a run on the date shown in the sources line; trimmed to fit.
Ingest of a synthetic Claude Code session (run 19 Oct 2026, HOME pointed at a made-up folder)
python3 provenance_log.py --summary
python3 provenance_log.py
Parsed 2 files (0 unchanged, skipped). Ingested 5 messages this run.
Database now holds 5 messages across 1 sessions -> .../provenance.db
Summary written -> .../PROVENANCE_SUMMARY.md
---rerun
Parsed 0 files (1 unchanged, skipped). Ingested 0 messages this run.
The demo used a fake ~/.claude with one four-message session and one prompt-history line. No real transcripts were read.
The provenance record for that session
sqlite3 -header -column provenance.db "select ts,role,model,tool_names,content_chars,substr(content_sha256,1,12) sha,content_preview from messages where source='claude-code' order by ts"
ts role model tool_names content_chars sha content_preview
-------------------- --------- --------------- ---------- ------------- ------------ ------------------------------------
2026-10-01T09:00:00Z user 25 82bb095abde1 Why does test_parse fail?
2026-10-01T09:00:05Z assistant claude-sonnet-5 Bash 39 7c687025e3fc Let me run it. {"command": "pytest -x"}
2026-10-01T09:00:09Z user 31 02aebbe264cc 1 failed: off-by-one in parse()
2026-10-01T09:00:15Z assistant claude-sonnet-5 Edit 73 63c17a533d05 parse() slices one char too many; fix the end index.
Preview lines trimmed. The first hash equals sha256('Why does test_parse fail?'), checked separately.
Summary file header
head -22 PROVENANCE_SUMMARY.md
**5 messages** across **1 sessions**
| Source | Messages | First | Last |
| claude-code | 4 | 2026-10-01T09:00:00Z | 2026-10-01T09:00:15Z |
| prompt-history | 1 | 2026-09-21T14:13:20+00:00 | ... |
| Model | Assistant messages |
| claude-sonnet-5 | 2 |
Trimmed. Counts are for the synthetic data only.
Ways to use it
| Method | How it works |
|---|---|
| Command line + SQLite | python3 provenance_log.py, then sqlite3 or any SQL viewer on provenance.db. |
| Verify a message | Read src_file at src_line, recompute the SHA-256 of the content text and compare it with content_sha256. |
| Scheduled | Run the script daily from cron or launchd; it is incremental so repeat runs are cheap. |
| Via an AI assistant | Ask Claude Code or Gemini CLI to write queries against provenance.db, for example tool usage by week. |
Sample prompts for your AI assistant
Copy, paste and edit the parts in [brackets].
- Explain the claude-provenance repository in plain English: what problem it solves, what the main files do, and what I need installed.
- Write a SQLite query that shows my Claude messages per day for the last 30 days, split by model.
- Which git branches had the most assistant tool calls? Query provenance.db and show the top 10.
- Explain how I would verify that one message in provenance.db has not been altered since it was ingested.
- Review provenance_log.py for privacy risks and suggest what I should exclude before sharing a summary.
- Help me export my claude.ai data and ingest it with --claude-ai-export, step by step.
Limits and honest caveats
- The demo used synthetic transcripts. On a real machine the database can be very large and can contain secrets that appeared in tool output; keep it private.
- Observed in the run: the sessions table counted the tool-result message as a user message (n_user = 3 for a session with one typed prompt), so n_user over-counts human prompts.
- It records only what exists locally. Server-side claude.ai chats need an export; deleted transcripts cannot be recovered.
- The SHA-256 detects changes to your own copy; it does not prove the text came from Claude.
Sources: claude-provenance README and provenance_log.py; run on 19 October 2026 on a fresh clone with HOME pointed at a synthetic ~/.claude folder (one made-up session). No real transcripts or the repo's own database were read.
- v1.0.0 — 26 October 2026 — first published.
About this article: Researched, written and edited by Umashankar Triplicane Dwarakanathan, with AI research assistance; every figure is meant to trace to the primary source cited. See the Editorial Policy for how sourcing, AI use and corrections work.