← All writing
· 4 min readaiengineeringlorekeepersecond-brainopen-sourcetypescript

Shipping Lorekeeper: from a note I couldn't find to npm

How I took Lorekeeper, an offline CLI that finds the passage in your Markdown notes that answers a question, from idea to an npm package, a docs site, an identity and a release pipeline.

I have said "I already wrote this down somewhere" more times than I'd like to admit.

It's usually true. The note exists, in a Markdown file I wrote months ago, under a heading I don't remember. The knowledge is there. It just isn't recoverable, and knowledge you can't recover is about as useful as knowledge you never had.

Lorekeeper started as my answer to that sentence. This week it became a real thing: an npm package, a documentation site, its own identity and a release pipeline. Here are the four decisions I'd make again.

You already wrote it down. Find the passage that answers.

That's the tagline, and the important word is passage.

Lorekeeper is a CLI with three commands. lore init creates a brain, which is just a directory of Markdown, or adopts a vault you already have without rewriting a file. lore capture files a thought or a URL. lore search ranks the passages of that brain against a question.

npx create-lorekeeper@0.1.0 init ~/brain

It runs offline. No account, no API key, no network call, no language model. Node 24+, macOS or Linux.

1. The passage is the unit, not the file

A three-thousand-word note about deployments isn't one fact. It's forty. Return the whole file and you get the answer plus thirty-nine things competing with it, which is bad for me and worse for an agent paying for every byte of context. (The longer version is in Lorekeeper retrieves spans.)

So every result is an address: path, heading, line range, score and text. A real run, asking one question two ways:

$ npx create-lorekeeper@0.1.0 search ~/brain \
    "retry policy" "what happens when the upload fails" --limit 2
notes/deploy-retries.md#When the upload fails:12-13  score 0.0164
~/brain/notes/deploy-retries.md
    The FTP step retries three times with a thirty-second backoff, then gives up.
    If it gives up, re-run the workflow; it only uploads changed files.

notes/README.md#notes:3-8  score 0.0161
~/brain/notes/README.md
    What you have worked out, written in your own words.
    ...

Two lines, not the file. The note never says "retry policy". The second wording found it.

No fake certainty

Look at the second hit. It's a README with nothing to do with retries, scoring 0.0161 against the right answer's 0.0164.

Those numbers aren't confidence. Lorekeeper fuses the ranked lists with Reciprocal Rank Fusion, and 0.0164 is just 1/61, the score for ranking first. A ranking score cannot prove that something is absent. In evaluation, a control question with no answer anywhere outranked real questions that had one.

So there's no relevance threshold. A cutoff would turn an honest miss into a confident "nothing found". Instead, the AGENTS.md that lore init writes tells agents to treat results as evidence, search again in other words, and say "the evidence is insufficient" rather than "your notes don't cover this". I'd rather ship a tool exactly as smart as it is.

Giving it a face

Lorekeeper is one of four tools in my Wonder Wagon family, with Pathfinder, Forge and Lama. Its role is the reading room, the quietest of the four. The mark is a four-point star held in a ring: what was found, and what keeps it.

The Lorekeeper documentation site in day mode.

Day and night each get a measured palette. At a colour terminal, lore --help paints Lorekeeper in periwinkle #99A2F0 and ends with a dimmed serial, LK-047, next to Pathfinder's PF-047 and Forge's FG-047. Piped output and --json carry no escape codes.

The same page at night.

2. Brand consistency as a failing test

The colours live in two repositories. Lorekeeper's tokens.json is the source, and the Wonder Wagon UI library restates nine of those values in its lorekeeper theme. When I promoted that theme from draft to pilot, the night accent changed.

Copied values drift, so both sides now check the same nine-value map. Run against the old Wonder Wagon pin, Lorekeeper's check fails on accent.night and accentInk.night, which is exactly right. Add measured contrast (52 pairs) and byte-for-byte checks on the README images, and "on brand" stops being a review opinion. It's a CI step.

3. One public package, private core

@lorekeeper/core does the real work and is private. The CLI imports it by name, and that import can't survive publishing. npm would look for a package that doesn't exist, and the install would die with a 404.

So the build inlines core into one file, dist/lore.js, with esbuild, then checks its own output: only node:* and yaml imports allowed, and core must actually be inside. A package check on every PR installs the tarball into a fresh prefix and runs the real lore. The build is deterministic, so the sha1 I approved, 3ef401e3…, is the one npm serves today.

4. Release evidence describes what happened

Before the release, the README said Lorekeeper installed from source. True, until release day. I didn't "fix" it early. It changed in the release PR itself, and the docs site waited until the package was actually on npm.

The site enforces this mechanically. Every command output on it is generated from the built binary, and a Vercel build refuses to deploy if that binary reports 0.0.0.

The live CLI reference page showing lore --help reading Lorekeeper 0.1.0.

The version comes from one place, the newest CHANGELOG.md heading, and the release workflow refuses if the manifest, tag or Release disagree. Every step skips work that's already done, so a failed run is re-run, never patched with a new version.

That got tested immediately. The first release run failed because npm@latest installed npm 12, which prints npm pack --json as an object instead of an array. Checks run before publishing, so nothing half-shipped. I taught the script both shapes, re-ran it, and it tagged v0.1.0.

What I learned

Ranking the right passage was the part I expected to be hard. Most of the work after that was making every public claim true: the README colour, the help-screen version, the install line, the tag.

What worked was giving each claim a check a machine runs. None of it is glamorous, but when the release broke on a JSON shape I never touched, nothing shipped broken. It stopped and told me why.

The docs are at lorekeeper-bay.vercel.app and work offline after one visit. The code is on GitHub. If Lorekeeper finds something you forgot you wrote, I'd like to hear about it.

Lamadrid Labs © 2026