Comparison · Git notes

Git Notes vs h5i for AI Coding: Does Your Commit Metadata Have Behavior?

It is not notes versus h5i. h5i is built on git notes for per-commit provenance and adds a typed schema, a capture/recall/audit pipeline, and sibling refs a single free-form note was never meant to hold. The deciding question is whether the metadata has behavior.

Key takeaways
  • Git notes are the right primitive, and h5i uses them — the record is JSON in a git note on refs/h5i/notes, not a competing store.
  • AI provenance is structured, multi-ref, and queried — which is exactly where a single free-form note breaks down.
  • Use raw notes for small human annotations; use h5i when the record must be captured repeatably and acted on later.

When a person writes a commit, the message is the provenance: a human chose the words and will answer for them. When an agent writes a commit, the interesting record lives outside the diff — which prompt produced it, which model and agent, how many tokens, whether the tests passed, whether an integrity audit flagged anything. None of that belongs in the commit message, and none of it should rewrite the commit's SHA. So the question arrives quickly for anyone running Claude Code, Codex, or a fleet of agents against a real repository: where does AI provenance go, and what can you do with it afterward?

The usual framing — "git notes versus h5i" — is the wrong one. h5i is built on git notes. Its per-commit provenance record is a JSON document stored as a git note. The real comparison is not between two storage mechanisms; it is between a free-form note you maintain by hand and a typed record with a query, audit, and sharing pipeline around it. The deciding question, the one this whole post turns on, is whether your metadata has behavior: does it merely sit there to be read by a human someday, or must it be queried, rendered into a PR packet, used to restore a future session, and moved between agents?

What you already know: how git notes actually work

Most readers of this post know the primitive, so the recap is short and aimed at the corners that bite later. A git note attaches data to an existing object — almost always a commit — without changing that object. Because a commit's SHA is a hash of its content, you cannot edit a merged commit to add metadata without rewriting history and breaking every downstream reference. Notes sidestep that: the note is stored as a separate blob in a parallel tree, keyed by the target commit's OID, and the commit itself is untouched.

Those note trees live under their own refs. The default is refs/notes/commits, which git log renders inline beneath each message. You are not limited to it: git notes --ref=<name> (or core.notesRef) lets you keep parallel, independent note namespaces, so build metadata and review metadata need not collide. Four facts about notes matter for what follows:

This is a genuinely good primitive. It is the right place to put per-commit metadata, and it is exactly what h5i uses. The open question is everything Git deliberately leaves to you: the schema, the queries, the sharing, the merge policy.

The contrast: a hand-rolled note vs h5i capture commit

Suppose an agent just added retry logic to an API client and you want the provenance recorded. The hand-rolled approach is one extra command:

$ git commit -m "add retry to api client"
$ git notes add -m "prompt: retry on 503; model: claude-sonnet-4-6; agent: claude-code; tests: 12 passed"
$ git log --notes -1
commit 9af1c2e…
    add retry to api client

Notes:
    prompt: retry on 503; model: claude-sonnet-4-6; agent: claude-code; tests: 12 passed

That works, and for a one-off it is fine. But look at what you have actually committed to: a single English string under the default ref, with a field convention (key: value; …) that exists only in your head. Nothing validates it. Nothing can answer "show me every commit by claude-code where tests failed" without you writing a parser. And as established above, that note will not leave your machine on the next git push.

The h5i path looks similar at the surface and diverges underneath:

$ git add src/api/client.py
$ h5i capture commit -m "add retry to api client" \
    --model claude-sonnet-4-6 --agent claude-code --tests --audit

This creates an ordinary git commit and writes a structured H5iCommitRecord — an AiMetadata block (model, agent id, prompt, token usage), optional TestMetrics, and an IntegrityReport whose severity is Valid, Warning, or Violation. In Claude Code the verbatim human prompt is captured automatically by the UserPromptSubmit hook and wins over any --intent you might pass, so the recorded prompt is what the human actually asked, not what the agent paraphrased.

It is notes underneath, with a schema on top

The point worth making visceral: h5i's record is not stored somewhere exotic. It is a git note — JSON, on h5i's own note ref, refs/h5i/notes (kept separate from refs/notes/commits so it never collides with anyone's hand-written notes). You can read it with plain Git:

$ git notes --ref=refs/h5i/notes show HEAD
{
  "git_oid": "9af1c2e…",
  "ai_metadata": {
    "model_name": "claude-sonnet-4-6",
    "prompt": "make the client retry on 503 with backoff",
    "agent_id": "claude-code",
    "usage": { "total_tokens": 1843, "model": "claude-sonnet-4-6" }
  },
  "test_metrics": { "passed": 12, "failed": 0, "total": 12, "tool": "pytest" },
  "timestamp": "2026-06-03T14:22:08Z"
}

That is the whole trick. Git notes are the storage; the schema is the value h5i adds. And because the record is typed rather than free-form, you read it ergonomically instead of grepping a string:

$ h5i recall log --limit 3                 # commit history with AI provenance
$ h5i recall blame src/api/client.py --show-prompt   # per line: author + model + agent + test result
$ h5i audit review --limit 50              # triage the integrity findings before merge

The hand-rolled note can do none of this without you building it. recall blame --show-prompt resolves each line to the commit that wrote it and surfaces that commit's model, agent, and test outcome; audit review funnels the IntegrityReport severities so you can look at the Violations before merging an AI-heavy branch. The metadata has behavior because it has a shape.

Where one note stops: provenance is multi-ref

Even with a schema, per-commit notes are only one dimension of what an agent session produces, and this is where the "just use a note" instinct quietly breaks. AI provenance is not a single annotation per commit; it spans several kinds of record with different lifetimes and merge semantics. This is the reasoning behind h5i's design as a substrate for auditable workspaces: it deliberately puts each dimension on its own ref:

Try to cram all of that into one free-form note per commit and three things break at once. Querying breaks: a reasoning DAG and a message log have no natural home keyed to a single commit SHA — context evolves between commits, and messages belong to no commit at all. Merging breaks: per-commit notes, an append-only message log, and a context DAG want different conflict policies (newest-wins, union-append, and structured merge respectively); one blob forces one policy on all of them. Sharing breaks: you would be moving coordination state and per-commit facts as a single unit when they have different audiences and update cadences. Separate refs exist precisely so each dimension keeps the merge and query model that suits it.

Sharing semantics: explicit, on both sides

Because every h5i ref lives under refs/h5i/*, none of it travels on a plain git push — the same rule that hides hand-written notes. The difference is the ergonomics of fixing that. With raw notes you edit remote.origin.push and remote.origin.fetch refspecs on each clone, remember to keep them in sync, and hope a teammate did too; forget, and provenance silently stays local. h5i moves the whole namespace with one verb on each side:

$ h5i share push    # push notes, context, msg, memory under refs/h5i/* to origin
$ h5i share pull    # pull them back, union-merging where the refs allow

This does not make sharing automatic — and that is deliberate. Provenance moves when you say so, not on every push, so a noisy local context branch does not spam the remote. But it is one intentional command rather than a refspec you maintain by hand and forget.

Failure modes and tradeoffs, on both sides

A fair comparison names where each approach hurts.

Raw notes. The failure modes are the four facts from earlier, now turned against you. Merge conflicts: two agents (or an agent and CI) annotating the same commit produce divergent note refs, and the default merge is a manual conflict — cat_sort_uniq can help for additive text but will happily concatenate two JSON blobs into something that is no longer JSON. Silent non-sharing: notes that are not in anyone's refspec simply never arrive, and nothing warns you. Rebase and amend orphan notes: rewrite a commit and its note is left pointing at an unreachable OID. Schema cost: the moment you want to query, you are maintaining a serialization format, a parser, and a convention across every contributor — an unfunded mandate that grows with the team.

h5i. It is not free either. It is another tool in the loop, with its own commands to learn and its own refs to share. The same conflict and orphaning realities exist underneath — h5i chooses merge policies per ref rather than abolishing the problem, and a record is still keyed to a commit, so aggressive history rewriting can still strand provenance. And it is genuine overkill for a solo developer who wants to scribble "reviewed, ship it" on a commit: that is a sentence, and a sentence wants a plain note. h5i earns its place when records are produced repeatably by agents and consumed later by tools or people — not when you want to leave one human remark.

When raw notes are enough vs when h5i fits

Reach for raw git notes when the metadata is small, human-authored, and rarely queried: a manual review marker, a "generated by an agent" flag, a one-line rationale you will read with your eyes and never with a script. You accept that you own the schema and the sharing, because there is barely a schema to own.

Reach for h5i when the record is produced during agent work and must be acted on later — filtered by agent or severity, rendered into a PR or compliance packet (h5i audit compliance --since … --until … --format html), used to restore a future session's context, or moved between Claude and Codex. Prompts, model identity, token counts, test evidence, integrity findings, and reasoning branches are structured, multi-ref records. Storing them as one free-form note does not just look untidy; it forecloses every downstream automation.

Conclusion: does the record have behavior?

The honest version of this comparison is not a contest. Git notes are the correct primitive for attaching data to a commit without rewriting it, and h5i agrees so completely that it stores its provenance as a git note. What h5i adds is everything Git deliberately leaves undefined: a typed schema so the record can be queried, a capture/recall/audit pipeline so it can be acted on, and sibling refs so the dimensions a single note cannot hold — reasoning, coordination, memory — each get a home with the right merge and sharing model.

So the choice is not "notes or h5i." It is a question you can ask of any piece of AI metadata before you decide where to put it: does this record have behavior? If it only needs to be read by a human someday, a plain note is the lighter, more Git-native answer, and you should take it. If it must be queried, rendered, restored, or moved between agents, then a free-form note is a parser and a merge policy and a sharing convention you have not written yet — and that is precisely the work h5i has already done.

FAQ

Does h5i replace git notes?

No — it is built on them. h5i's per-commit provenance is a JSON H5iCommitRecord stored as a git note on its own ref, refs/h5i/notes. It adds a typed schema, a query/audit command surface, and sibling refs on top of the same primitive rather than competing with it.

Can teammates ignore h5i?

Yes. The code history is ordinary Git. Anyone who does not use h5i can clone, branch, diff, and merge normally; the h5i data sits in refs/h5i/* and is only ever moved by an explicit h5i share push / pull.

Why not put everything in commit messages?

Commit messages are user-facing summaries and editing one rewrites the commit's SHA. AI provenance is structured data — prompt, model, tokens, tests, integrity findings — that wants its own queryable record attached without touching the commit, which is exactly what a git note is for.

Are git notes shared on a normal push?

No. refs/notes/* is outside the default refspec, so a plain git push leaves notes behind unless you configure push/fetch refspecs explicitly. h5i keeps its data under refs/h5i/* and moves all of it with h5i share push / h5i share pull.

Sources and verification

This article avoids vendor-specific claims that were not checked against primary docs or local h5i CLI behavior.

Try h5i on your next AI-assisted branch

Create a sandboxed workspace, capture the run, and post a review-ready PR brief. h5i records prompts, context, test evidence, review signals, and agent messages alongside normal Git history.

Star on GitHub Read the guides