Capturing knowledge

Push notes, links, files, transcripts, and chat turns into a brain.

A single capture

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

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.

1const result = await client.captures.captureBatch({
2 brainId,
3 items: [
4 { kind: "url", fetchUrl: "https://example.com/a" },
5 { kind: "note", content: "Follow up with the infra team." },
6 ],
7});
8
9console.log(`${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.

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

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:

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

Statuses run pendingcompilingcompleted, or failed.

Retrying

1await client.captures.retrySource({ brainId, sourceId });

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.

Polling works, but the change feed is cheaper and tells you when pages actually appear rather than when a source finishes.