Engineering

How git blame powers Sticky Note's attribution engine

April 10, 20265 min read
GitAISticky NoteDeveloper ToolsAttribution

How git blame powers Sticky Note's attribution engine

Sticky Note uses git blame, Git Notes, and a three-tier fallback
pipeline to figure out which AI session wrote which lines of code.
Here's how the whole thing works.


The problem

You're an AI coding assistant. A developer asks you to edit
src/auth/refresh.ts. You open the file and see 200 lines of code. What
you don't know is that Alice spent three hours last week rewriting lines
45–80 to fix a token refresh race condition — and she left a stuck thread
because the fix broke integration tests.

Without context, you might blunder into those same lines and repeat her
mistakes. With context, you'd know exactly what she tried, what failed,
and what's left to do.

That's what Sticky Note's attribution engine is for.


The core idea

Every time an AI assistant edits a file, Sticky Note records metadata
about the session on the resulting commit. Later, when any assistant
touches that file, Sticky Note runs git blame to discover which commits
produced which lines, resolves those commits back to sessions and threads,
and injects the relevant context before the tool executes.

The result: your AI knows Alice worked on lines 45–80, what she was doing,
and what went wrong — before it reads a single line of the file.


How it works

Recording attribution (the write path)

When an AI session makes edits and the work gets committed, Sticky Note's
session-end.js hook writes attribution data to the commit using
Git Notes:

git notes --ref refs/notes/sticky-note add -f -m '<commit-sha>

The JSON payload looks like this:

[
  {
    "session_id": "062383e7-6223-490a-95d2-839e075752d1",
    "user": "alice",
    "file": "src/auth/refresh.ts",
    "type": "ai_edit",
    "ts": "2026-03-08T21:15:52.373Z",
    "lines_changed": ["45-80"],
    "checkpoint": "fixing token refresh race condition"
  }
]

This metadata lives in a separate Git ref (refs/notes/sticky-note).
It doesn't modify the commit SHA, doesn't pollute the commit message,
and won't show up in git log unless you ask for it.

As a backup, the same session info is also written to the audit JSONL
file (.sticky-note/audit/<user>.jsonl), which provides a second
resolution path.

Reading attribution (the read path)

When a tool call fires — Read, Edit, Write, Bash — the pre-tool-use.js
hook intercepts it and extracts the target file path. Then the attribution
engine kicks in:

Tool call: Read("src/auth/refresh.ts")
    │
    ▼
pre-tool-use.js intercepts
    │
    ▼
git blame --line-porcelain src/auth/refresh.ts
    │
    ▼
Parse output → { line 45: sha abc123, line 46: sha abc123, ... }
    │
    ▼
For each unique SHA → three-tier resolution
    │
    ▼
SHA → session_id → thread → inject context

Three-tier SHA resolution

This is where it gets interesting. A commit SHA alone doesn't tell you
which Sticky Note session produced it. The attribution engine resolves
SHAs to sessions using three fallback tiers:

Tier 1: Git Notes (fast and reliable)

git notes --ref refs/notes/sticky-note show <commit-sha>

This is the primary resolution path. If the commit was made while Sticky
Note was running, there's a note attached. The lookup is essentially
O(1) — Git hashes the SHA and finds the note object directly.

Tier 2: Audit JSONL (fallback for missing notes)

If Tier 1 misses — the note was never written, got dropped during a
rebase, or the repo was cloned without --notes — the engine falls back
to scanning the audit log:

.sticky-note/audit/<user>.jsonl

Each line is a JSON record. The engine does a fast string includes(sha)
pre-filter before parsing, so it only deserializes lines that might match.

Tier 3: Heuristic matching (last resort)

If both Tier 1 and Tier 2 miss, the engine falls back to heuristics:
commit timestamp + author email matched against session records. This
handles squash merges and external commits that happened to touch the
same file.


Useful Git Notes commands

List all annotated commits

git notes --ref refs/notes/sticky-note list

Returns one line per commit SHA that has a sticky-note attribution attached.

Read a specific note

git notes --ref sticky-note show <commit-sha>

Returns the raw JSON array of attribution entries for that commit.

Smart resume using attribution

npx sticky-note resume-thread --query "token refresh race condition"

This searches threads by text similarity and boosts results whose
git-blame-attributed files overlap with your query context.


Performance

The attribution engine needs to be fast since it runs in the
PreToolUse hook:

Operation Budget Notes
git blame --line-porcelain 10s timeout Runs once per file per tool call
Git Notes lookup per SHA 3s timeout Usually <50ms; only unique SHAs checked
Audit JSONL scan No timeout Fast string includes() pre-filter before JSON parse
Heuristic fallback 3s per SHA Only reached if Tier 1 and 2 miss
Total attribution budget 500ms target Most files resolve in <200ms via Tier 1

The engine short-circuits: as soon as a higher tier resolves a SHA, lower
tiers are skipped. For repos with Git Notes configured (the default after
npx sticky-note init), nearly all attribution resolves via Tier 1 with
no fallback needed.


Wrapping up

The basic idea is simple: git blame already knows who wrote each line.
Sticky Note adds a layer on top that maps commits back to AI sessions
and threads, so the next assistant to touch the file knows what happened
last time. Three fallback tiers handle the messy cases (rebases, squash
merges, missing notes), and the whole thing runs automatically after
npx sticky-note init.