I want to investigate adding the installation of a global git hook like git-ai (~/code/git-ai) that allows us to attach a traces id to commits and other refs which will get stored in refs/notes/traces so that the trace id gets synced whne pushed, this way we can automatically read a trace id from a github app and provide more deep and automatic integration, this will be a big feature and may require other changes to the system so lets write a markdown file for this, some follow on pieces: connecting the repo and trace, having the local tui be able to find traces in the current dir if its a git repo, having the traces ui be able to pull down traces that the user did not create, being able to group traces by repo. The overall workflow is that I code with my agent, open a pr, then any other collaborator can browse my trace and even download it locally for inspection (or maybe even resuming in the future, at least injecting as context), so they can understand how i ended up with the PR because the traces provide full context (there may be multiple traces attached to a single pr), this helps with debugging and also attestion of what happened and what tools and data was used. ensure the design has clear boundaries and is in small composbile peieces, there will also need some new api endpoints required to be added
Let me explore the codebase first to understand the current architecture and then write the design document.
Now I have a thorough understanding of both codebases. Let me write the design document.
Written to docs/git-integration.md. Here's the shape of it:
9 composable pieces, each independently shippable:
refs/notes/traces on commit.git/traces-active) so the hook knows which traces are recordingrepos and traceRepoLinks Convex tables to connect git repos to namespacesPieces 1 and 2 are pure local git work with zero API changes and can ship first. The rest layers on in dependency order. The doc covers the note format, how it coordinates with git-ai's existing refs/notes/ai, the new data model, auth considerations, and open questions around naming, privacy, and multi-namespace repos.
"A single repo could be linked to multiple namespaces if different team members use different traces accounts" are you talking about traces namespaces or git forge namespaces?
Traces namespaces. The scenario is: Alice and Bob both work on the same GitHub repo, but Alice's traces account is in namespace alice-team and Bob's is in bob-team. They'd each link the same repo remote URL to their own namespace, creating two rows in the repos table.
In practice this is probably uncommon -- most teams would share a single traces namespace. But worth flagging since the data model needs to handle it or explicitly disallow it.
i don't think git integration needs worry or know aobut namespaces
You're right. The trace already belongs to a namespace. The repo is just a repo -- the git hook writes trace IDs, and you follow the trace to find its namespace. The repo table doesn't need a namespaceId at all.
That simplifies piece 3 a lot. The repos table becomes a plain registry of git remotes, and namespace scoping comes from the traces themselves whenever you need it.
Let me update the doc.
Now update the API endpoints section to drop namespace from repo registration, and the auth section.
Now fix the push hook section that still references namespace.
And update the open questions section -- the multiple namespaces question changes character now.
And the GitHub App installation flow still mentions namespace API keys.
Done. The repo layer is now a plain registry of git remotes with no namespace coupling. Namespace scoping flows entirely through the traces themselves -- their existing visibility and ownership rules handle who can see what. The GitHub App, the CLI, and the frontend all just query by repo/commit and let the trace-level auth filter results.
You're right. I was designing endpoints before knowing what actually needs them. Let me strip piece 4 down to just what the other pieces concretely require.
Now update the push hook section that was referencing the speculative endpoints.
And update the dependency graph since piece 4 is no longer a concrete dependency.
Piece 4 is now just a note that endpoints emerge from the pieces that need them, not a speculative API design up front.
if the github app reads trace ids out of a git repo, it can load them
Right -- the GitHub App already has access to the repo contents. It can read refs/notes/traces directly from the repo it's installed on, pull out the trace external IDs, and load them from the traces API. No push hook syncing step needed.
That collapses pieces 3, 5, and the whole traceRepoLinks table. Let me simplify.
Now remove the old piece 7 (GitHub App) since it's been consolidated into piece 3, and clean up the remaining pieces.
Now update the dependency graph.
Now clean up the GitHub App comment format -- it was in the old piece 7, let me add it back to piece 3 where the app now lives.
Now clean up the open questions -- remove the ones that no longer apply.
Much cleaner. The key insight killed three pieces: the repos table, the traceRepoLinks table, and the push hook sync. Git notes are the link layer. The GitHub App reads them from the repo it's installed on, the CLI reads them from the local checkout. No intermediate database needed.
we can actuakky hve the git hook trigger traces cli to uplaod the trace, it doesn't need to be running in the background (it reads the traces from the agent datastore)
Good point. The CLI already knows how to read traces from agent datastores and upload them. The hook just needs to trigger that for the active trace IDs -- it doesn't need any background process or marker file coordination.
That collapses piece 2 (CLI markers) into piece 1 (git hook). The hook reads the marker file to get IDs, then calls traces sync <externalId> or similar. Actually -- if the CLI can figure out which traces are active for a directory on its own (it already scans agent datastores by directory), the marker file might not even be needed.
Let me re-read piece 2 to see what to cut.
Now update the dependency graph and summary since piece 2 is gone.
Now renumber the pieces in the body to match (old piece 3 → 2, old piece 4 → 3, etc.).
Down to 5 pieces now. The marker file and background process are gone. The hook calls the CLI directly -- traces active --dir . to find IDs, traces sync to upload. The CLI reads from the agent's on-disk datastore, same as it always does.
How it works diagram nees tweaking
use the term ref instead of commit
Now let me check the rest of the doc for other places that should say "ref" instead of "commit".
Done.
"Multiple traces can attach to a single commit"
git-ai actually installs multiple hooks: - Pre-commit: creates a "checkpoint" capturing the file state and authorship baseline before the commit happens. Each checkpoint records the diff, who
authored it (human vs AI agent vs AI tab completion), timestamps, and optionally the conversation transcript.
The post-push hook is particularly nice -- git-ai already pushes refs/notes/ai to the remote there, so adding refs/notes/traces to the same push is trivial.
"Git notes don't sync by default. " thats a problem, what if we jsut used raw refs instead?
Raw refs (refs/traces/<sha> or similar) would have the same sync problem -- only refs/heads/* and refs/tags/* sync by default. Anything else needs refspec configuration.
The options I can see:
refs/notes/traces): one refspec to configure, but notes have their own merge complexityrefs/traces/*): one refspec to configure, simpler than notes (just blobs), but creates a ref per commit which grows unboundedlytraces/<externalId>): sync with git push --tags which many workflows already do, but pollutes the tag namespaceTraces-Id: abc123): sync automatically with the commit, zero config, but can't be added after the fact and clutters commit messagesgit-ai already solves this for its own notes by pushing them in the post-push hook. If git-ai is present, adding refs/notes/traces to that push is trivial. The problem is only when git-ai is not installed.
What were you thinking with raw refs?
we want to copy git-ai, not use it
Right. The traces hook handles its own push/fetch refspec configuration at install time, same way git-ai does. No dependency on git-ai being present.
how does gittuf solve this?
gittuf stores its metadata under refs/gittuf/* and has the same sync problem. They solve it three ways:
git push <remote> refs/gittuf/* / git fetch <remote> refs/gittuf/*:refs/gittuf/*gittuf add-hooks installs a pre-push hook that syncs automaticallyrefs/gittuf/* on normal push/pull without explicit gittuf commandsThe custom transport is the interesting one -- it makes the refs invisible to the user. But it's also the most complex to build.
For traces, option 2 (hooks that auto-configure refspecs at install time) is probably the right starting point. Same as what we have in the doc now.
Sources:
recent git has a global hook install
Right, core.hooksPath (since Git 2.9). Set it once globally and every repo picks it up:
git config --global core.hooksPath ~/.githooks
The catch is it replaces the per-repo .git/hooks directory rather than chaining with it. So if a repo has its own hooks (husky, pre-commit, etc.), they stop running.
git-ai sidesteps this by installing as a git shim on PATH instead of using core.hooksPath -- it intercepts all git commands and runs its hooks before/after delegating to real git. That way it doesn't conflict with per-repo hooks.
For the traces hook, worth noting both options in the doc -- core.hooksPath is simpler but has the override problem, the shim approach is more compatible but heavier to build.
Sources:
none of this is that complex
You're right, I'm overcomplicating it. Let me simplify the hook section.
also mention some other potential things the github app could do, like allow a user to mention the @traces-com and ask questions aoubt the trace
it could also comment with a summary of tool calls, websites loaded and other details available from the traces
and which agent and model was used
Already covered -- "what models were used" is in the summary sentence. But "which agent" (Claude Code vs Cursor vs Codex etc.) is missing.
also add a markdown export of the trace as another api endpoint
the local traces app then can also import traces automatically from the repo in the current dir when it's launched
also want to think of this as the infra for other kinds of integrations, this is low level connecting the dots between git data and agent traces, the github app, the tui and other integrations (IDEs, agent skills, LSP, MCP) can all use this lowlevel tooling primatives
avoid short punch sentances and avoid all signposting and paralllel construction and restatement
we should also mention the potential for using a custom transport based on gittufs approach: https://gittuf.dev/documentation/contributors/automatic
i liked that list of other things in the beyond the github app section
oops, i commited the doc to main, but want it on a branch to open a pr with, not main
Let me check what happened.
So b6f71ce is the doc commit on main, and 642f89c is where main should be. I can create a branch from the current state, then move main back. Want me to:
git-integration-doc from b6f71ce642f89cThat way the commit lives on the branch and main is clean again.
yes do that
Done. Main is back at 642f89c and the doc commit is on git-integration-doc.
open a pr
we should also get the trace upload process to return an id early, so we can record that into git fast as possible
The external ID is already generated client-side before upload, so the hook can write the note immediately and kick off the upload in the background. Let me make that explicit.
The key insight is that externalId already exists locally before any upload -- the CLI generates it when it first discovers the trace from the agent's datastore. So the note write is instant and the upload can happen async without blocking the commit.
also add gittuff and git-ai as references in the bottom of the doc
commit and push to the pr