Private preview · pre-release · October 2026

Engineering memory for Git commits

Know why the code is the way it is. Before you change it.

GitStory keeps the reasons behind landed code. It collects evidence while the work happens (agent sessions, tests, notes and Git) and distills it into a short story: the decisions, the approaches that were rejected, and the questions nobody answered. Every claim is cited and checked against the code that actually landed.

1import time2import uuid34def charge(client, order):5    # One key for every attempt6    key = str(uuid.uuid4())7    for attempt in range(3):8        try:9            return client.charge(10                order.id, idempotency_key=key)
$ git story blame billing/retry.py:5-10 --brief
st_01m5aa3y  0e841b8f  Reuse one idempotency key across charge retries
currentst_01m5aa3y·commit 0e841b8f·landed

The charge retry loop reuses one idempotency key across attempts, so a retry after a timeout cannot charge twice.

Decisions

  • Generate one key before the retry loop and pass it to every attempt.observed · diff
  • Reuse the key because the provider deduplicates on it.stated · note

Rejected

  • A Redis lock around charge(): it cannot help once the provider already processed the first request.stated · session

Unknowns

  • What idempotency guarantees and retention period the provider enforces.
Blame a few lines and get the story behind them. An agent sees the rejected Redis lock before it tries it again.

Distilled decisions, not transcripts

Claims without cited evidence that survive validation
0
Raw session transcripts sent to a model
0
Changes to Git commits, messages, refs or notes
0
PRD acceptance scenarios passing as tests
15/15

Scrubbed, typed evidence goes to the model, never the raw log. Every call is listed in an egress manifest stored with the story.

01 · The problem

The code survives. The reasons behind it don't.

Every change carries decisions: why this approach, what was tried first, which constraint ruled out the obvious fix. Today that lives in a chat session, a CI log or someone's head, and it's gone by the time the next person, or the next agent, touches the code.

  • Commit messages say what, rarely why. And never what was tried and dropped.
  • Agents repeat rejected approaches. Nothing tells them the lock was tried and failed.
  • Transcripts are the wrong record. They're huge, they leak secrets, and nobody rereads them.
  • Old decisions go stale silently. A reason that held last quarter may not hold now, and nothing says so.

02 · With and without

Six weeks later, an agent is asked to simplify the retry loop.

An illustrative example. The code is the one in the figure above. Charges sometimes take three attempts, and the task is to clean up billing/retry.py.

Without GitStory

  1. Reads the file and git log: "Use an idempotency key across charge retries (#12)". Nothing says why the key must be shared.
  2. Moves key creation into the loop so each attempt starts clean, or adds a Redis lock around charge(). That lock was already tried and dropped.
  3. The tests pass: none of them covers a timeout after the provider already charged.
  4. Double charges come back in production.

With GitStory

  1. Runs git story blame billing/retry.py:5-10 --brief before editing.
  2. Learns the decision: one key for every attempt, because the provider deduplicates on it.
  3. Sees the rejected Redis lock and why it fails, so it doesn't try it again. The open question about the provider's retention window goes to a human instead of a guess.
  4. Simplifies the loop, keeps the key shared, and records its own reason with git story note.

03 · How GitStory works

Evidence while you work.
A story when it lands.

Git

holds what changed: commits, diffs, history.

GitStory

holds why: cited decisions, rejected options and unknowns, bound to the landed commit.

ghf, optionally

holds what was tried. GitStory cites its checkpoints when it's installed.

Collect evidence

Notes, test results, commits and Claude Code session logs become typed, scrubbed evidence events, kept on your machine. Record a decision as you make it with git story note.

Draft and land

Hooks draft in the background, so nothing waits on a model. After the merge, git story land reconciles the drafts with the code that landed. Approaches dropped in review never become decisions.

Ask why

blame, path, history and search return the stories behind lines and files. They follow supersedes links to the decision that holds now.

Memory that stays current

When a change reverses an earlier decision, it says so with --supersedes. Blame on any line the old decision still covers also returns the story that replaced it, marked current.

$ git story note "Bring the Redis lock back: versioning missed cross-row writes" \
    --supersedes st_01m5b
