> 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.

# Pages and buckets

## Listing

`listPages` paginates automatically — iterate and the SDK fetches as it goes.

**`TypeScript`**

```typescript TypeScript
for await (const page of await client.workspace.listPages({ brainId, bucket: "ideas" })) {
  console.log(page.slug, page.status);
}
```

**`Python`**

```python Python
for page in client.workspace.list_pages(brain_id=brain_id, bucket="ideas"):
    print(page.slug, page.status)
```

Filter by `bucket` (`inbox`, `notes`, `ideas`, `projects`) or `status` (`active`,
`deprecated`, `stale`, `contested`, `archived`). Deprecated pages are hidden unless you pass
`includeDeprecated`, and archived pages are hidden unless you pass `includeArchived`.

For bucket navigation with counts, `buckets` is one call instead of four:

**`TypeScript`**

```typescript TypeScript
const counts = await client.workspace.buckets({ brainId });
```

**`Python`**

```python Python
counts = client.workspace.buckets(brain_id=brain_id)
```

## Reading a page

**`TypeScript`**

```typescript TypeScript
const page = await client.workspace.getPage({ brainId, slug: "attention-is-all-you-need" });
```

**`Python`**

```python Python
page = client.workspace.get_page(brain_id=brain_id, slug="attention-is-all-you-need")
```

> **Warn**
>
> `getPage` bumps the page's `lastReferencedAt`, which feeds the [health score](/api-reference).
> Call it when a human or agent actually consumes the content — not to hydrate a list view.

## Editing

Manual edits create a new version; the previous content stays in the history.

**`TypeScript`**

```typescript TypeScript
await client.workspace.editContent({ brainId, slug, body: "Revised content…" });

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

**`Python`**

```python Python
client.workspace.edit_content(brain_id=brain_id, slug=slug, body="Revised content…")

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

## Organizing

**`TypeScript`**

```typescript TypeScript
await client.workspace.moveBucket({ brainId, slug, bucket: "projects" });
await client.workspace.pin({ brainId, slug, pinned: true });
await client.workspace.rename({ brainId, slug, title: "New title", newSlug: "new-title" });
```

**`Python`**

```python Python
client.workspace.move_bucket(brain_id=brain_id, slug=slug, bucket="projects")
client.workspace.pin(brain_id=brain_id, slug=slug, pinned=True)
client.workspace.rename(brain_id=brain_id, slug=slug, title="New title", new_slug="new-title")
```

Moving a page sets `bucketSource: "user"`, which tells the brain not to re-route it. Pinned
pages are prioritized in the [prompt index](/docs/search#prompt-index) and never deprecate.

> **Warn**
>
> Renaming changes the slug. Connections follow the page, but anything outside Living Brain
> holding the old slug will break.

## Contested pages

When new material contradicts a page, its status becomes `contested`. Resolve it explicitly:

**`TypeScript`**

```typescript TypeScript
const contested = await client.workspace.listPages({ brainId, status: "contested" });
await client.workspace.resolve({ brainId, slug, resolution: "keep_new" });
```

**`Python`**

```python Python
contested = client.workspace.list_pages(brain_id=brain_id, status="contested")
client.workspace.resolve(brain_id=brain_id, slug=slug, resolution="keep_new")
```

## Archiving

Archive a page to take it out of lists and search without losing anything. Its content,
versions, and connections are kept, and `restore` brings it back as an active page.

**`TypeScript`**

```typescript TypeScript
await client.workspace.archive({ brainId, slug });
await client.workspace.restore({ brainId, slug });
```

**`Python`**

```python Python
client.workspace.archive(brain_id=brain_id, slug=slug)
client.workspace.restore(brain_id=brain_id, slug=slug)
```

To see archived pages, list with `includeArchived` or filter by `status: "archived"`:

**`TypeScript`**

```typescript TypeScript
for await (const page of await client.workspace.listPages({ brainId, status: "archived" })) {
  console.log(page.slug);
}
```

**`Python`**

```python Python
for page in client.workspace.list_pages(brain_id=brain_id, status="archived"):
    print(page.slug)
```

## Deleting

Use archive when a page might come back. Deleting is permanent.

**`TypeScript`**

```typescript TypeScript
await client.workspace.deletePermanently({ brainId, slug, permanent: "true" });
await client.workspace.recover({ brainId, slug });
```

**`Python`**

```python Python
client.workspace.delete_permanently(brain_id=brain_id, slug=slug, permanent="true")
client.workspace.recover(brain_id=brain_id, slug=slug)
```

> **Warn**
>
> `permanent: "true"` is **required** — the parameter exists as an explicit confirmation, not
> as a soft-delete toggle. The call removes the page, its versions, and its connections, and
> there is no undo. `recover` restores a *deprecated* page; it cannot bring back a deleted one.

`reviewed` is a legacy alias for `recover`, kept for backwards compatibility. Prefer `recover`.

## Exporting

**`TypeScript`**

```typescript TypeScript
const bundle = await client.workspace.exportMarkdown({ brainId });
```

**`Python`**

```python Python
bundle = client.workspace.export_markdown(brain_id=brain_id)
```