Repository navigation
feat(cli): stamp commits with the AIDD run id #630
Description
As a team measuring AI spend
I want each agent commit to carry the session that produced it
So that cost attaches at commit precision, not only at session precision
Acceptance
- A commit created by an agent in an enabled repository carries
AIDD-Session-Id. - The trailer carries the AIDD
aidd_id, never a vendor identifier. - A commit created by a human while a session is open carries no trailer, including when it lands in the window between the marker being written and the agent's own commit.
- Installing on a repository using
core.hooksPath, one using lefthook, one using husky, and one using none, leaves every pre-existing handler invoked on commit, asserted by its side effect. - A failing, missing or slow hook never blocks a commit; the commit succeeds unstamped, and the hook returns under 200 ms at p95.
- Disabling removes the entries it added and nothing else.
-
git log --format='%(trailers:key=AIDD-Session-Id,valueonly)'returns the identifiers.
Scope
Two halves, because neither can do it alone. The host hook knows the session id but cannot write the commit message; the git hook owns the message but knows nothing about the session.
- Host hook on
PreToolUseforBash: when the command is agit commit, write a one-shot marker under$(git rev-parse --absolute-git-dir)/aidd/. - Git hook
prepare-commit-msg: consume the marker — read, then delete — and append the trailer withgit interpret-trailers.
Consuming the marker is the guarantee: one marker, one commit.
The concurrent-human case needs a real answer, not a claim. Marker consumption alone does not exclude a human commit landing in the same window; that commit would consume the marker and be stamped. Scoping the marker to the agent's own invocation is part of this issue, not an assumption of it.
Hook manager detection is load-bearing. Writing .git/hooks/prepare-commit-msg on a repository that sets core.hooksPath produces a hook git never runs, and a silent hole in the data. Observed live during this design work: a worktree on the author's machine had core.hooksPath pointing at a different path's .git/hooks.
Why this is not in the first milestone
The run journal already covers sessions that produce no commit — planning, exploring, debugging, answering a review — which are the most expensive and the worst counted. The trailer adds precision per commit, not the ability to measure.
Out of scope
- The diagnostic and the report, which are skills.
- Rewriting history to stamp past commits.
Relations
| Field | Value |
|---|---|
| parent | #652 |
| depends_on | #620 |
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Projects
- StatusShow more project fieldsDone
Activity
blafourcade commentedon Aug 20, 2026
Why this matters more than the acceptance criteria above suggest
Measured while building #663's journal, and it sharpens the case for this ticket.
The run journal records a
file_writtenline only when the path looks like a task folder (aidd_docs/tasks/<yyyy_mm>/<slug>/). That filter is a volume decision, not a task-identity one - it keeps the hook from appending a line for every strayWritein a repository. But it has a consequence the journal cannot fix on its own:A session spent entirely outside the task flow leaves a cost with no content. Debugging, an ad-hoc prompt, a refactor driven from chat - the collector still records what it cost, the journal still records that the session happened and which skills ran, and nothing anywhere records what it produced.
And separately: nothing in the repository distinguishes what a human wrote from what an agent wrote.
A commit trailer answers both at once, at commit precision rather than session precision, which is why this ticket is the right shape for it rather than widening the journal's filter.
Closing #679 as a duplicate of this. It was filed without checking the backlog first; this ticket came first and is more precise - it already pins the trailer to the AIDD
aidd_idrather than a vendor identifier, and already names thecore.hooksPath/ lefthook / husky coexistence and the p95 budget, none of which #679 covered.blafourcade commentedon Sep 2, 2026
Delivered by #706, squash-merged into
nextas 627408f.blafourcade commentedon Sep 11, 2026
Closed for the delivered commit-to-session link, with the remaining hook-lifecycle work owned by #746.
#706 proves the core path on real commits: an AI-session commit carries
AIDD-Session-Id, a commit without a session carries nothing, amend does not duplicate it,telemetry offstops it, and an existingprepare-commit-msgstill runs.The trailer value is the existing session anchor (
CLAUDE_CODE_SESSION_IDorCODEX_THREAD_ID), not a separately minted AIDD identifier. That keeps the commit directly joinable to the telemetry records.#746 owns the unproven host layouts, regenerated-hook repair, diagnostic coverage, and timing bound.