$ git story blame lock.rs:3
st_01m5b  2870d7da  Remove the lock; row versioning replaces it [superseded]
st_01m5c  9a1c44e0  Reintroduce the Redis lock for cross-row writes   (current; supersedes st_01m5b)
$ git story history st_01m5c
st_01m5a  5d07be21  Add a Redis lock [superseded]
st_01m5b  2870d7da  Remove the lock [superseded]
st_01m5c  9a1c44e0  Reintroduce the lock
  1. superseded

    A · Add a Redis lock

    Retries were double-charging customers.

  2. superseded

    B · Remove the lock

    Row versioning replaced it. Proposed as superseding A by blame, then accepted.

  3. current

    C · Bring the lock back

    Versioning missed cross-row writes. Explicitly supersedes B.

Better with ghf

ghf keeps what was tried.
GitStory keeps why it landed.

ghf is GitStory's sibling: high-frequency source control for AI agents. It saves the worktree after every agent edit, so any checkpoint can be restored, diffed or forked. The two answer different questions and keep their data for different lengths of time.

ghf

What state was the code in, and can I get back to it? Every edit is a checkpoint. Traces are pruned 30 days after the work lands.

GitStory

Why is the code this way? A few cited decisions per change, bound to the landed commit, kept as long as the code matters.

Git

What changed? Commits and diffs, untouched by either tool.

Checkpoints become evidence

GitStory reads ghf traces through ghf's public CLI. It cites the attempts, and each checkpoint's tests=pass or tests=fail annotation.

Holds until the story lands

GitStory places a hold on each trace it reads, so ghf won't prune it while the work is open. It releases the hold once the story lands.

Stories outlive traces

A story keeps the durable part of every event it cites. After ghf prunes the trace, the story still validates.

Independent by design

Neither needs the other. ghf doesn't know GitStory exists, and GitStory works with plain Git.

Trustworthy by construction

A story is only as good as its evidence.

Every claim is cited

Each decision, rejected option and test result cites evidence events. A claim that cites nothing, or cites something that doesn't exist, is dropped.

Guesses stay labeled

A model's own reading goes in hypotheses, never in decisions. --brief leaves hypotheses out, so agents never treat a guess as a constraint.

A separate validation pass

A second call checks every claim against its cited evidence and the landed diff. Test claims are checked mechanically against the recorded pass and fail counts.

Durable on its own

Each claim stands on the stored part of its evidence. Delete the session log or lose the CI link, and git story validate still passes.

Secrets never leave

Keys, tokens, .env values and high-entropy strings are scrubbed before anything is stored or sent. .storyignore keeps paths and drops their content.

You decide what leaves

One gate checks every model call against your egress policy and trusted endpoints. With inference = local, no request leaves the machine. Each call is recorded in a manifest.

Built for agents

Built for agents to call

The agent skill teaches the habit: blame before changing existing code, note real decisions as they happen, supersede on purpose. Every command takes --json and returns one versioned envelope.

  • Agent skill, installed with git story skill install
  • Background drafting hooks for Claude Code and Git
  • Versioned --json, stable error and exit codes
  • No prompts, ever
{"schema":"gitstory.cli/v1","command":"blame","ok":true,
 "data":{"path":"billing/retry.py","range":[5,10],"stories":[
  {"current":true,"via":"blame","story":{
   "story_id":"st_01m5aa3y…","status":"current",
   "summary":"Reuse one idempotency key across charge retries",
   "decisions":[{"claim":"Generate one key before the loop…","type":"observed"}],
   "rejected":[{"claim":"A Redis lock around charge()…","type":"stated"}],
   "unknowns":["What guarantees the provider enforces"]}}]}}

Your store

Stories live where you put them

Stories, cited evidence, links and egress manifests are plain JSON in a store you choose. A local SQLite index makes lookups fast, and it can be rebuilt from the store at any time.

  • A local directory, or S3 and compatible stores, shared by the team
  • Export and import with nothing lost
  • Append-only link log, with proposals reviewed before they apply

Quick start

  1. Install and enable a repository

    cargo install --path cli        # from a GitStory checkout
    git story init                  # writes .gitstory; commit it
    git story trust                 # allow the configured model endpoint
  2. Collect while you work

    git story hooks install claude-code
    git story skill install
    git story note "Use row versioning instead of a Redis lock because CI has no Redis"
  3. Land, then ask

    git story land --work-unit feat/retry --to origin/main
    git story blame src/lock.rs:40-80 --brief

The model is configured in .gitstory: Anthropic, OpenAI, an OpenAI-compatible local server, or any command. The CLI reference covers the rest.

Give every change its reasons.

Works with plain Git, with or without ghf.

Private preview. GitStory is in early development, and the name is a working title. Anything can change before a first release, including commands, the story schema and the store format.