linelore
v0.6.0
Published
The lore of a line of code — trace a single line's full history through edits and renames.
Maintainers
Readme
linelore
The lore of a line of code.
git blame tells you who last touched a line. It shows you a single frame.
linelore shows you the whole reel — every commit that shaped one line, back to
its birth, following it across edits and file renames.
$ linelore src/auth.ts:42
the lore of src/auth.ts:42
4 changes · 1y ago → 3d ago
● 3f9a1c2e0 3d ago Ada Lovelace
harden token check against clock skew
- if (exp < now) return false;
+ if (exp < now - SKEW_TOLERANCE) return false;
● a71d4b8c9 4mo ago Ada Lovelace
extract SKEW_TOLERANCE constant
- if (exp < now - 30) return false;
+ if (exp < now - SKEW_TOLERANCE) return false;
✱ 0be2f1a77 1y ago Ada Lovelace
initial auth guard
+ if (exp < now) return false;The same reel lives in a web view — run
linelore serve, paste a GitHub permalink:
Why
Source code records what is true now and discards why it got that way. The
reasoning — the dead ends, the load-bearing weirdness, the "we tried the obvious
thing and it broke" — lives in commit history, PR threads, and people's heads,
never in the file you're reading. linelore is a small step toward recovering
that: point it at a line and it reconstructs the line's story from the one place
the "why" is actually written down.
Tracing works fully offline — it is all built on git log -L. The one
opt-in exception is --why, which brings its
own model.
Install
npm install -g lineloreUsage
linelore <file>:<line> # trace a single line
linelore <file> <line> # same, space-separated
linelore <file> <start> <end> # trace a line range
linelore <file>:<line> --json # structured output for tooling
linelore <file>:<line> --at-head # line numbers are HEAD's, not the working tree's
linelore <file>:<line> --prs # pull in each commit's merging PR discussion
linelore <file>:<line> --why # ask Claude why the line evolved this way
linelore serve # web view: paste a permalink, get the reelUncommitted changes
Line numbers mean what your editor shows. If the file has uncommitted changes,
linelore maps the line back to HEAD before tracing it, so :42 follows the
line you are actually looking at rather than whatever now sits at line 42 of the
last commit:
$ linelore src/auth.ts:42
the lore of src/auth.ts:42
uncommitted changes above · that's HEAD 39
...If the line is one you are editing right now, linelore traces the history of
the text it replaced — usually exactly the "why" you were reaching for. A line
you have only just typed has no history, and it says so instead of guessing.
Pass --at-head to opt out and number lines as of the last commit.
Pull-request discussion (--prs)
Commit messages carry the what; the argument usually happened on the PR.
--prs finds the pull request that merged each commit in the reel and pulls
its discussion in — the description, and the review thread with bots filtered
out:
$ linelore src/auth.ts:42 --prs
...the reel, each commit tagged `· PR #7`...
pull requests
#7 Harden auth against clock skew — ada
We saw 30s skew in prod; loosen the check.
bob: should the tolerance be configurable?
… 3 more comments · https://github.com/you/repo/pull/7The terminal shows excerpts; --json carries the full text under a pulls
key. Commits that were pushed directly stay untagged. Works on GitHub remotes;
public repos need no credentials (set GITHUB_TOKEN for private repos or more
rate-limit headroom, and GITHUB_API_URL for GitHub Enterprise-style hosts
that serve the same API). A failed lookup never costs you the reel — it still
prints, with the error on stderr.
Intent synthesis (--why)
The reel shows what changed; --why asks Claude to read the arc and say
why. It appends a short synthesis after the reel (or a why field to
--json output):
$ linelore src/auth.ts:42 --why
...the reel...
why
The check was born strict and loosened deliberately: clock-skew failures
pushed an exact comparison toward a tolerance window, and the constant
extraction that followed was housekeeping around that same decision.It is opt-in and bring-your-own-key. Three providers are supported:
| --provider | Key | Default model | Notes |
| --- | --- | --- | --- |
| anthropic (default) | ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN | claude-opus-4-8 | ANTHROPIC_BASE_URL honored |
| mistral (alias: vibe) | MISTRAL_API_KEY | mistral-large-latest | Mistral Vibe accounts work here |
| openai | OPENAI_API_KEY | — (--model required) | any OpenAI-compatible endpoint via OPENAI_BASE_URL, e.g. OpenRouter or a local Ollama |
--model <id> overrides the default. The prompt instructs the model to say
when the record is too thin to support a conclusion rather than invent one.
Combine with --prs and the PR discussions join the evidence the model reads.
Everything outside --prs and --why works offline; nothing talks to a
network unless you ask.
Web view (linelore serve)
Run linelore serve inside a clone and it hosts the reel on localhost
(port 5673 — LORE on a phone keypad; --port overrides). Paste a GitHub
permalink — the kind the y key mints, …/blob/<sha>/<path>#L42 or
#L40-L55 — or a plain file:line, and the page renders the same reel as
the terminal, dark and monospaced.
Permalinks are traced at their pinned ref, so the line numbers mean what
GitHub showed, even if your checkout has moved on. Branch permalinks work
too, including branch names with slashes. Tracing is done by your local
clone; nothing leaves your machine, and permalinks for a different repo than
the served one are refused rather than guessed at. The URL updates as you
trace (?t=…), so a reel can be shared with anyone else running
linelore serve in the same repo.
Roadmap
- [x] Trace a line range through history via
git log -L(offline, zero-dep) - [x] Structured
--jsonoutput - [x] Intent synthesis — an optional layer that reads the arc of changes and
summarizes why the line evolved the way it did (opt-in, brings its own
model):
--why - [x] Follow a line whose number has drifted in the working tree
- [x] Pull in the merging PR's discussion for each commit:
--prs - [x] A web view: paste a permalink, get the reel:
linelore serve
Development
npm install
npm run build # tsc → dist/
npm run dev -- src/foo.ts:10
npm testZero runtime dependencies. Requires Node ≥ 20 and git on PATH.
License
MIT
