Skip to navigation

How to build with Living Brain

The write path, the read path and the decisions your app makes in between.

An app built on Living Brain writes material into a brain as it happens and reads pages back when someone needs an answer. The brain organises, versions and indexes the pages. Your app decides what to capture, whether a page is enough to act on, and where a question goes when it isn’t.

Most of the advice below comes from building the Automated X Support Bot, which answers public questions from one brain and hands the rest to a person.

WriteCapturewith an originRefAcceptedstatus pendingCompiledpages updatedNotifiedwebhook or feedReadSearchfind candidatesRead the pagefull bodySupported?Answercite the pageHand offto a personyesnoWriteCapturewith an originRefAcceptedstatus pendingCompiledpages updatedNotifiedwebhook or feedReadSearchfind candidatesRead the pagefull bodySupported?Answercite the pageHand offto a personyesno
Your appThe brainA person

Choose how to connect

InterfaceUse it whenStart here
SDK or RESTYour own backend writes to and reads from brains. You control every call.TypeScript, Python, API reference
MCPAn agent you don’t control (Claude, ChatGPT, Cursor) should read and write a user’s brain.MCP with API key, MCP with sign-in
CLIYou’re scripting imports, inspecting a brain or testing from a terminal.CLI

All three use the same brains. A user can capture through your app and read the same pages from Claude over MCP.

Writing to a brain

Decide what one brain holds

Most products create one brain per end user. Create more than one when the contents shouldn’t mix: a consultancy might keep one brain per client so that a search for one client can never return another client’s pages. Every call names its brainId, so the boundary is enforced on every request.

Give every capture an originRef

Set originRef to an ID from the system the material came from, such as a Slack message timestamp or a document ID. The brain uses it as the capture’s identity, so a retry after a timeout updates the same capture instead of creating a duplicate.

await client.captures.capture({
brainId,
body: {
kind: "transcript",
content: transcriptText,
label: "Billing launch sync, 14 May",
originRef: `meet:${meetingId}`,
},
});

A different originRef is a different capture, even if the content looks the same to a person.

Don’t search for what you just wrote

A capture returns as soon as the brain accepts it, before anything is compiled. If your app captures something and searches for it in the next line, the search won’t find it. When you need to know a capture has landed, watch for it:

  • Webhooks: subscribe to brain.page.updated and react when the page changes. See Change feed and webhooks.
  • Sources: list sources by status to show a queue, and retry the ones that failed. See Tracking ingestion.

Send chat turns through the classifier

For conversational products, send every turn with captureChatTurn and let the brain decide what’s worth keeping. Most turns aren’t, and a filter you write yourself will drop some that are.

Fill in the profile early

The brain profile tells the brain what the user cares about and which terms mean what. It shapes how later captures are compiled and doesn’t reach back to earlier ones, so set it before the first large import.

Reading from a brain

Load the index once, search per question

Give an agent the prompt index at the start of a session so it knows what the brain broadly contains, then search when a question needs something specific. The index is short and changes slowly, so one load per session is usually enough. Each search is a separate call scoped to one question.

Search, then read the page

A search result carries a title, a summary and a match reason. Use them to choose which pages to open, then read the full page before you answer from it.

const hits = await client.workspace.searchPages({
brainId,
query: "When does the billing page launch?",
topK: 5,
});
const pages = await Promise.all(
hits
.filter((h) => h.status === "active" || h.status === "contested")
.slice(0, 3)
.map((h) => client.workspace.getPage({ brainId, slug: h.slug })),
);
// Each page has body, status, version and the sources it was built from.

The Automated X Support Bot searches the question as asked plus up to two rewrites, keeps the best eight pages and reads four in full. Rewrites help most when users phrase things differently from the material, for example asking “is it free?” when the page is titled “Pricing”.

Rank by similarity, decide by reading

similarity orders results. It doesn’t tell you whether a page answers the question. Use minSimilarity to drop weak matches, and decide whether you have an answer by reading the page. See How search ranks pages.

Check the page status

Only active pages are settled. A contested page holds two claims that disagree. Either show both claims or hand the question to someone who can resolve it. Skip deprecated and archived pages unless the question is about history.

Deciding what to do with the evidence

Answer from pages, and say which ones

Pass the pages you read to your model and ask it to answer from them only. Ask it to return which page supports each claim. Then keep the page slug and version with the answer, so anyone can later see exactly what the answer was based on.

Give unsupported questions somewhere to go

Some questions won’t be covered by the brain. Decide in advance where those go: a support queue, a Slack channel, a “we don’t know yet” reply. The Automated X Support Bot sends these to a Slack channel with the reason and what the brain was missing.

Don’t fall back on the model’s own memory

When search returns nothing useful, a model asked to answer will usually still produce a fluent reply, and a reader can’t tell it apart from one backed by pages. If retrieval fails, escalate.

Check claims against the pages

For anything public or high-stakes, run a second check after drafting. Confirm every page the draft cites exists and says what the draft claims. The support bot does this in code (references, length) and with a separate model call (does each claim follow from the pages). It allows one revision that can only remove or soften claims. If the checks still fail, it escalates.

Keeping a brain healthy

  • Watch Strain. Rising Strain means failed sources, a backlog or unresolved conflicts. Each of those can make answers worse without any error showing up.
  • Resolve contested pages. Until a person decides, every reader sees the disagreement.
  • Fill gaps you find. When a question is escalated because the brain had nothing, capture the answer once a person gives it. Search will then find that page for later questions phrased other ways.

Before you ship

  • Every capture sets originRef.
  • Nothing searches for a capture in the same request that sent it.
  • Answers are built from full pages, not search snippets.
  • contested pages are shown as disputed or escalated.
  • Every answer records the page slugs and versions it used.
  • There’s a defined place for questions the brain can’t answer.
  • Retrieval failure leads to escalation, not a guess.