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

# Capturing knowledge

## A single capture

**`TypeScript`**

```typescript TypeScript
const source = await client.captures.capture({
  brainId,
  body: { kind: "note", content: "Postgres LISTEN/NOTIFY caps out around 8k msg/s.", bucket: "notes" },
});
```

**`Python`**

```python Python
source = client.captures.capture(
    brain_id=brain_id,
    kind="note",
    content="Postgres LISTEN/NOTIFY caps out around 8k msg/s.",
    bucket="notes",
)
```

Omit `bucket` and the brain routes the capture itself, recording `bucketSource: "auto"`.

## Batches

Each item in a batch is processed independently — one malformed entry fails on its own
instead of rejecting the whole request.

**`TypeScript`**

```typescript TypeScript
const result = await client.captures.captureBatch({
  brainId,
  items: [
    { kind: "url", fetchUrl: "https://example.com/a" },
    { kind: "note", content: "Follow up with the infra team." },
  ],
});

console.log(`${result.ingested} accepted`);
```

**`Python`**

```python Python
result = client.captures.capture_batch(
    brain_id=brain_id,
    items=[
        {"kind": "url", "fetch_url": "https://example.com/a"},
        {"kind": "note", "content": "Follow up with the infra team."},
    ],
)

print(f"{result.ingested} accepted")
```

## Chat turns

If you're building a conversational product, most turns aren't worth remembering. Rather than
capturing everything and polluting the brain, push turns through the classifier and let it
decide.

**`TypeScript`**

```typescript TypeScript
const result = await client.captures.captureChatTurn({
  brainId,
  sender: "user",
  text: "We decided to drop the Redis cache — latency wasn't the bottleneck.",
});
```

**`Python`**

```python Python
result = client.captures.capture_chat_turn(
    brain_id=brain_id,
    sender="user",
    text="We decided to drop the Redis cache — latency wasn't the bottleneck.",
)
```

> **Tip**
>
> Send every turn. The classifier is the point — filtering client-side with your own heuristic
> defeats it, and turns you discard are gone for good.

## Tracking ingestion

Captures compile in the background. To show a queue, list the brain's sources:

**`TypeScript`**

```typescript TypeScript
for await (const src of await client.captures.listSources({ brainId, status: "failed" })) {
  console.warn(`${src.label ?? src.id} failed after ${src.attempts} attempts`);
}
```

**`Python`**

```python Python
for src in client.captures.list_sources(brain_id=brain_id, status="failed"):
    print(f"{src.label or src.id} failed after {src.attempts} attempts")
```

Statuses run `pending` → `compiling` → `completed`, or `failed`.

### Retrying

**`TypeScript`**

```typescript TypeScript
await client.captures.retrySource({ brainId, sourceId });
```

**`Python`**

```python Python
client.captures.retry_source(brain_id=brain_id, source_id=source_id)
```

Only `failed` sources can be retried. Deleting a source leaves any pages already derived from
it in place — delete those separately if you want them gone.

> **Info**
>
> Polling works, but the [change feed](/docs/changes) is cheaper and tells you when pages actually
> appear rather than when a source finishes.