Prefer Swagger UI? Click hereThe same API in the classic OpenAPI explorer.
// concept · 11 min read

Brain Packs and mounts

A Brain is single-tenant by design: its own data, its own encryption key, its own policy. That isolation is the point, but it leaves one gap. When you run many brains for many tenants, they often need to share a common base of knowledge defined once, an org or platform layer, without copying it into every tenant by hand. A Pack is that base: an immutable, versioned snapshot minted from a brain. A mount layers one or more Packs under a brain as read-only base layers, remapped into its scope tree. Recall composes the brain and its mounted Packs in one ranked pass; writes only ever land in the brain's own native layer.

Availability

Brain Packs are gated behind a platform flag (RINGSIDE_BRAIN_PACKS_ENABLED) on top of the Brains flag. Where the flag is off, the publish, packs and mounts endpoints return 404 and recall runs its normal single-brain path unchanged. A brain with no mounts is byte-identical to a brain that has never heard of Packs.

This supersedes "sub-brains"

There is no parent_brain_id, no brain inheritance and no "sub-brains" feature. That earlier proposal was superseded by Brain Packs: a brain mounts an immutable, versioned Pack published from another brain rather than inheriting from a parent. If you arrived searching for sub-brains, this is the replacement.

The gap Packs close

Scope inheritance already gives you a shared top inside one brain: an entry at / is seen by every scope below it, so an agency can keep agency-wide knowledge at the root and per-client memory under /acme, /globex. What it cannot give you is per-tenant encryption or per-tenant policy, because the data-encryption key and the memory policy are properties of the whole brain, not of a scope. A tenant that needs its own sealing or its own taxonomy needs its own brain, and the moment it gets one it loses the shared top.

Packs add the missing primitive. The shared base lives in one place and is published as a versioned artifact. Each tenant keeps its own brain, with its own key and policy, and mounts the published base underneath. Update the base once and every tenant sees the new version; nobody re-seeds anything.

Three objects: Brain, Pack, Mount

Brain
A living, writable, single-tenant memory store. Unchanged. This is where learning and your own writes land.
Pack
An immutable, versioned snapshot minted from a brain: entries, chunks, already-computed vectors, the knowledge graph (entities and edges) and the frozen policy and tier weights. The unit of sharing. You depend on a published version, like a library at 1.2.0, never on a moving HEAD.
Mount
A brain mounting one or more Pack versions as read-only base layers, remapped into its scope tree. Recall reads brain plus mounted Packs; writes only ever hit the brain's native layer.
Mental model

Read-only base layers under one writable top, the way Docker layers or a filesystem mount work. The base is shared and immutable; everything you write sits in the leaf on top of it.

Why encryption stays on the private layer

The load-bearing insight is that the shared base is not secret. It is the platform's own runbooks and instincts, identical for every tenant. The genuinely private material, your server topology, procedures and gotchas, lives in the tenant's own brain layer; raw credentials and keys belong in a real secret store, never in a Brain at all.

So sealing the shared base under each tenant's key buys no security and costs one full copy per tenant. Encryption stays where it belongs, on the per-tenant private layer that is already sealed under the tenant key, and the shared base is stored once and read by all. That single decision drives the two mount modes.

Two mount modes

ModeStored in the consumer brainHow recall uses itWhen to choose it
referenceNothingRecall reads candidates from the Pack version's own store (stored once) and scores them alongside the brain's native rows in one pass.The default for a shared base: non-secret, reused by many tenants. The scale case.
materializeA re-sealed copyThe Pack's rows are imported into the brain, re-sealed under the consumer key, and recall is otherwise unchanged.Strict isolation: a tenant wants even the shared layer sealed under its own key, or a cross-account consumer wants a self-contained copy.

Both ship in v1. reference is the right economics for a shared base read by thousands of tenants, because the base is stored once and adding a tenant adds no copy. materialize is the premium strict-isolation tier: it duplicates and re-seals the base per tenant, and a new published version re-imports. In v1 reference is intra-account (publisher and consumer share the same account) or reads a plaintext Pack; cross-account reference is deferred. materialize already covers cross-account today via a granted, imported copy.

reference needs a plaintext Pack

A reference mount reads the Pack version's store live, so it requires the Pack to be published with encryption_at_publish: none. That avoids any cross-key unwrap: the shared base is plaintext, while the tenant's private layer stays sealed under the tenant key, untouched. Mounting a sealed Pack by reference is rejected with 409 reference_requires_plaintext_pack.

