Brainy Brainy
Docs Brainy

Brainy

In this section

Brainy is a database built for an agent to work out of, all day, across every session it ever has. It holds vectors, a graph, structured metadata, files and point-in-time history in one engine — and on top of that engine it holds three things an agent specifically needs and a plain database does not: somewhere to keep what it has learned, a way for its owner to bind what it may do without trusting the agent to remember the rule, and a durable record of what it agreed to with everyone else working the same problem.

One install. npm install @soulcraft/brainy — no separate services to stand up, no configuration to get right before the first write. A thin TypeScript API sits over a Rust engine; the hot paths — vector search, metadata filtering, graph traversal, SIMD distance, embedding — run compiled, in the same process, with no network hop between your code and the data.

The store is the record. Nothing here is a cache in front of a database of record kept somewhere else. What Brainy holds on disk is the data, the memory, the policy and the coordination history — durable, point-in-time readable, and yours: the on-disk format has an MIT-licensed reference reader (Open Brainy), so the files this engine writes are never hostage to a subscription.

The rest of this page is the three pillars, the doors that reach them, how the engine keeps a store honest underneath all of it, and how you get it.


Infinite memory

A plain vector store answers what matches these words. An agent needs a different question answered: what should come to mind now — which weighs a match against how much a memory matters, how well it is still remembered, how recently it was made, and how often it has actually been useful, and then expands to what that memory is connected to. Doing that outside the engine means round-tripping the whole candidate pool through your own process to blend five signals by hand; Brainy Memory does it inside the engine, where the columns already live.

  • Remember and recall, ranked, not just matched. remember() writes a memory with engine-owned fields (recallCount, stability, difficulty, FSRS forgetting-curve state) a caller cannot set — because those fields are the ranking's inputs, and a caller able to set them could rank its own rows to the top. recall() is one door, five internal stages — retrieve, fuse, expand, rerank, strengthen — under one budget, and the blend it ranks by is a formula the caller can read back and recompute by hand, never a black box.

  • Layers, not a layer field. Every memory is an episode. An abstraction is one whose subtype marks it as a rollup; a passage is an auto-derived chunk of a longer document. memory.abstract() writes a rollup and absorbs the episodes it stands for in one transaction — the rollup row, the pointer on every absorbed row, and the graph edge between them — so a process killed mid-write can never leave one true without the others.

  • Retire, never delete. memory.retire(id, { reason }) demotes a row out of ordinary recall; get(), history, and every point-in-time view still hold it, unchanged. There is no forget(), and there will not be one.

  • Scopes as fences, not filters. world, visibility and retired are three-valued axes evaluated inside the index before a candidate is ever scored — a dreamed row, an internal bookkeeping row, or a retired row never costs the ranking anything unless you deliberately ask to see it.

  • Cite and citation rank. cite() counts real usage — the gap between returned and useful — and citationRank is a bounded PageRank over the citation graph, so a fact eight other important rows lean on outranks one merely mentioned eight times. It runs as a background job, never per query, because a whole-graph rank computed inside a recall would make every recall pay for every citation in the store.

  • context() — the slice that already fits. One call that fills a model's window with cited facts first, the recent tail verbatim, and older episodes represented by the abstractions that absorbed them, every item carrying its own provenance. The budget is characters by default — no tokenizer required — or tokens, when the caller supplies its own token counter; the engine never estimates a token count from characters, because a budget that is wrong in exactly the case it exists for is worse than no budget.

  • turn() receipts. One call per exchange records the running gist of a conversation — bounded, measured against the caller's own token counter, and idempotent on the exchange's own position, so a retried call is a no-op rather than a second entry.

  • Deferred embedding, and awaitIndexed. A write acknowledges at durability — findable by id, tag or metadata the instant remember() returns — and its vector lands on a background worker. A caller that needs to read its own write back by meaning right away opts in explicitly, bounded and refused by name on timeout rather than lied to.

  • Digest, sessions, abstract() rollups. memory.sessions() and memory.digest() read a derived projection — one row per session (each a (source, sourceRef) pair), folded incrementally as memories are written, never re-walked from scratch — so a caller can ask "what happened since I last checked" and get a head rather than a full re-scan; a digest a caller already holds is confirmed unchanged with no rows re-sent when nothing moved.

  • Housekeeping runs itself. Four background jobs — decay, episodes, consolidation, retirement — arm on the first remember(), cost is proportional to what changed rather than to what the store holds, and every cycle reports a health row even when it did nothing.

