Skip to content

feat(cli): stamp commits with the AIDD run id #630

Description

@blafourcade

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.

  1. Host hook on PreToolUse for Bash: when the command is a git commit, write a one-shot marker under $(git rev-parse --absolute-git-dir)/aidd/.
  2. Git hook prepare-commit-msg: consume the marker — read, then delete — and append the trailer with git 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Fields

    Priority

    High

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions