I rebuilt the install for my 'git blame for AI' tool — six steps became one

Published: (April 30, 2026 at 09:27 PM EDT)
9 min read
Source: Dev.to

Source: Dev.to

A week ago I shipped Selvedge, an MCP server that captures why AI agents change code

Quick context (if you missed the first post)

AI agents write code with full intent in the moment, and then the session ends and the intent is gone. Selvedge captures that intent live, by the agent, while it’s still in context. Six months later you can run:

selvedge blame users.email

and get an actual sentence back about why the column exists.

The original launch did fine: a few hundred installs, a handful of stars, one post on each of dev.to and HN that converted better than I expected. Nothing dramatic, but the shape of where people dropped off was instructive, and that’s what the v0.3.4 release I shipped this weekend is mostly about.

The install was the bottleneck and I was kidding myself

I knew the install wasn’t great. The first version of the README walked you through six things:

  1. pip install selvedge
  2. cd your-project && selvedge init
  3. Open ~/.claude/config.json and add an mcpServers.selvedge block. Hope you got the JSON right.
  4. Open your project’s CLAUDE.md (or create one). Paste in the system prompt that tells the agent to call log_change whenever it touches a column, function, env var, or dependency.
  5. selvedge install-hook so post‑commit can link events to commits.
  6. Restart Claude Code, because the MCP config doesn’t hot‑reload.

Four flips between the README and your editor. One of those steps — number three — is “edit a JSON file by hand,” which kills curiosity in about eight seconds. And number five, the post‑commit hook, silently failed on macOS when you committed through a GUI client like Tower or GitKraken, because git launches with a stripped PATH and selvedge isn’t on it. I wrote selvedge doctor in v0.3.2 specifically because of that bug. The bug existed because the install didn’t surface that the hook was even there to fail.

What actually happened in the install metrics is roughly what you’d expect:

  • People pip install‑ed.
  • Some ran selvedge init.
  • A much smaller fraction ever made it to the point where tool_calls started arriving at the server — the only thing I actually care about.

The JSON edit and the CLAUDE.md edit are where the cliff is.

v0.3.4: One‑command setup

v0.3.4 collapses all of that to one command:

pip install selvedge
cd your-project
selvedge setup

The wizard:

  • Reads ~/.claude/config.json, ~/.cursor/mcp.json, and looks for .github/copilot-instructions.md — whichever of those you actually have.
  • Writes the MCP entry.
  • Drops the system‑prompt block into your CLAUDE.md or .cursorrules, sentinel‑bracketed so the next time I update the recommended block you can re‑run selvedge prompt --install and it patches in place without disturbing the rest of your file.
  • Runs selvedge init.
  • Installs the hook.
  • Writes a .bak next to every file it touches before any change reaches disk, so if it makes a wrong call you can revert.

Re‑running on an already‑set‑up project is a no‑op. For CI or devcontainer.json’s postCreateCommand you can use:

selvedge setup --non-interactive --yes

That’s it. The “interesting” parts of Selvedge — live reasoning capture, entity‑level history, changesets — are useless if nobody gets past the install. Six manual steps were burning everyone who would have otherwise tried it. One command isn’t.

On not being alone in the category anymore

Another thing that changed since the launch post: the “git blame for AI” space has gotten crowded fast. AgentDiff, Origin, Git AI, BlamePrompt — all real tools, all active, several backed by named teams. When I posted the first article a week ago I knew about basically one direct competitor. Now I have four or five.

That’s actually fine. It means the problem is real enough that more than one person decided to work on it. But it does mean I should be specific about what’s different, because if you read every tool’s README in isolation you’d reasonably conclude they’re all doing the same thing.

What’s actually different? When the reasoning gets captured

ToolReasoning sourceGranularityMechanism
SelvedgeCaptured live, by the agent in the same context that produced the changeEntity (DB column, table, env var, dep, API route, function)MCP server — agent calls it as work happens
AgentDiffInferred post‑hoc by Claude Haiku from the diff at session endLineGit pre/post‑commit hook
OriginCaptured at commit timeLineGit hook
Git AIAttribution metadataLineGit hook + Agent Trace alliance
BlamePromptPrompt‑onlyLineGit hook

Most of these tools wait until commit time and then ask a second LLM to look at the diff and explain what changed. That’s a reasonable approach and the output looks fine on first read, but it isn’t the actual reasoning the agent had — the agent had the prompt, the conversation history, the user’s actual ask, and a model’s interpretation of all of it. The post‑hoc explainer only sees the diff, so it generates something plausible.

