Quick start
Ten minutes, one repository, no server. At the end of it you will have a commit carrying an AI-attribution trailer and a local HTML report you can open in a browser.
The dashboard layer at the end is optional, and you can stop before it.
Before you start
You need a git repository and at least one AI coding agent that keeps local session transcripts. Today that means Claude Code, Codex CLI, or Antigravity. Nothing else is required: no account, no API key, and no network access for anything in steps 1 to 5.
1. Install
# macOS and Linux
brew install navjyotnishant/tap/dun
# Windows
scoop install dun
The binary must be called dun and be on your PATH. The git hooks resolve it
by name, so an unzipped archive sitting in ~/Downloads will install fine and
then silently stamp every commit undetermined.
Check it:
dun version
2. Capture a baseline, if you want a before-and-after
Skip this if you only want to see attribution working. Come back to it before you instrument a team.
cd your-repo
dun baseline capture --since 2026-01-01 --until 2026-06-30
Name the window when your team was working without an agent. The command reads git history for exactly that period and stores commits, cadence, median diff size and revert rate.
This is the one step that gets impossible rather than late. Once hooks are
installed, every window that includes today contains AI-assisted work, so
there is no pre-adoption period left to measure. dun baseline capture with no
window prints help rather than guessing, for that reason.
3. Instrument the repository
dun init
That installs three git hooks: prepare-commit-msg, commit-msg and
pre-push. If the repository already has hooks, yours are chained rather than
replaced.
dun init is deliberately one repository at a time. There is no flag to enrol
every repository on your machine, because that set includes client work and
clones of other people's projects, and stamping attribution into a commit
message is a disclosure decision that belongs to whoever owns the repo.
4. Make a commit
Work as you normally would, with your agent, and commit.
git commit -m "feat: add the thing"
git log -1 --format='%(trailers:key=AI-Attribution)'
You should see something like:
AI-Attribution: v=1; status=assisted; method=intersected; agent=claude-code; agent_version=2.1.229; ratio=0.58; model=claude-opus-5; session=d1a8a52b
method is the field that matters. intersected means the text the agent
produced is verifiably what ended up staged. Weaker levels say so, and when
there is no evidence at all it records undetermined rather than deciding no
AI was involved.
If the trailer is missing or says undetermined
dun verify
It checks that the hooks are installed, that dun is still where the hooks
expect it, and that your agent's transcripts are being found. dun log shows
what the hooks did on recent commits, including errors they survived rather
than failing the commit over.
A commit written entirely by hand is correctly undetermined. That is not a
failure.
5. Look at it locally
dun status # coverage and method mix for recent commits
dun report # self-contained HTML, opens in your browser
dun report renders a single file with no server and makes no network
request. If you only ever want to see your own numbers, you are finished here.
6. Optional: a shared dashboard
Everything above is local. This step is the only one that transmits anything, and it is opt-in.
The stack is DevLake plus Grafana, run with docker compose. Setting it up is covered in Setting up the datalake; it is two scripts, one for the stack and one for the dashboards.
Once it is running, point dun at it:
dun config datalake
That prompts for the connection and stores the password encrypted at rest, bound to the machine. Then publish:
dun sync --dry-run # prints the exact payload, sends nothing
dun sync
Run --dry-run first at least once. It shows precisely which rows leave your
machine, which is a better answer to "what does this send?" than any
documentation.
After the first sync, git push publishes automatically through the pre-push
hook.
What is on your machine
| Path | What it holds |
|---|---|
~/.whodunit/ | the journal, baselines and config, 0700 directories and 0600 files |
.git/hooks/ | three hooks, chained to anything already there |
The journal stores file paths, counts, outcomes and line hashes. It has no field capable of holding prompt text, message content, file contents, hostnames or remote URLs, which is a schema property rather than a filtering promise.
Where to go next
- Your first commit walks through the same flow in more detail, including what happens on a commit an agent did not touch.
- The trailer explains every field and what each
methodlevel is claiming. - Setting up the datalake covers the shared stack, ports, and keeping it running.
- What the numbers mean is worth reading before anyone quotes a figure from a dashboard in a meeting.