Read the full shape, the blend formula, and every refusal class in Brainy Memory and Housekeeping.


Policy at the door

An agent does not usually go rogue because it is malicious. It goes rogue because the rule that was supposed to bind it lived in a prompt, the prompt was compacted, and what is left is a capable model with a tool belt and no memory of what it was told not to do. The policy door moves the rule out of the prompt and into the store, so an agent that never read it still meets it.

  • A rule is a row. Durable, generation-pinned, bound to an actor, a scope and a list of doors — including tools Brainy does not itself serve, like a shell or another MCP server, through an adapter. Every rule carries the authority that let it exist and the one sentence a refused caller is shown.

  • The check runs inside the door. policy.check is evaluated inside add, relate, update, remove, every memory write and every Accords write, before the plan is decided — a caller cannot skip it by not calling it, and every refusal or ask writes an audit row naming the actor, the rule, and the call's digest.

  • The most restrictive matching rule wins. refuse beats ask beats allow; a narrow allow can never punch a hole in a wide refuse, and no matching rule at all means allow — stated as a decision, not a default, so a fresh store with no rules behaves exactly as it always did.

  • Two tiers of authorship. Any agent may declare a rule that only tightens and only binds itself and the subagents it filed work for, effective immediately. Anything that loosens, locks, unlocks, or binds another agent needs the owner's own ruling — a credential minted only by a human sign-in, never a shared tenant key.

  • One evaluator, every adapter. The same Rust function backs the in-process API, brainy serve, the MCP door, and a harness's own pre-tool-use hook (brainy policy check), so the rule an agent meets cannot differ by which door it happened to come in through.

Full shape, the precedence law, and both tool adapters in The policy door.


Accords

Two agents and a person, working the same problem, need somewhere to keep the negotiation itself — who asked whom, what was decided, who agreed, and whether it is still open — that survives every restart and cannot be half-written by a crash mid-update. The Accords are that: coordination as a native record profile, with the protocol's own rules enforced inside the write door rather than left to application code to get right every time.

  • Ten kinds, one graph. Threads, rounds, decisions, actions, mandates, participants, presence and citations, each carried by the row's own (type, subtype) pair.

  • Eighteen protocol rules, enforced before a write lands. Append-only rounds; compare-and-post, so a blind write is refused with the rounds it missed rather than silently landing out of order; all-owner consent before an action closes; a state machine with one terminal state; only the human reopens a resolved record, and only with a reason.

  • The inbox and the dashboard are real queries, not a fetch-then-sort. Ordered segments, each a query in its own right, concatenated — so a board with ten thousand quiet threads pays only for the ten it shows.

  • Native. The five reads execute natively from a read-only attach, reachable everywhere; the eight writes execute natively too, in-process, as one generation-pinned transaction, since 12.5.0.

Full shape, the whole rule table, and a worked example in The Accords.


The doors

The same engine is reachable from wherever your code runs:

  • The SDKimport { Brainy } from '@soulcraft/brainy', in-process, every door native.

  • brainy serve — the engine's own server, a Rust binary that links the engine as a library and answers HTTP/1.1, HTTP/2, HTTP/3, WebSockets, SSE and gRPC from one generated contract, with no JavaScript in the request path.

  • MCP — the same door table as a tool list, reachable over stdio or Streamable HTTP, with a description on every tool that teaches an agent when to reach for it, not only what it does.

  • Minted keys — a static key in a file the host places is right for a service acting as itself; an arriving agent instead gets a short-lived, issuer-signed token (bk1.…) scoped to one brain and to read or read/write, verified rather than looked up, and revoked simply by letting it expire rather than by editing a file every other key also lives in.

What the hosted server answers today, and what stays in-process

Not every door has reached brainy serve yet, and the honest shape of that gap is worth stating plainly rather than discovering by a failed call. Every door that is not there yet refuses by name, carrying the release it arrives in — never a silent no-op, never an empty success.

Door family

In-process (the SDK, and brainy mcp's bridge)

brainy serve (HTTP / gRPC / WebSocket / its own MCP dispatch)

Engine reads — get, find, related, counts, aggregates, history/asOf/diff, VFS reads

served

served natively

Accords reads — inbox, dashboard, search, read, timeline

served

served natively, from a read-only attach

Accords writes — file, postRound, postUpdate, decide, vote, record, resolve, escalate

served natively since 12.5.0

in the contract as an optional term, but refuses by name — brainy serve attaches every store read-only and holds no transaction to commit a write in

Engine writes — add, update, remove, relate, transact, import, VFS writes

served

refuses by name, for the same reason

The memory profile's two contract doors — turn, abstract

served natively

in the contract, and refuses by name over the wire, for the same reason as the Accords writes

The rest of brain.memoryremember, recall, context, retire, cite, reinforce, digest, sessions, jobs, episodes, consolidate

served natively (and over MCP, via brainy mcp's bridge)

not part of the API contract at all yet — no brainy serve counterpart, not even a named refusal

Policy doors — policy_check, policy_declare, policy_propose, policy_ratify, policy_unlock, policy_freeze, policy_retire, policy_audit, policy_binding, policy_rules

served natively (policy_check runs inside every write door already)

in-process only — policy_* over MCP stays in-process until brainy serve binds the policy profile

brainy mcp is the bridge: today, running against the same public Brainy class every TypeScript consumer imports, over stdio. It is not a second product — it is this package's engine, reached over MCP one release early — and the day brainy serve dispatches every door natively, the bridge retires and brainy mcp execs brainy-serve mcp unconditionally, invisibly from a client's point of view: tool names, argument shapes and refusal codes are already brainy-serve's exactly. Full detail in brainy serve and MCP.


The engine underneath

Every pillar above rests on the same store, and the store keeps three promises regardless of which door you write through.

  • A clean close costs what you actually changed, never what the store holds. Closing flushes what this process acknowledged, attests the projections so the next open is a manifest load rather than a proof, and releases the writer lock — background jobs are stood down at their next yield rather than awaited, because every one of them carries a durable progress marker and resumes where it left off. See Clean Close.

  • A crash boot serves from what it has while it verifies. An unclean stop means the next open verifies the attach and heals any torn strand behind the doors — reads are served throughout, never blocked on a foreground rebuild.

  • Snapshot safety is a contract, not a hope: every persistent file is written so a snapshot taken at any moment, with no caller coordination, is coherent — and brain.snapshot() is that same guarantee exposed as a verb, a full, portable, file-count-bounded copy of a live store.

  • Rollback is classed and named on every release: exact (nothing on disk changed shape), rebuild (a projection's shape changed — a rollback needs repairIndex()), or snapshot (the canonical or an arena changed shape — a rollback needs a restored copy). A format change an older reader would misread sets a must-understand flag, so an old binary refuses by name rather than serving a quiet wrong answer.

  • Column-store compaction merges level-0 segments behind the doors under the same serving law as everything else — measured on a fleet-shaped copy: 320,054 segment files reduced to 1,118, 1.3 GB of blocks to 16 MB, the heaviest field's first-touch load from 1,577 ms to 0.7 ms, zero row or posting mismatches (CHANGELOG 12.5.0).

  • Converging a store is a ceremony, never a silent migration. The re-embed ceremony moves a store's vectors from one embedding space to another online and resumably, gated on your word and finishing with one atomic flip; the tokens re-index ceremony gives an existing store the token projection its rows were written without, the same way — resumable, reported by class, and readable months later from its own receipt.


How you get it

Hosted. A brain comes bundled with the rest of the Soulcraft product suite you're already on — no separate price.

Self-hosted, billed flat per year by organization, never by how much data you store, bought directly on the pricing page rather than behind a "talk to us":

Tier

Price

For

Indie

$490/year

a solo developer or a small project

Business

$2,900/year

a team running Brainy in production

Enterprise

$9,900/year, with SLA

an organization that needs a service-level agreement

Enterprise Scale

contact

organizations of 1,000+ people, with SLA and a named engineer

Every paid tier gets the same full native acceleration — a tier prices the scale you run at, never gates a capability. An unlicensed install, an invalid key, or a key whose coverage has closed for a given build all REFUSE to open — loudly, naming the cure, before touching the store — rather than stepping down to run unaccelerated. That refusal is never a data problem: underneath every tier is the same open exit, Open Brainy, the MIT reference engine, reading and writing the identical store format with no key at all — so moving off Brainy is pointing Open Brainy at the same directory, not an export. Full detail, including the license key's complete artifact inventory and what a legacy install needs to migrate, in License Artifacts.


What to read next