Plausible isn’t always right.
If you migrated from INTEGER cents to DECIMAL(10,2) because a user reported rounding errors on international transactions, that’s the actual reason. If a second LLM looks at the diff months later, it’ll write something like “improved precision for monetary values” — true in a generic sense, useless when you’re trying to figure out which currencies you should regression‑test next time.

Selvedge’s reasoning is whatever the agent that made the change wrote. It comes from the same context window that produced the change. There’s no second model and no inference. And because it’s whatever the agent had, an empty reasoning field is itself useful information — it means the agent didn’t have a reason to record.

Entity Attribution, Briefly

The other thing that’s a bit different: most tools attribute lines. Selvedge attributes things.
When you investigate something in your codebase you don’t search “lines 40 through 48 of users.py”; you search for users.email, STRIPE_SECRET_KEY, or /api/v1/checkout. That’s what Selvedge stores:

users.email           DB column
users                 DB table
src/auth.py::login    Function in a file
api/v1/users          API route
deps/stripe           Dependency
env/STRIPE_SECRET_KEY Environment variable

selvedge diff users returns events for users, users.email, and anything else under users.. The same works for any prefix.

I debated whether to also attribute lines (more granular, like other tools) and decided not to. Lines drift. Renames break attribution. Refactoring a function into three files invalidates everything that referenced the original location. Entities are sticky in a way that lines aren’t.

Changesets

Another thing Selvedge offers that I haven’t seen elsewhere is changesets—a slug you can attach to any event, so later you can pull every event for a feature back, regardless of how many entities it touched or how many PRs it spanned.

Example: Stripe billing.
A real billing rollout in a real codebase touches new columns on users, two new env vars, three new API routes, a new dependency, four functions across the codebase, and lands as eight smaller PRs over a month because nobody wants to review one mega‑diff.

Six months later someone has to audit which lines of code touch payment data— for compliance, an incident, or a refactor. git log is useless for this. Each PR is generic (“update billing”, “wire webhook”, “fix typo in migration”) and the cross‑cutting nature is gone.

If every event in that work was tagged changeset:add-stripe-billing, you can run:

selvedge changeset add-stripe-billing

and get every event from every entity that was part of it, with the agent’s reasoning on each. It’s a roll‑up view. Nobody else stores it (as far as I can tell) because it requires capturing reasoning at the per‑change level, which only works if you’re capturing live.

Agent Trace

A few people DM’d me about Agent Trace after the first article. Cursor and Cognition put out an RFC in January for an open standard for AI code‑attribution traces: JSON records, file/line granularity, deliberately storage‑agnostic. Cloudflare, Vercel, Google Jules, Amp, OpenCode, and git‑ai are all signed on.

Selvedge isn’t competing with that; it’s a producer for it.

  • Agent Trace = the wire format.
  • Selvedge = one way to populate that wire format (live, from the agent, at the moment the change is made).

The export design lives at docs/agent-trace-interop.md. I’ll ship the actual selvedge export --format agent-trace flag in v0.3.5 or v0.4.

Try It

pip install selvedge
cd your-project
selvedge setup

Then start an agent session in that directory, make a non‑trivial change, and in a separate terminal run:

selvedge watch

You should see events stream in as the agent calls log_change. Once a few have landed:

selvedge blame

The reasoning was captured live—that’s the whole product.

If nothing appears in selvedge watch, run:

selvedge doctor

It will tell you which step is silently broken (there are still edge‑cases that can be silently broken; I’m working on them).

What’s Next, and What I Want Feedback On

Phase 3 of the roadmap is the team‑sync story—Postgres backend, an HTTP API, multiple developers sharing history without sharing a SQLite file. I don’t have a date on it yet. The local SQLite version is fully featured for solo devs and small teams who are fine sharing a file.

Feedback request: When you try this, where does selvedge setup pick the wrong default? The Cursor and Copilot paths are newer than the Claude Code one—I’ve used them less, and the test coverage exists but isn’t from real‑world usage. If something in the wizard surprises you, opening an issue is the most useful thing you can do.

github.com/masondelan/selvedge — issues and DMs both work.

0 views
Back to Blog

Related posts

Read more »

The smarter the model, the more it saves.

The Myth: Smarter Models Will Make Plugins Redundant Since WOZCODE launched, many Claude Code power users have whispered that the plugin’s advantage will disap...