LBrain
Beta. Early software from a small team, with no independent security audit yet. Keep backups, as you would with any beta.
Local memory for AI that knows which record to trust.
Your agent can already search your notes. The harder problem starts when your notes disagree.
LBrain retrieves the relevant records, shows where they came from, tells the agent which ones are current, and flags when a record doesn't actually answer the question.
No API key. No account. Your memory stays on your machine.
The two-minute story — our XPRIZE submission.
See it work
Say your project contains two notes.
notes/deploy-flag.md, from March:
Deploys use --safe-mode. Never ship without it.
Then, five months later, notes/deploy-flag-update.md:
--safe-mode is retired. Deploys now use --verify-first.
Supersedes [[deploy-flag]].
Now ask:
$ lbrain query "what flag do deploys use?"
[1] deploy-flag-update · dated 2026-08-02 · binds
│ --safe-mode is retired. Deploys now use --verify-first.
[2] postgres-choice · dated 2026-05-20 · near-miss
[3] team-lunch · near-miss
[4] deploy-flag · dated 2026-03-14 · SUPERSEDED · binds
│ Deploys use --safe-mode. Never ship without it.
Real output from the bundled sample corpus, trimmed for width. Reproduce it yourself: the corpus
ships in examples/demo-corpus, and the terminal-recording script is
examples/demo.tape.
Both deploy notes match the question. Only one is current. LBrain puts the current decision first,
keeps the old one visible but marks it SUPERSEDED, and identifies unrelated matches as
near-miss. So your agent answers --verify-first, with the record that supports it.
And when nothing answers
Ask the same corpus something it doesn't know:
$ lbrain query "what is our production Redis eviction policy?"
[1] redis-evaluation · dated 2026-06-11 · near-miss
│ Evaluated Redis vs Memcached for the session cache. Redis won on data
│ structures and persistence options. Eviction policy discussion deferred
│ until we see production load.
[2] caching-notes · near-miss
...
Every match comes back flagged near-miss: text about Redis exists, a decision about eviction
policy does not, and nothing pretends otherwise. Finding the nearest text and finding an answer are
not the same operation.
That's deliberate. We'd rather give the model a little more reason to say "I don't know" than another reason to be confidently wrong.
What can I give it?
Start with Markdown.
Point LBrain at a directory and it indexes the .md files underneath it, subdirectories included.
Your notes don't need a schema:
---
date: 2026-08-21
type: decision
---
We picked Postgres over SQLite for the API tier because ...
The frontmatter is optional — plain Markdown works. Dates and record types just give LBrain more to work with.
When one decision replaces another, say so on its own line:
Supersedes [[deploy-flag]].
LBrain keeps both records. The newer decision takes precedence without erasing the history that came before it.
PDFs and Word documents? Not directly, yet. Convert the ones that matter to Markdown and keep the originals as your source of truth. The easy way: you already have an agent — tell it "convert the PDFs in ~/docs that are relevant to our work into markdown notes." Agents are good at this, it takes a minute, and you get to review what your memory is about to be made of. That review is the point: extraction quality varies enough that we'd rather have you glance at a conversion than quietly put mangled text into something your AI will later treat as memory.
Try it
You need Python 3.10–3.13 whose SQLite can load extensions, and ~67 MB of disk for the on-device embedding model. No API key, no account, no cloud service. Check the SQLite requirement first:
python3 -c "import sqlite3; print(hasattr(sqlite3.connect(':memory:'), 'enable_load_extension'))"
If that prints False — Apple's /usr/bin/python3 and the python.org macOS installers are built
that way — use Homebrew's (brew install python@3.12). Linux distro packages normally have it
enabled.
pip install "lbrain[local]"
lbrain init --source ~/notes
lbrain import
lbrain embed --stale
lbrain query "what did we decide about the deploy flag?"
Rather kick the tires before pointing it at your own notes? Both examples above run against the bundled corpus:
lbrain init --source examples/demo-corpus
lbrain import && lbrain embed --stale
lbrain query "what flag do deploys use?"
Indexing and search run on-device — your documents and queries are never transmitted. The one network call the local path ever makes is the one-time ~67 MB embedding model download (that is the model coming down, not your notes going up); after that, embedding is fully offline.
[!IMPORTANT] Importing an old archive? A cold import of old notes will serve old decisions as current — a bulk copy resets every file date to today, so newest-wins has nothing to order by. Read this first: either vet it, restore the dates, or knowingly run a calibration period.
Connect it to an agent
Start with AGENTS.md — it is written to the agent itself: how to stand LBrain up
cleanly for its human, and the contract for consuming what it serves.
# Claude Code
claude mcp add lbrain -- lbrain mcp
# Any client that speaks streamable HTTP
lbrain mcp --transport streamable-http --host 127.0.0.1 --port 7370
Five tools over MCP: semantic recall, exact-phrase search, a save-worthiness check, an action check
against your recorded corrections, and corpus statistics. Everything also works from the shell —
lbrain query, search, import, doctor.
Terminal presentation
Choose a semantic terminal theme without changing any served content or brain configuration:
LBRAIN_THEME=high-contrast lbrain query "what did we decide?"
LBRAIN_THEME=mono lbrain search "exact phrase"
Themes are classic (default), high-contrast, and mono. They alter ANSI
styling only: record order, fences, trust labels, provenance, and exit behavior
remain unchanged. An unknown theme reports a warning and visibly falls back to
classic.
⚠️ The HTTP server has no built-in auth and exposes the whole corpus. Bind to
127.0.0.1, or put authenticated TLS ingress in front. Never publish it on a public interface.
Why use LBrain?
Because retrieval isn't enough when your history disagrees with itself. A long-running project accumulates stale decisions, corrections, near-duplicates, and things that were true six months ago. Ordinary retrieval finds all of them. LBrain is built to help the agent distinguish among them.
Because evidence should travel with the answer. Retrieved records carry their source, date, status, and whether they actually answer the question — the model has something to cite instead of just something plausible to repeat.
Because your memory should belong to you. Local-first: SQLite, sqlite-vec, FTS5. No account, no cloud database, no hosted memory service.
Change your model. Change your agent. Change your tools. Keep the history.
What LBrain doesn't do
LBrain isn't a hallucination cure and it doesn't make a model smarter. It governs the records retrieved from your corpus; it can't control facts a model invents from its own weights, or guarantee what the model does with good evidence. And its admissibility check is deliberately conservative, so it will sometimes flag a record you'd have accepted. That's a trade we're willing to make: we'd rather surface uncertainty than manufacture confidence.
How it works
- Hybrid retrieval — vector + BM25 keyword, fused by reciprocal rank fusion.
- Deterministic admissibility check — classifies each record against the question as admissible, near-miss, or irrelevant, without a second model call.
- Supersession — a replaced note stops being served but is never deleted. Persistence and activation are separate concerns.
- Honest dating — each record states whether its date came from the content, the filename, or
the filesystem. No invented timestamps. Precedence, strongest first: a
**Last Updated**:header (verified) → anas of <date>in the body → frontmatterdate:or a date in the filename (dated) → mtime (file-dated, the weakest — it moves on any edit).Copying a corpus reages it.
cp, a git clone, and most sync tools reset mtime to now. Put adate:in the frontmatter and the claim date rides inside the file — it survives the move. - Untrusted-data fencing — retrieved text is fenced and labelled as data, never instructions, so a note can't hijack the agent reading it.
Research behind it
LBrain grew out of a simple question: what happens when the correct answer is present, but the surrounding records make it easy to use the wrong one?
We profiled eight model architectures from seven organizations on the same near-domain retrieval task. Failure rates swung 1.3% / 35.7% / 16.7% depending only on how the records were structured — a 34.4-point absolute difference — while architecture explained roughly none of the variance, with identical failure ordering in 8 of 8 models. Changing models didn't remove the effect. Telling the model not to guess didn't either. So the fix belongs before generation, on the input side, and it has to be deterministic.
The work is published as DOI-backed preprints and datasets, and the experiments are available for others to challenge: lbrain.ai/papers. We also killed three of our own claims while building this; the retractions are published with the findings.
Related work — read these too
Four 2026 papers staked adjacent ground while we were building, and they deserve the citation:
- Deceptive Grounding — Caruzzo, Yoo & Kim (arXiv:2607.09349): named and measured the failure mode — RAG responses that pass standard quality checks while attributing evidence to the wrong entity, in 8–87% of cases across 13 models.
- MemStrata (arXiv:2606.26511): deterministic supersession rules over a bi-temporal ledger, against stale-fact errors on evolving knowledge.
- Engram (arXiv:2606.09900): a bi-temporal memory graph tracking provenance and contradictions — a lean retrieved context beats the full history.
- Don't Ask the LLM to Track Freshness (arXiv:2606.01435): conflict resolution belongs in deterministic code, not model judgment.
What our 8-model matrix adds is the controlled variable: the serving format, not the model, is the controlling variable — the axis these works leave open, and the axis LBrain operates on.
Embeddings
| Provider | Setup | Where your text goes |
|---|---|---|
local (default) |
none | nowhere — on-device ONNX, 384-dim (one-time model download) |
gemini |
your own key | Google, under your key |
openai |
your own key | OpenAI, under your key |
lbrain init uses local unless you pass a key on the command line. A key sitting in your
environment is never treated as consent to send your corpus to a third party. Every network call
LBrain can make is listed in the Privacy Policy, §3. See
docs/KEYS.md.
Known issues — read this before filing
Most reports land in one of these. Checking first is faster than waiting for us.
| Symptom | Cause / fix |
|---|---|
TOMLDecodeError on any command right after init, on Windows |
You are on 0.1.0, which is yanked. It wrote an unparseable config.toml on Windows paths. pip install -U lbrain (≥ 0.1.1), then delete ~/.lbrain/config.toml and re-run init. |
UnicodeEncodeError during init, on Windows |
Same fix — 0.1.0 wrote template files in the locale encoding. Fixed in 0.1.1. |
Build errors installing [local] (fastembed / onnxruntime / sqlite-vec) |
Native wheels. Upgrade pip first (pip install -U pip), which resolves nearly all of these. On Windows a wheel may be missing for a very new Python — 3.10–3.13 are supported; 3.14+ may have no wheel yet. |
First embed pauses, then works |
One-time ~67 MB model download. It is the model coming down, not your notes going up. Offline after that. |
| "It says my provider is Gemini but I never set that" | Run lbrain doctor. It marks every setting [config] or [DEFAULT]. In 0.1.0 an API key in your environment silently selected a hosted provider; 0.1.1 refuses to treat an ambient key as consent. |
| Results changed after switching provider | Changing provider changes the vector space. Re-embed (lbrain embed --all); doctor exits non-zero on drift until you do. |
| A note is missing from results but the file exists | Usually imported-but-not-embedded. lbrain stats shows the gap; lbrain embed --stale closes it. |
| I edited only the YAML frontmatter and nothing changed | Known in 0.1.1 and earlier: change detection hashed the body only, so type: / description: edits were skipped and the old value persisted. Fixed in the next release — import will report meta-refreshed: N. Workaround today: touch the body (a trailing newline is enough) to force a re-index. |
| Two brains on one machine interfering | Use LBRAIN_HOME=/path/to/brain2 per invocation. |
Not listed? Then it is worth an issue — please use the template, it asks for lbrain doctor --json.
Something wrong?
lbrain doctor
Prints the effective config with per-setting provenance — [config] vs [DEFAULT] — and
whether your stored vectors match your current embedding settings. Include its output in any issue.
docs/DEVELOPER-NOTES.md covers the symptoms that look like bugs and
aren't — switching embedding providers on an existing brain, two brains on one machine,
imported-but-not-embedded records, and why a note can vanish from results without being deleted.
Agent identity
A brain that persists can also know whose it is. Identity is a first-class layer in LBrain — and deliberately optional: an anonymous install stays fully functional forever. Identity accretes onto a brain; it never gates one.
lbrain register --name jarvis --address <your-key-address> # bind a gcx:// name to this brain
lbrain whoami # who is this brain, what is it trusted for?
registeris free. It persists the identity to~/.lbrain/identity.json(0600); from then onwhoamiand the MCPlair_whoamireport this brain as that identity — which matters the moment more than one agent, tool, or machine touches your memory.whoamianswers the question an agent should ask before relying on retrieved records: what am I reading, how does it serve, and who does it claim to be.- Since 0.1.10 the write path honors identity: a process claiming a seat
(
LBRAIN_SEAT) cannot write into a brain whose identity doesn't match, and a config resolving to a foreign database is refused with both paths named. "Wrote into the wrong brain" stopped being a documentation warning and became an engine refusal.
The name can outlive your accounts, too: lbrain.ai is the project
home, and a permanent gcx:// name — yours, portable across tools, models, and machines —
can be claimed at lbrain.ai/claim.html.
More
docs/DESIGN-binding-aware-serving.md— the serving design and its review recorddocs/lair-framework/— the organizing convention LBrain readscontrib/— session-capture hooks, a shared-key proxyDockerfile,docker-compose.kite.yml— containerized deployment
Truth hierarchy: your source files are authoritative; the index is a derivative cache. If they
disagree, trust the file and re-run lbrain import && lbrain embed --stale.
If LBrain earns a place in your setup, a ⭐ on this repo is the signal that helps the next person find it.
License
BSD-3-Clause — see LICENSE. Copyright (c) 2026 Metavolve Labs, Inc.
Patents pending. The licence covers the code; it does not grant patent rights.
Metadata
Release files for lbrain 0.1.10.post1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lbrain-0.1.10.post1.tar.gz | 388.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lbrain-0.1.10.post1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 665.4 kB
Release files / lbrain-0.1.10.post1.tar.gz
| Download URL | lbrain-0.1.10.post1.tar.gz |
|---|---|
| Size | 388.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5ba2eaa8fd1690284c52d4be9a1d6e67474e082ba25e0eabc05a1be12a581f24
|
|
BLAKE2b-256 checksum How to use checksums |
4db212a445ca2068afefbfaa11994b5419b874607baf26166adfac708f4dff66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / lbrain-0.1.10.post1-py3-none-any.whl
| Download URL | lbrain-0.1.10.post1-py3-none-any.whl |
|---|---|
| Size | 276.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
649c439a1a3541415e0b086a5c4649fc03fa7a922a6dd10ec9889fa6b0f90df4
|
|
BLAKE2b-256 checksum How to use checksums |
26bf70f8f75055cfd8efb4a34f9812ba1ded606880c92bc601fce8edd82796ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency log