Skip to main content
Ingestion is four steps, and the split is the design rather than a limitation. The brain does not decide what a document means — an external model does, and the protocol validates what it proposes. So the boundary is visible in the API: there is no path that lets a model write to a Merkle DAG.
brain.ingest() runs all of it in one call. Use the separate calls when the model runs elsewhere — in another process, behind an MCP server, or on a human’s desk.

1. Register the source

The bytes are preserved verbatim and addressed by their hash. This is canonical memory: what was actually observed, so every later claim can be traced back to it.
Registering the same bytes again is a no-op that returns the same identity, because identical content has one identity. Safe to retry. To register a newer edition of a source, use replace — a register plus a supersession edge, never a mutation of bytes already stored:

Normalization pipelines

A normalized view is a deterministic transform of the original, recorded in provenance with the pipeline name and version.

2. Define the task

Canonical and provenance can never be proposed. One is the source itself; the other is the brain’s own record of what happened — define_task refuses them.
The schema its candidates must satisfy is emitted by the SDK, not described by it. Hand it to your model as structured output:
With one allowed memory type the schema names that variant directly; with several it uses oneOf. The other wire schemas are available the same way:

3. Your model proposes

A Candidate is not a Block and has no block_id. An unvalidated proposal has no identity, so it cannot be committed by accident. Recording producer at this granularity is what makes a later batch invalidation possible.

4. Validate

Validation is the brain’s, not yours. A candidate that fails comes back rejected with a code rather than stored — and rather than raised as an error.

The validation gate

DEFAULT_VALIDATORS runs seven checks, in this order:
The duplicate case is worth understanding: identical knowledge is identical, so re-submitting a set you already committed rejects all of it and commits nothing. That is correct, not a failure.
A rejection is information. Fix the candidate and submit again. Add your own checks by passing validators=[*DEFAULT_VALIDATORS, MyDomainCheck()] to Brain.open.

5. Commit

The only write path, and one transaction: a failure part-way through leaves the previous snapshot as the current one.
An external model can reach validate but never commit without going through it.

Re-derivation

When a source was wrong rather than unwanted, regenerate the knowledge against the corrected source instead of losing it:
That is the difference between a deletion and a re-derivation — see Retention.

Indices after a commit

A travelling index cannot be regenerated — that is what makes it travelling — and it is persisted only when the artifact is materialized. If you ingest and the process exits without pack or push, the vector index is lost. Push from the process that committed, or call brain.pack() before it exits.