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
layerfield. 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 noforget(), and there will not be one.Scopes as fences, not filters.
world,visibilityandretiredare 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 — andcitationRankis 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 instantremember()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()andmemory.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.checkis evaluated insideadd,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 oraskwrites an audit row naming the actor, the rule, and the call's digest.The most restrictive matching rule wins.
refusebeatsaskbeatsallow; a narrowallowcan never punch a hole in a widerefuse, 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 SDK —
import { 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 toreadorread/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 |
|
|---|---|---|
Engine reads — | served | served natively |
Accords reads — | served | served natively, from a read-only attach |
Accords writes — | served natively since 12.5.0 | in the contract as an optional term, but refuses by name — |
Engine writes — | served | refuses by name, for the same reason |
The memory profile's two contract doors — | served natively | in the contract, and refuses by name over the wire, for the same reason as the Accords writes |
The rest of | served natively (and over MCP, via | not part of the API contract at all yet — no |
Policy doors — | served natively ( | in-process only — |
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.