Your agent does not need a better memory. It needs a system of record.
Most agent-memory tools solve retrieval: given a question, find some related text and ask a model to read it again.
That works for "where did we discuss the payments migration?" It breaks down on "what am I still on the hook for?" The second question isn't about similarity. It depends on identity and change over time: which decision was made, what blocked it, who owns it, and whether something later resolved or superseded it.
Notebrainer turns source material into typed, queryable claims. An agent can ask for open decisions, unresolved risks, dependencies, contradictions, and ownership without reconstructing the state of the world from scratch in every session.
The agent still writes the answer. Notebrainer gives it something better than recollection: records.
Search can find a promise. It cannot tell you whether you still owe it.
A semantic search for "payments rollout" returns messages that resemble the phrase. A Notebrainer query can return decisions about the rollout that have no later RESOLVES or SUPERSEDES relationship, order them by importance, and point back to the bodies that asserted each claim.
nb canonicals list \
--type DECISION \
--not-incoming RESOLVES,SUPERSEDES \
--priority high,medium \
--sort by-importanceThe distinction matters whenever the question hinges on words like still, current, blocked, resolved, contradicted, or who owns. Those are graph questions masquerading as search questions.
- Bodies are evidence. Notebrainer keeps the source material and treats extracted rows as claims about it. It doesn't replace your records with an LLM-written recollection.
- Every claim has provenance. Mentions point to
content_id; relationships point toasserted_in_content_id. An answer can always be traced back to the body that supports it. - Structure is primary. Typed entities and asserted relationships carry state. Embeddings help with search and identity resolution; cosine similarity is not a theory of truth.
- Corrections survive extraction. Manual canonicals and relationships are not erased when you rerun the extractor with a different model.
- The database and the agent have separate jobs. Notebrainer returns inspectable rows. The agent composes them into prose.
Ingest source material:
nb ingest-mbox ~/Mail/inbox.mbox --workspace work --config auto
nb ingest-markdown ./docs --workspace work --config commonAsk structural questions:
# What decisions remain open?
nb canonicals list --type DECISION \
--not-incoming RESOLVES,SUPERSEDES
# Which decisions are blocked?
nb canonicals list --type DECISION \
--has-outgoing DEPENDS_ON
# What depends on this decision?
nb relations list --object 4421 --predicate DEPENDS_ON
# What did this email actually resolve?
nb relations list --asserted-in 9183 --predicate RESOLVES
# Find the source material around a topic.
nb search "payment gateway rollout"That is the product surface: content in, typed rows out. The bundled agent skills teach an agent to compose these primitives, so you can ask the same questions in plain language. And by default the agent is also the extractor: the ingest skill fans out sub-agents over emitted chunks, so building the graph needs no extraction model and no API key. Configured models are the fallback for unattended runs. The full filter algebra covers incoming/outgoing predicate filters, mention filters, support thresholds, and importance ranking.
Notebrainer runs locally, and its front door is the Claude Code plugin: the bundled skills walk you through setup, run the ingestion, and answer the queries. You need uv, plus either Docker (the setup skill stands up Postgres+pgvector for you) or an existing Postgres with rights to create the vector and pg_trgm extensions. Optional: a local Ollama — only needed for embeddings, which back semantic search.
In Claude Code, run one slash command per line (Claude Code executes a single slash command per message):
/plugin marketplace add ahmohamed/notebrainer
/plugin install notebrainer@notebrainer
/notebrainer:setup
The setup skill installs the nb CLI if it's missing, asks you the choices that matter — where Postgres should live, who extracts (the agent by default; no model keys), and a workspace id — then stands everything up and verifies the connection.
/notebrainer:ingest ~/Mail/inbox.mbox into workspace me, first 100 messages
Then:
What am I still on the hook for in workspace me?
What is blocked?
Who owns the payments rollout?
The graph persists across sessions. The agent doesn't have to reread its own conversation history to reconstruct it.
Prefer the terminal, or a different runtime? Manual setup covers the same steps as plain nb commands, and nb install --skills copies the skills into any Agent Skills-compatible runtime.
Notebrainer ships first-class ingestion for mbox archives and Markdown directories.
Other sources don't need an SDK or a Notebrainer dependency. Write a parser that emits one ContentItem JSON object per root tree, one per line, then pipe it into nb batch -:
source -> your parser -> ContentItem JSONL -> nb batch -
Calendar data, Slack exports, GitHub notifications, meeting transcripts, and Notion exports all use the same boundary. Notebrainer deduplicates content by workspace, source, and source ID.
source material
|
v
content and chunks -----> semantic/text search
|
v
typed extraction
|
v
canonical entities -----> asserted relationships
| |
+------------+--------------+
v
structural queries
|
v
agent
Extraction identifies applicable vocabulary, extracts entities, and then extracts relationships whose endpoints must resolve to known candidates. Two things can run it: the agent itself (the default — nb extract --emit hands chunks to sub-agents, --apply-batch writes their output deterministically) or configured models for unattended runs (details). Domain packs define the entity types, predicates, and resolution rules appropriate to a workspace; eleven ship bundled, and writing your own is a 50-line YAML file.
Canonical identities are resolved by exact match, aliases, or embeddings, depending on the entity type. Postgres is the system of record; pgvector supports semantic search and embedding-based resolution. It does not manufacture graph edges from proximity.
Re-extraction replaces extracted mentions and relationships for the affected content. Canonicals you have corrected, cluster labels, and manually created edges remain intact.
- Not a chatbot. It returns records with provenance and leaves presentation to the agent or interface using it.
- Not "chat with your data." It doesn't make the model reread a changing pile of chunks whenever you ask for current state.
- Not a vector database wearing a graph hat. Embeddings support the system; they do not define its facts or relationships.
- Not a hosted memory silo. It runs on Postgres, works through a CLI or matching HTTP API, and can use local or hosted models.
- Not a claim that extraction is infallible. Models can misread source material. Notebrainer makes every extracted claim traceable to its source and correctable when the model gets it wrong.
The technical reference covers the rest: manual setup, the extraction pipeline, canonical resolution methods, domain packs, the bundled source parsers, search modes, model routing, nb profile, the HTTP API, and the schema.
Use grep, full-text search, or a small vector index if you have a modest collection and only need to find passages. Notebrainer is deliberately more machinery than that.
It's also the wrong fit if you can't run Postgres, don't want models extracting structure from your content, or need every extracted claim to be correct without review. Provenance limits the damage of a bad extraction; it doesn't make the extraction right.
Use Notebrainer when the cost of repeatedly reconstructing state is greater than the cost of maintaining it.
