Works in Claude Code. To install, run these two commands in a Claude Code session:
/plugin marketplace add Rmasood1122/commitproof
/plugin install commitproof@commitproof
An AI audit trail for your commits. Know which commits AI wrote, and prove the record wasn't rewritten.
Teams using Claude Code get asked two questions:
- "How much of this did the AI write?"
/ai-historyanswers in seconds from the git history you already have. No setup, no key, writes nothing. - "Can you prove that record hasn't been edited since?"
/receipt-initgives every commit from then on a tamper-evident receipt: hash-chained, signed, verifiable offline./receipt-reportturns the chain into a change-control report you can give a SOC 2, HIPAA or PCI auditor as supporting evidence.
/plugin marketplace add Rmasood1122/commitproof
/plugin install commitproof@commitproof
Then, in any repository:
/ai-history
| | commits | lines added |
|---|---|---|
| Scanned (non-merge) | 7 | 749 |
| With a Claude trailer | 4 (57%) | 605 (81%) |
## By author
| author | commits | with a Claude trailer |
|---|---|---|
| Dana Lee <dana@example.com> | 3 | 0 (0%) |
| Priya Nair <priya@example.com> | 2 | 2 (100%) |
| Sam Ortiz <sam@example.com> | 2 | 2 (100%) |(full sample, from a demo repo.) It reads the
Co-Authored-By: Claude … and Claude-Session: trailers Claude Code already
puts on commits (and the Linux kernel's Assisted-by: Claude:… form), so it labels itself unsigned: a starting estimate, not
evidence. Trailers are plain text and history can be rewritten. That gap is
what receipts close.
Open Claude Code inside the repository you want receipts for:
/receipt-init # one-time: signing key (gitignored), vendored verifier, git post-commit hook
git commit -m "…" # every commit from now on is receipted, human or AI
/verify-chain # walks the chain offline; exit 0 means intact
/receipt-report --badge docs/ai-audit-badge.svg
/receipt-report writes the evidence document: verification result first,
then AI-assisted share by author, month and recorder, and the models and
Claude Code versions recorded. See a sample report.
Each receipt is one small JSON file in .titan/attestations/:
Edit any recorded field (flip one ai_assisted flag) or delete a receipt from
the middle of the chain, and /verify-chain fails and names the receipt.
--badge writes a self-contained SVG (no badge service, nothing phones home)
and prints the README line:
The badge can't say more than the check behind it. It says chain verified
only when the chain is intact and every signature checks out, structure
only without the key, verification FAILED with no percentage if anything
was altered, and unsigned when it comes from /ai-history.
| Command | What it does |
|---|---|
/ai-history |
Share of commits and lines added with a Claude trailer, by author and month, from git history. No setup, writes nothing, unsigned. --since, --json, --badge. |
/receipt-init |
Generates the signing key (gitignored; init refuses if git tracks it), vendors the verifier into .titan/tools/, installs a git post-commit hook. --no-git-hook to skip the hook. |
/receipt |
Writes a signed, chained receipt for HEAD by hand. One per commit; re-runs are no-ops. |
/verify-chain |
Walks the whole chain offline: structure and every signature. Any tamper exits 1 and names the receipt. --structure-only checks without the key and says signatures were not checked. Ends with an ANCHOR line: how many receipts are committed and pushed. |
/receipt-report |
Markdown evidence: verification result, AI-assisted share by recorder / author / month, models and Claude Code versions recorded, and the limits footer. --out, --badge. |
| Commit made… | Receipted by | ai_assisted |
Extra detail |
|---|---|---|---|
| in a Claude Code session | plugin PostToolUse hook |
true (basis: claude-code-hook, plus trailers if present) |
session id, model(s), Claude Code version, transcript hash, tool-use id |
| from your own terminal | git post-commit hook (defers inside Claude Code) |
from Co-Authored-By/Claude-Session trailers; otherwise false |
author, timestamp |
Neither hook can break a commit: an uninitialized repo is a silent no-op
(plus a one-time notice naming /receipt-init; COMMITPROOF_QUIET=1
turns it off), and the git hook always exits 0. Commit .titan/attestations/
and .titan/tools/, never .titan/key. Git hooks aren't cloned, so each
teammate runs python3 .titan/tools/receipt.py install-hook once per clone
(python or py on Windows).
git-ai does line-level AI blame across many coding agents. Use it for that. CommitProof answers the question an auditor asks next: can you prove this record wasn't edited after the fact? It does that with hash-chained, signed receipts you verify offline, and a report built as change-control evidence. The two work side by side.
- uses: Rmasood1122/commitproof@v1.3.2
with:
key: ${{ secrets.TITAN_KEY }} # omit for structure-only verification
report: docs/ai-change-receipts.md # optionalWithout the key the action verifies chain structure and content hashes and
says plainly that signatures were not checked. The key is written only for
the step and removed after. The action verifies with its own pinned
verifier, never the .titan/tools/receipt.py in the repo under audit: the
party who could alter the receipts also controls that copy. Pin a ref you
trust. allow_repo_verifier: true runs the repo's copy for the rare
compatibility case and warns that the result is self-reported.
Proves: the recorded content (file hashes, diff hash, author, provenance claims) is unchanged since signing, and the receipts form one unbroken ordered chain, under a key your team controls.
Does not prove: read before writing a compliance claim
- Who held the key. HMAC is a shared secret; anyone with
.titan/keycan produce valid signatures. Asymmetric signing and external timestamping live in the upstream titan-gate engine. - That anyone reviewed the change, or that it was good.
- That provenance is true.
ai_assisted, model, version, session and transcript hash are recorded claims: trailers from the commit message and what the Claude Code hook observed locally. The chain proves they weren't edited afterwards, not that they were accurate when written. - Anything about un-receipted commits. Coverage is as good as hook installation; the report counts only receipted commits.
- Ordering to anyone but you until
.titan/attestations/is committed and pushed. Every pushed clone then holds an independent copy a rewrite would have to chase down, and/verify-chainreports how much is pushed.
A fresh clone has the receipts but not the gitignored key: /verify-chain
still runs the full structural walk there, then says SIGNATURES NOT CHECKED
and exits 2. Share the key out-of-band with whoever must verify signatures.
The bundled receipt-integrity skill keeps compliance language inside these
lines, because a receipt system that overclaims is worse than none.
- Plugin hook (
PostToolUse, every Bash tool call). Startscore/py.sh, which runscore/receipt.py hookunder the first Python 3.10+ it finds. It reads the hook's JSON from stdin and exits unless the command was a successfulgit commit. In a repo without receipts it shows the one-time setup notice and records that it did in the plugin's data folder (a hash of the repo path, nothing inside your repo). - When it writes a receipt (receipts on, commit made): runs read-only git
commands, hashes the changed files, and reads the Claude Code session
transcript named in the hook payload to record model names, the Claude
Code version, its line count and sha256. Transcript content is never copied
into the receipt. The session id comes from the hook payload or a
Claude-Session:commit trailer; no session-id environment variable is read. Writes one JSON file under.titan/attestations/. /receipt-init: creates.titan/keyand adds it to.gitignore, copiesreceipt.py,badge.py,canonical.pyandchain_state.pyinto.titan/tools/, and installs or appends to.git/hooks/post-commit. Nothing else in your repo changes./ai-history,/verify-chain,/receipt-report: read-only, apart from the--outor--badgefile you name.- Network: none. No telemetry, no package installs, no service.
Claude Code, git, and Python 3.10+ on PATH as python3, python or py.
Stdlib only: no packages, no network, no service, nothing phones home
(PRIVACY.md). CI runs the full suite, every tamper path
included, on Ubuntu and Windows.
Same tool, new name (1.3.0). To switch an existing install:
/plugin uninstall titan-receipts@titan-receipts-marketplace
/plugin marketplace remove titan-receipts-marketplace
/plugin marketplace add Rmasood1122/commitproof
/plugin install commitproof@commitproof
Existing .titan/ chains keep verifying unchanged. Re-run
python3 .titan/tools/receipt.py install-hook in each clone to pick up the
updated git hook. TITAN_RECEIPTS_QUIET still works.
The canonicalization and chain-walk rules are vendored byte-compatible from
titan-gate, whose receipt engine
adds Ed25519 signing, RFC-3161 timestamping and Merkle roots. This plugin is
its lightweight attestation profile, change-attestation/v1. Related:
eval-conductor and
proof-gate by the same author.
MIT
{ "commit": { "sha": "629fca04…", "subject": "feat: add handler", "author": "Dev <dev@example.com>", "committed_at": "2026-10-03T07:32:14-04:00" }, "files": [ { "path": "app.py", "status": "M", "sha256": "bc16d440…" } ], "diff_sha256": "e95b93b0…", "provenance": { "ai_assisted": true, "basis": ["commit-trailers", "claude-code-hook"], "models": ["claude-opus-5-5"], "claude_code_version": "2.1.299", "session_id": "7f3a…", "transcript": { "lines": 412, "content_sha256": "2ef9732e…" } }, "prev_receipt_hash": "b9f069af…", "receipt_hash": "c41d0e7b…", "signature": "80265ea9…" }