How recall composes the layers

Mounted content, in either mode, is reference knowledge: static, curated, evergreen. The brain's native rows are episodic memory that ages and reinforces. Recall scores everything with the same composite, cosine x tier_weight x recency x usage x graph, but four rules govern how the two layers compose. They are a small, explicit extension keyed on where a row came from, not a rewrite of recall.

  1. 01Evergreen reference scoring. A mounted row skips recency and usage (both forced to 1.0) and keeps cosine x tier_weight x graph. Shared base knowledge does not rot or get reinforced like the tenant's own memory.
  2. 02The Pack carries its own tiers. A mounted row resolves its tier weight from the Pack version's frozen taxonomy; native rows use the consumer's policy. A tier-A gotcha keeps its authored importance even if the consumer's policy never defines that type.
  3. 03Reserved native slots, relevance-gated. A native hit claims a reserved top-k slot only when it clears a relevance threshold; reference backfills when native is sparse or off-topic. The tenant's own memory surfaces when it is actually relevant, the static base cannot crowd it out, and a near-empty new tenant does not waste slots.
  4. 04Native shadows reference. A native entry suppresses or outranks its Pack twin when it explicitly supersedes it, or shares the same scope and normalized entity or title. The tenant's site-specific override beats the shared default. Semantic-only contradictions with different wording are not caught in v1.
Autotune ignores mounted rows

Recall feeds the consumer brain's autotune, but mounted rows never drive it: they are shared, evergreen and Pack-tiered, not the tenant's authored memory. Conversely, publish snapshots the source brain's live, autotuned tier weights, so a Pack carries the publisher's real importance model rather than bare policy defaults.

The graph travels with the Pack for the same reason. Recall graph-boosts entries whose entities match the query, so a Pack snapshots entities and edges alongside entries and chunks. materialize imports them (scope-remapped, mount-tagged); reference recall reads the Pack version's entities for its own rows. In v1 each store boosts only its own entries; native-to-Pack graph edges are deferred.

Scope remapping

A mount carries a scope map that rebases the Pack's scopes into the consumer's tree, applied by longest-prefix match. The default { "/": "/" } mounts the whole Pack at the consumer root. { "/": "/shared" } tucks it under /shared. Explicit entries remap subtrees independently, for example { "/policies": "/shared/policies" }. For materialize the rewrite happens once at import; for reference it is applied at query time, reverse-mapping the recall's ancestor scopes back to Pack scopes to fetch candidates.

Pack scopes                 mount scope_map            consumer brain
/                  --->  { "/": "/shared" }   --->   /shared       (read-only base)
/policies          --->                              /shared/policies
                                                     /acme         (native, writable)
                                                     /acme/q3

recall at /acme/q3  ->  native /, /acme, /acme/q3  +  Pack base under /shared
A scope map rebases a Pack under the consumer tree. Writes still only land in native scopes.

The API surface

Publishing and mounting are a thin layer over the Brains API you already use. Every route goes through the same Brains auth and owner-scoped 404.

  • ·POST /v1/brains/{id}/publish snapshots the brain's current entries, chunks, vectors, graph and policy into the next immutable Pack version, auto-creating the Pack on first publish. Large snapshots build asynchronously (building then ready).
  • ·GET /v1/packs and GET /v1/packs/{packId} list and inspect Packs you own or are granted, with their versions.
  • ·POST /v1/packs/{packId}/grants and DELETE /v1/packs/{packId}/grants/{granteeId} grant and revoke cross-account mount access.
  • ·DELETE /v1/packs/{packId} soft-retires a Pack: it disappears from new mounts, existing reference mounts keep reading it, and content is collected only once the last reference mount drops or re-points.
  • ·POST /v1/brains/{id}/mounts mounts a Pack version; GET, PATCH and DELETE on the same path list, re-point and unmount.
  • ·POST /v1/brains/{id}/recall is unchanged on the wire: it composes native and mounted content automatically.

Mounting validates a few invariants. The Pack's embedding_model must equal the consumer brain's, or you get 422 embedding_model_mismatch, because the two stores have to share one cosine space. A reference mount requires a plaintext Pack (409 reference_requires_plaintext_pack). A malformed scope_map returns 400. A brain may hold at most one reference mount in v1 (a second returns 409 reference_mount_limit); materialize mounts are unlimited.

# 1. Publish the shared base as a plaintext Pack (required for reference)
curl https://api.fightclub.pro/v1/brains/brn_base/publish \
  -H "Authorization: Bearer $RINGSIDE_KEY" \
  -d '{ "name": "platform-runbooks", "slug": "platform-runbooks",
        "encryption_at_publish": "none", "notes": "Q3 base" }'
# -> { "pack_id": "pack_...", "version": 1, "status": "ready", ... }

# 2. Mount that version under a tenant brain, rebased to /shared
curl https://api.fightclub.pro/v1/brains/brn_acme/mounts \
  -H "Authorization: Bearer $RINGSIDE_KEY" \
  -d '{ "pack_id": "pack_...", "mode": "reference",
        "scope_map": { "/": "/shared" } }'

# 3. Recall composes native /acme memory with the mounted base, in one call
curl https://api.fightclub.pro/v1/brains/brn_acme/recall \
  -H "Authorization: Bearer $RINGSIDE_KEY" \
  -d '{ "scope": "/acme/q3", "query": "how do we roll back a failed deploy" }'

Versioning and updates

Pack versions are immutable: a version never changes, and updating the base means publishing a new one. A mount is pinned by default, so it keeps reading the exact version it was created against until you move it. Set follow_latest: true and a new publish re-points a reference mount (cheap) or re-materializes a materialize mount (atomic: import-new, flip, delete-old, so recall never sees a half-swapped base). Changing version on a PATCH does the same on demand.

Tenancy and authorization

Intra-account mounts need no grant: when the publisher and consumer share an account, ownership authorizes the mount. This is the primary case, one platform account holding many tenant brains. Grants exist only for cross-account mounts, where the owner of a Pack explicitly grants another account the right to mount it. Unpublished brains keep the hard cross-tenant 404 invariant intact; the only thing that ever crosses an account boundary is a Pack its owner published and granted.

Publishing is a declassification

A reference mount needs a plaintext Pack, so publishing a sealed brain to encryption_at_publish: none decrypts its content and stores it in the clear in the Pack. That is an explicit owner opt-in, and the default mirrors the source brain's encryption. Treat publish as a distribution amplifier: review the base for anything that should not be shared before you publish it plaintext.

Billing

  • ·Publish counts the Pack version's content toward the publisher's storage, at the normal storage rate. No embedding charge, because the vectors are copied, not recomputed.
  • ·A reference mount adds no consumer storage at all: the base is stored once by the publisher and read live. Recall reads the shared index, which is compute, not storage.
  • ·A materialize mount counts the imported copy toward the consumer's storage, again at storage rate only, because vectors are reused rather than re-embedded.
  • ·Retained Pack versions are billed to the publisher's storage. That is the economic pressure to deprecate old versions, without forcing any consumer to churn off a version it still pins.

The scale case

Picture thousands of tenants, each needing its own key for its private server topology and procedures, over a small, non-secret shared base of a thousand or so chunks. materialize does not fit: one re-sealed copy per tenant turns a 1k-chunk base over 10k tenants into roughly 10M duplicated sealed rows, a base update re-seals all of them, and the same base is decrypted ten thousand times under ten thousand keys. reference fits cleanly: the base is stored once at a few megabytes, every tenant's private layer stays sealed under its own key, and a base update rewrites exactly one Pack version that every tenant sees with no per-tenant work. materialize remains available as the strict-isolation escape hatch for any tenant that wants even the shared base under its own key, and tenants that need no isolation at all can skip brains-per-tenant entirely and live as scopes in one shared brain.

What v1 ships, and what it does not

In v1: publish (one Pack per source brain, versioned, graph included, serial versions); one reference mount per brain (intra-account or plaintext Pack); unlimited materialize mounts, including cross-account via grants; scope remapping; the four recall composition rules; pinned-by-default with opt-in follow_latest; soft-retire with computed-refcount collection and billed retained versions; unmount; an async build and materialize worker with status; and private grants.

Deferred to later, on the same API: cross-account reference (live read across accounts, which needs the read grant plus approximate nearest-neighbour search on a large shared index); org, unlisted and public visibility with a Pack catalog; more than one Pack per source brain; and incremental publish (v1 republish is always a full snapshot).