Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wherefore

git blame tells you who and what. wherefore tells you why — and makes recording the why as cheap as making the change, so it never needs recovering.

Git-native: whys live in Why: commit trailers and git notes (refs/notes/why). No server, no database, nothing to run. The ledger is versioned with the repo and travels with it.

One command: why.

Install

npm link        # exposes `why` on PATH (or run: node why.mjs ...)

Node ≥ 18, and git on PATH. That's the whole dependency list.

Record

# zero tooling — a trailer on the commit itself:
git commit -m "Raise webhook timeout" -m "Why: payment retries spike past 5s under load"

why add -m "Stripe counts per-minute windows, not rolling"      # annotate HEAD after the fact
why add -f src/limiter.ts:40-44 -m "headroom for retries" -t perf   # anchor to code
why add -c 3f2a1c9 -m "..."                                     # annotate any commit

Recover

why show src/limiter.ts:42    # blame the line, walk its history, print every recorded why
why show src/limiter.ts       # whole-file why chain
why log                       # the whole ledger, newest first
why log src/limiter.ts        # filtered to one path
why log --md                  # appendable markdown section (DECISIONS.md interop)
why show ... --json           # machine-readable, for agents and tooling
why search "rolling window"   # full-text search this repo's ledger, no path needed

why show exits 2 when nothing is recorded — "not recoverable from the ledger" is a first-class, scriptable answer. It never invents a reason. That exit code is the point of the tool for automation: an agent or script can be told to ground its explanation in the ledger and stay silent when the ledger is, instead of confabulating a plausible-sounding rationale.

Anchored line ranges are drift-tracked: each entry records the commit its coordinates refer to, and show/log map them to current HEAD via diff hunks (lines 40-44→43-47). A range whose code was rewritten is flagged (edited since) and always shown — hiding a why is a worse failure than showing a stale one. Notes anchored to lines their commit never touched (after-the-fact why add -f) are found by a full anchored-entry scan, not just the blame chain. Renames of anchored files aren't followed — re-anchor after a rename.

Share

why sync            # push/pull refs/notes/why with origin
why sync upstream
why hook install    # pre-push hook: every push carries the ledger automatically

Notes don't travel with plain git push; run why sync (or install the hook once per repo) to share the ledger. Merging uses cat_sort_uniq — the ledger is append-only, so syncs never conflict. The hook never blocks a push and refuses to clobber an existing pre-push (husky repos: add the one-liner manually).

DECISIONS.md interop

If your repo keeps a human-facing DECISIONS.md, treat it as the record of record and never overwrite it. Append the ledger as its own section instead:

why log --md >> DECISIONS.md

Cross-repo search and citation

The ledger is per-repo by design — git notes don't span repos, and a why answers for the repo it's asked in. When a decision in one repo is really justified by another (a shared schema repo's migration, a sibling service's incident), cite it as plain text; no special syntax exists or is needed:

why add -m "per schema-core@a1b2c3d: rate table pinned to v4" -f src/rates.ts:12

why fleet then makes that citation findable without knowing which repo it lives in — it walks every git repo directly under the current directory and searches all of their ledgers at once:

cd ~/code
why fleet                       # every recorded why, across every repo, newest first
why fleet "rate table"          # filtered by text, across every repo
why fleet ... --json            # machine-readable

Set WHEREFORE_FLEET_ROOT to search from elsewhere without cd-ing there. Each row is tagged with its repo name. Repos with no ledger just contribute nothing — they aren't an error.

Scope

wherefore records code intent only. Regulatory or compliance rule provenance belongs in your compliance system of record, where it can be audited as rules — don't launder it into code annotations here. Keep this ledger about why the code is the way it is.

How it works

  • TrailersWhy: lines are parsed straight off the commit message (git log --format=%(trailers:key=Why)), so the cheapest possible capture needs no tool at all.
  • Notes — everything added after the fact lives as JSONL in refs/notes/why, one ref for the whole repo. Reads are batched (git cat-file --batch + git log --stdin) so the ledger costs the same handful of git spawns whether it holds ten entries or ten thousand.
  • Recoverywhy show <file>:<line> blames the line, walks its history with git log -L, and also scans every file-anchored note, then prints each recorded why in order.

Test

node test.mjs

One self-contained check: it fails if capture, recovery, chain-walking, drift tracking, batched reads, --md export, cross-repo fleet, hook install, or the exit codes break.

License

MIT

About

Record and recover the WHY behind code. A git-native decision ledger — Why: trailers + git notes, no server, and it never invents a reason.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages