Skip to content

Give your AI agent a memory: semantic git search with git-semantic-bun

· 7 min read

Every time you start a new session with an AI coding agent, you’re onboarding a new hire. A talented one — but one who has never seen your codebase before, doesn’t know why the authentication flow was rewritten last month, and has no idea that the retry backoff bug was fixed three weeks ago in a commit titled “edge case when upstream 503s during token refresh.”

The agent can read your current code. It can’t remember your project’s history.

git log --grep exists, but it matches exact strings. When the question is “that commit where we fixed the race condition in auth” — fuzzy, human, imprecise — keyword search falls apart. That’s the gap git-semantic-bun fills: semantic search over your git history, running entirely on your machine.

The context gap

The major AI coding tools — Claude Code, Cursor, Codex — have surprisingly limited access to git history.

Claude Code can run git log through its shell, but that’s raw text output that the agent has to parse and reason over. The official MCP git server exposes git_log and git_show, but these are keyword-based lookups — you need to know what you’re looking for. Cursor had an @Git feature for browsing historical commits, but silently removed it in late 2025. OpenAI’s Codex CLI runs in an environment where git log shows only a single grafted commit.

Pete Hodgson put it well: “every time you reset the context or start a new session, you’re working with another brand new hire.” The agent suggests patterns you deliberately removed. It re-introduces bugs you already fixed. It contradicts architectural decisions made two sprints ago — because it simply can’t see them.

The theaistack.dev community developed a workaround: run git log main..HEAD --oneline --name-status at the start of every session and inject the results into the agent’s context. It helps, but it’s blunt — a chronological dump with no ranking, no relevance filtering, and no semantic understanding.

What agents actually need is the ability to ask: “find commits related to rate limiting in the payment service” and get ranked, relevant results back.

What git-semantic-bun does

gsb (the CLI command) embeds every commit message into a vector space using Transformers.js and ranks search results by a weighted blend of semantic similarity, BM25 lexical overlap, and recency. Everything runs locally — no API keys, no cloud services, no data leaving your machine.

bash
# Install
bun add -g github:danjdewhurst/git-semantic-bun

# Initialise and index
gsb init
gsb index

# Search by meaning
gsb search "fix race condition in auth token refresh"

The search is fuzzy by design. “fix the retry backoff” will surface a commit titled “edge case: exponential backoff resets on 503” even though none of those words overlap exactly. The hybrid ranking ensures that lexically similar results still rank well, while the recency weight gently favours recent commits — useful when an agent needs to understand the current state of a codebase rather than archaeology from three years ago.

Built for machines

The feature that makes gsb particularly useful for AI agents is gsb serve — a warm daemon that accepts queries over stdin and returns structured JSON over stdout.

bash
gsb serve --jsonl -n 5

The daemon loads the embedding model and index once, then processes queries line by line. No cold start penalty per query. This is the exact interface pattern that tool-using agents expect: send a string in, get structured data back.

bash
# Pipe queries from an agent
printf "token refresh race condition\nretry backoff edge case\n:quit\n" \
  | gsb serve --jsonl -n 3

Each response is a self-contained JSON object with ranked results, scores, commit hashes, authors, dates, and messages. An agent can parse this directly without any text extraction heuristics.

For one-off queries, --format json works with the standard search command:

bash
gsb search "payment retry logic" --format json --min-score 0

The --min-score 0 default for JSON output means agents get the full ranked list and can apply their own relevance thresholds. For longer, more descriptive queries — the kind an agent might construct when trying to understand a broad area of the codebase — --query-file reads the query text from a file rather than a shell argument.

What agents would do with this

Semantic git search becomes useful at every stage of an agent’s workflow:

Before proposing a change — search for related past commits to understand what’s been tried, what patterns exist, and what was deliberately removed. An agent working on error handling in the webhook system could search for “error handling webhook retry” and discover that exponential backoff was added six months ago, that a specific edge case was patched last week, and that an earlier approach using a dead-letter queue was reverted.

