> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.livingbrain.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.livingbrain.com/_mcp/server.

# New-hire onboarding

New hires often ask why something is done a certain way, and the answer may be in an old meeting, a
postmortem or one person's memory. An assistant in your team chat can answer from a brain, link to the
sources and say when a page might be out of date. When no page covers the question, it asks someone and
keeps the answer for the next hire.

![Cursor CLI answering what was decided about the onboarding flow, naming the decision, the channel and the date](/_fern-files/_img/95f19831810a6e899ad727e1697ee388d87f29c7804c0d26b52bf53861a41ccd.webp)

An example Cursor CLI session from livingbrain.com. The answer names where and when the decision was made.

## Explain why something changed

A brain page keeps its earlier versions, so when a new hire asks why the team works a certain way, the
answer can include how the current rule came about.

A page has three versions. A runbook sets the original rule, a postmortem adds an exception, and a team meeting narrows the rule, which is the current version.

A question is searched and the page read. An active page gets an answer with sources. A stale page gets an answer with its age flagged. A contested page shows both claims. With no page, the assistant asks the owner, and the answer is captured so the next search finds it.

Each version records its source. The assistant can explain what changed and when, and the new hire can
open each source.

**`TypeScript`**

```typescript TypeScript
const versions = await client.workspace.pageVersions({ brainId, slug });

// Newest first. Each version has its body, its ingestSourceId and when it was created.
const history = versions.map((v) => ({
  version: v.version,
  summary: v.summary,
  sourceId: v.ingestSourceId,
  date: v.createdAt,
}));
```

**`Python`**

```python Python
versions = client.workspace.page_versions(brain_id=brain_id, slug=slug)

# Newest first. Each version has its body, its ingest_source_id and when it was created.
history = [
    {
        "version": v.version,
        "summary": v.summary,
        "source_id": v.ingest_source_id,
        "date": v.created_at,
    }
    for v in versions
]
```

**`Example output`**

```json Example output
[
  { "version": 3, "summary": "Narrowed the rule after a team meeting", "date": "2026-09-16" },
  { "version": 2, "summary": "Added an exception after a postmortem", "date": "2026-03-11" },
  { "version": 1, "summary": "First written in the runbook", "date": "2026-01-20" }
]
```

Pass the history to your model when the question is about why or when. For a question about what the
rule is today, the current page is enough.

## What the assistant does with each status

A page has three versions. A runbook sets the original rule, a postmortem adds an exception, and a team meeting narrows the rule, which is the current version.

A question is searched and the page read. An active page gets an answer with sources. A stale page gets an answer with its age flagged. A contested page shows both claims. With no page, the assistant asks the owner, and the answer is captured so the next search finds it.

A new hire can't tell whether an answer rests on a disputed page, so the assistant should say so. Base
its response on the page's status:

| Page status              | What the assistant does                                                                                    |
| ------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `active`                 | Answers and links the sources                                                                              |
| `stale`                  | Answers, gives the date of the last update and suggests who to check with                                  |
| `contested`              | Shows both claims with their sources and asks the owner to [resolve](/docs/pages#contested-pages) the page |
| `deprecated`, `archived` | Skips the page, unless the question is about history                                                       |
| No usable page           | Says it doesn't know and asks the owner                                                                    |

`stale` means nobody has referenced or refreshed the page recently. The page may still be correct, so the
assistant answers from it and shows its age.

**`TypeScript`**

```typescript TypeScript
const hits = await client.workspace.searchPages({ brainId, query: question, topK: 5 });
const usable = hits.filter((h) => !["deprecated", "archived"].includes(h.status));

if (usable.length === 0) return askOwner(question);

const pages = await Promise.all(
  usable.slice(0, 3).map((h) => client.workspace.getPage({ brainId, slug: h.slug })),
);

// The model answers from these pages only, or reports that they don't cover the question.
const draft = await answerFromPages(question, pages);
if (draft.unanswered) return askOwner(question);

return {
  text: draft.text,
  sources: draft.pagesUsed.map((p) => ({ slug: p.slug, version: p.version, status: p.status })),
};
```

**`Python`**

```python Python
hits = client.workspace.search_pages(brain_id=brain_id, query=question, top_k=5)
usable = [h for h in hits if h.status not in ("deprecated", "archived")]

if not usable:
    return ask_owner(question)

pages = [client.workspace.get_page(brain_id=brain_id, slug=h.slug) for h in usable[:3]]

# The model answers from these pages only, or reports that they don't cover the question.
draft = answer_from_pages(question, pages)
if draft.unanswered:
    return ask_owner(question)

return {
    "text": draft.text,
    "sources": [
        {"slug": p.slug, "version": p.version, "status": p.status} for p in draft.pages_used
    ],
}
```

**`Example output`**

```json Example output
{
  "text": "The current rule comes from a team meeting, which narrowed an exception added after a postmortem.",
  "sources": [{ "slug": "team-process", "version": 3, "status": "active" }]
}
```

Search can return pages that don't contain the answer, so the assistant reads them before answering. If
they don't cover the question, it asks the owner, as it would with no page at all. Don't let the model
fall back on its own knowledge, because a new hire has nothing to check that answer against.

## Closing a gap

When no page covers a question, the assistant posts it in the channel of whoever owns that area. A page
has no owner field, so keep a map from topic to channel in your app. When the owner replies, capture the
reply:

**`TypeScript`**

```typescript TypeScript
await client.captures.capture({
  brainId,
  body: {
    kind: "note",
    content: `Question: ${question}\n\nAnswer from ${owner.team}: ${reply.text}`,
    label: `Answer: ${question}`,
    originRef: `slack:${reply.channel}:${reply.ts}`,
  },
});
```

**`Python`**

```python Python
client.captures.capture(
    brain_id=brain_id,
    kind="note",
    content=f"Question: {question}\n\nAnswer from {owner.team}: {reply.text}",
    label=f"Answer: {question}",
    origin_ref=f"slack:{reply.channel}:{reply.ts}",
)
```

Send the reply to the new hire straight away, because the capture has to compile before search can find
it. After that, search can find the answer for the next person, even if they word the question
differently.

The capture includes the question so the answer makes sense on its own. It leaves out who asked, so the
brain holds no record of what a particular person didn't know.

## What goes in the brain

Access is decided per brain, so anyone who can use the assistant can get an answer from any page in it.
Choose what goes in with that in mind.

| Put in                                              | Keep out                                                        |
| --------------------------------------------------- | --------------------------------------------------------------- |
| Decisions and the reasons behind them               | Pay, performance reviews and hiring discussions                 |
| Postmortems and runbooks                            | Customer contracts and other restricted documents               |
| Team meeting transcripts, with attendees' agreement | Benefits and legal policy, which should be linked word for word |
| Architecture docs, as `file` or `url` captures      | Private conversations                                           |

Then set the brain up for people who don't know the team's vocabulary yet:

* **Add your terms to the [profile](/docs/concepts#brain-profile).** List what your internal names and
  acronyms stand for, before the first import.
* **Search with rewrites.** A new hire may not know what the team calls something yet, so have the
  assistant search the question plus one or two rewordings.
* **Pin the first-week pages,** such as who owns what and how to ship your first change.
  [Pinned pages](/docs/pages#organizing) rank first in the prompt index and never deprecate.

## Keeping pages current

The brain flags pages that are going out of date, and someone has to review them. This sweep sends each
stale page to its owner:

**`TypeScript`**

```typescript TypeScript
for await (const page of await client.workspace.listPages({ brainId, status: "stale" })) {
  await notifyOwner(ownerFor(page), page.slug, page.lastCompiledAt);
}
```

**`Python`**

```python Python
for page in client.workspace.list_pages(brain_id=brain_id, status="stale"):
    notify_owner(owner_for(page), page.slug, page.last_compiled_at)
```

Use `listPages` for a sweep like this. `getPage` updates a page's `lastReferencedAt`, so a script that
opens every page would make them all look recently used.

Review these lists on a schedule:

| List                   | Where it comes from  | What it tells you                                |
| ---------------------- | -------------------- | ------------------------------------------------ |
| Questions with no page | Your assistant's log | What onboarding doesn't cover yet                |
| `contested` pages      | `listPages`          | Where the team disagrees or a decision has moved |
| `stale` pages          | `listPages`          | What needs checking or retiring                  |

[Brain health](/docs/brain-health) tracks the same work over time. Unresolved contested pages and failed
sources raise Strain, and a brain nobody is feeding loses Freshness.

## When a brain isn't the right tool

A team small enough for a new hire to ask everyone directly may not need this. For policies with legal or
financial weight, such as benefits or expenses, link to the original document, because a paraphrase can
get details wrong. New hires will still need a buddy or manager for anything nobody has written down.

[How to build with Living Brain](/docs/build) covers the write and read paths in more detail.