Skip to main content
The brain is a company’s shared knowledge: beliefs it holds, lessons it has learned, documents it has ingested, and the episodes those came from. A company may declare several, and exactly one of them is the default. Teams read a slice of a brain; agents read a view of that slice.

N brains, one default

brain_knowledge_bases is keyed (company_id, name) and carries a partial unique index on is_default = true. So the store has always held many brains per company and exactly one default, and naive brain list / naive brain create --name --default have always driven it. The DSL now says the same thing.
default in the DSL is a claim about this config, not a write to the platform. It decides which brain an unnamed binding in this file resolves to — and therefore which brain.brainName each compiled template carries into provisioning_templates.spec. It does not set brain_knowledge_bases.is_default: no apply calls the route that writes that flag.A route does exist — PATCH /v1/brain/{id}, reached as naive brain default <name|id> or naive.brains.setDefault(id). So a config saying default: "core" over a company whose live default is "support" is a difference naive up will not reconcile and one command will. naive brain list reports which brain actually carries the flag, and that is the authority. On a one-brain company the two cannot disagree.
One brain — unchanged, and still the shortest thing to write:
Several brainsbrains({ default, declared }). The record key is the name:
brain and brains are the same declaration at two arities. Writing both is company_brain_and_brains at define time — two spellings of one declaration is the defect, not the feature — and everything downstream reads one resolved shape, so a company that declares one brain and a company that declares six go down the same code path.

Connecting a brain to an agent

view() and partition() are the only ways to obtain a binding, and both are methods on the value that declares the brain. That is what makes “this agent uses that brain” structural rather than conventional: no expression can name a brain it was not handed. On the wire a binding carries brainName. It is absent for a company that declares one brain — and absent means the company default, exactly as is_default means it in the database. A binding written before brains() existed is byte-identical to what it was.
An empty ability list is how an agent gets nothingcan: [], not a second concept and not a second brain. No field anywhere means “a different brain, or none”.

What is unwritable, by construction

These are not runtime refusals with friendly messages. They do not compile. And these are refused at define time, because a config can also arrive as JSON:

Scope — where a brain sits, and what is inside it

scope mirrors brain_knowledge_bases.scope: Default recall unions the caller’s project brain with the org brain, which is why a second org trunk has to be refused rather than accepted and silently ignored. Inside one brain the levels are unchanged:

Visibility — a ceiling and a narrowing

view({ can: [...] }) picks from recall, attach, think, remember, learn, propose, reaffirm, pressure. A brain may also declare visibility: { can: [...] } — the ceiling for every view of that brain. A brain no agent may ever write into says so once, on the brain, instead of every view() in the config having to remember. A view may only narrow it; a wider one is brain_view_exceeds_visibility at define time, naming both levels. That is the same direction retention moves, so adding an agent can never widen what a brain exposes. promote and forget are not on the ability list, and cannot be added. They are the human acceptance and the human erasure of model-authored text; an agent holding promote could accept its own proposals, which is the one thing writes: { mode: "review" } exists to prevent.

Retention is per content noun, and it only narrows

retention.beliefs is required: a brain with no stated belief retention keeps everything forever, and that should be a decision somebody made rather than a default they inherited. A partition or lane may narrow any value; widening throws at define time, naming both levels. Everything is bounded by a 365-day ceiling. The platform’s own numbers are exported as brainDefaults so you can read and narrow them rather than invent one:
Retention is declared but not yet enforced. brain({ retention }) compiles the per-content-noun ceiling in @usenaive-sdk/iac, and the narrowing rule and the 365-day ceiling are real define-time checks — a widening config throws before it ships. But nothing server-side reads or stores that policy: there is no ttl, retention or expiry column on any brain_* table, so no belief in this build ever lapses. GET /v1/brain/retention answers 501 and says exactly this rather than reporting a policy it does not apply. Declare retention now — it is the record of your decision and it will be what the enforcement reads — but do not rely on it to delete anything yet.

What governs a brain write

brain is an opt-in primitive (optIn: true in the registry), because it engages a subprocessor. A fresh workspace does not have it: a gated brain call with no kit entry is denied, not silently allowed. Four brain actions are human-gated by default (AccountKits):
  • brain.kb.delete and brain.document.delete — both, so the KB-delete gate cannot be bypassed by deleting document by document.
  • brain.forget — company-scope forget is effectively a right-to-be-forgotten wipe.
  • brain.proposal.accept — canonizing a claim is a review act.
None of the four has a sandbox leg. A sandbox operator calling them gets 501 not_configured, not a synthetic acknowledgement — see Environments enforcement.

The read surface — what is wired

GET /v1/brain/beliefs answers from brain_claims and is keyset-paged. Its defining property is that it shows its work: every row carries recallable and the three filters that produced it, so “why did recall not return this?” is answerable from the row instead of guessable.
Where a field cannot be computed in this build it says so by name rather than defaulting to a plausible value — lane_unavailable_because, shadows_unavailable_because, expires_at_unavailable_because. A filter reporting true because it was never run is the exact failure this shape exists to prevent.
Three schema facts worth knowing before you design against this.
  1. There is no agent level on any brain_* table. The DSL has brain → partition → lane; the store has org and project. level: "agent" is unreachable, and the endpoint reports it in levels_absent rather than letting you infer it from an empty result.
  2. valid_to is temporal validity, not retention. It answers “this was true until then”, not “this expires then”. There is no retention column anywhere on brain_*, so a belief in this build never lapses — which is why expires_at is absent rather than null.
  3. There is no lane column. Lanes are declarable in the DSL and not yet storable.

What refuses today

These operations are declared and addressable, and answer 501 not_configured with details.missing naming the absent dependency: GET /v1/brain/levels and the belief reads are real. The knowledge-base, ingestion, recall, proposal and writeback surfaces under /v1/brain/* are real too.
Recalled brain text reaches the model as prose, and sources include external systems. Brain content can originate from Slack, Gmail, the web and uploads. On the recall path that text is interpolated into the model’s context. Do not treat a recalled belief as trusted instruction merely because it came from your own brain — an attacker who can get text into an ingested source can get text into a prompt. Keep writes: { mode: "review" } on any partition fed by an external source, and keep promote where it is: with a human.