Understanding intentgit blame tells you who changed a line and when. Semantic search tells you why. When an agent encounters an unusual code pattern, it can search for the commit that introduced it and read the message explaining the reasoning — “workaround for upstream API returning 200 on partial failure” is the kind of context that prevents an agent from “cleaning up” a deliberate hack.

Avoiding regressions — one of the most common complaints about AI agents is that they re-introduce patterns that were deliberately removed. A search for “remove deprecated auth middleware” before suggesting changes to the auth stack would surface the commit that removed it and the reasoning behind the removal.

Building PR context — when an agent generates a pull request description, semantic search over the branch’s diff context can surface related historical changes, giving reviewers the full picture without manual archaeology.

Under the hood

The ranking system blends three signals, each with a configurable weight:

  • Semantic similarity — cosine distance between the query embedding and each commit message embedding, using all-MiniLM-L6-v2 (384 dimensions) by default
  • BM25 lexical overlap — classic information retrieval scoring that rewards exact term matches, cached per index checksum for fast repeated queries
  • Recency boost — a gentle decay function that favours recent commits without burying older results

The --explain flag shows the score breakdown per result, which is useful for tuning weights:

bash
gsb search "auth token refresh" --explain

Storage is compact. Embeddings default to f32 but support f16 for half the disk usage. Everything lives inside .git/semantic-index/ — nothing outside your repository. gsb update incrementally indexes only new commits, with built-in detection for rebases and force-pushes.

For very large repositories (10k+ commits), an optional approximate nearest-neighbour backend via usearch reduces vector lookup to sub-millisecond:

bash
bun add usearch
gsb index          # builds HNSW index alongside the standard one
gsb search "fix bug" --strategy ann

When usearch isn’t installed, everything falls back to exact brute-force search transparently. For most repositories, brute-force is already fast enough.

Extensible via plugins

gsb has a plugin system that lets you swap out or extend nearly every component. For AI agent workflows, the most interesting extension points are custom embedders and hooks.

A plugin that uses an Ollama model instead of the built-in Transformers.js embedder:

typescript
import type { GsbPlugin } from "git-semantic-bun/plugin";

const plugin: GsbPlugin = {
  meta: { name: "ollama-embedder", version: "1.0.0" },

  createEmbedder(modelName, cacheDir) {
    if (!modelName.startsWith("ollama/")) return undefined;

    return Promise.resolve({
      modelName,
      async embedBatch(texts) {
        const res = await fetch("http://localhost:11434/api/embed", {
          method: "POST",
          body: JSON.stringify({ model: modelName.slice(7), input: texts }),
        });
        const data = await res.json();
        return data.embeddings;
      },
    });
  },
};

export default plugin;

Drop this in .gsb/plugins/ and run gsb index --model ollama/nomic-embed-text. Plugins can also add custom scoring signals (e.g. penalising merge commits), output formatters, commit filters, and lifecycle hooks that transform queries or results before they reach the agent.

Getting started

bash
# Install from GitHub
bun add -g github:danjdewhurst/git-semantic-bun

# Or download a prebuilt binary from
# https://github.com/danjdewhurst/git-semantic-bun/releases

# Index your repo
cd your-project
gsb init
gsb index

# Try a search
gsb search "that bug where the cache wasn't invalidating"

# Start the daemon for agent integration
gsb serve --jsonl -n 10

The initial index takes a few seconds for most repositories (the embedding model downloads on first run at ~80MB). After that, gsb update handles incremental indexing in milliseconds.

The broader point is simple: AI agents make better decisions when they can see project history, and keyword search isn’t good enough for the fuzzy, intent-based questions that actually matter. Semantic search over git commits is a low-effort way to give agents the memory they currently lack — locally, privately, and in a format they can consume natively.

The source is on GitHub. MIT licensed. PRs welcome.

If you enjoyed this, you might also like

👤

Written by

Daniel Dewhurst

Lead AI Solutions Engineer building with AI, Laravel, TypeScript, and the craft of software.