Brains API
Every endpoint under /v1/brains: create and configure brains, write entries, recall, observe turns, forget, and manage the review queue and conflicts. All endpoints require a Bearer API key. Cross-tenant access returns 404, never 403.
Brains is gated behind a single platform-wide flag (RINGSIDE_BRAINS_ENABLED), which is enabled in production — every account, including provisioned ones, can call /v1/brains immediately. This is not a per-account setting. A 404 on these endpoints means the flag is off in that environment (for example a self-hosted or staging deployment).
To share one curated base of knowledge under many private, per-tenant brains without re-seeding it into each one, publish a brain as a Pack and mount it. See the Brain Packs API for POST /v1/brains/{id}/publish, /v1/packs and /v1/brains/{id}/mounts.
Object: brain
{
"id": "brn_3f9a2c...",
"object": "brain",
"name": "Acme advisory brain",
"embedding_model": "openai/text-embedding-3-small",
"embedding_dims": 1536,
"encryption": "none",
"tuning": "auto",
"autotune_frozen": false,
"memory_policy": { "...": "the resolved policy" },
"created_at": "2026-06-25T10:00:00.000Z",
"updated_at": "2026-06-25T10:00:00.000Z"
}Create a brain
POST /v1/brains (scope api:write). Body fields:
- name
- Required. Human label.
- encryption
- Optional. One of none, standard, strict. Default none. Immutable in effect once data is written. Set per Brain, not per scope. Key custody is Ringside-managed (server-wrapped per-brain DEK): Strict stops a DB-only compromise but is NOT zero-knowledge to Ringside, and managed learning needs plaintext server-side. Customer-held BYOK keys are not available today. See the encryption-modes section of the Brains concept page.
- embedding_model
- Optional. Default openai/text-embedding-3-small. Brains embed through the same gateway as POST /v1/embeddings, so any embedding model that endpoint supports works here: text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002, embed-english-v3.0, embed-multilingual-v3.0, voyage-3-large, voyage-3-lite, mistral-embed, text-embedding-004 (the openai/ prefix on the default is optional — the gateway resolves the bare name too). For non-English content (e.g. Greek product names) choose a multilingual-strong model — text-embedding-3-large, embed-multilingual-v3.0, voyage-3-large, mistral-embed or text-embedding-004 — not the default small, English-leaning one. Choose it deliberately up front — it is the one setting that governs every vector in the brain. It is not immutable:
POST /v1/brains/{id}/reindexre-embeds the whole brain under a new model (returns a cost estimate first; passconfirm:trueto run it), with a 7-day rollback window. Reindex is blocked while a pack is mounted. - memory_policy
- Optional. Partial policy object merged over the defaults. See the policy fields below.
curl https://api.fightclub.pro/v1/brains \
-H "Authorization: Bearer $RINGSIDE_KEY" \
-d '{ "name": "Acme advisory brain", "encryption": "standard" }'List, get, update, delete
- ·
GET /v1/brains(api:read) lists your brains. - ·
GET /v1/brains/{id}(api:read) returns one brain. - ·
PATCH /v1/brains/{id}(api:write) updatesname,encryptionormemory_policy. - ·
DELETE /v1/brains/{id}(api:write) deletes the brain and all its entries.
Write an entry
PUT /v1/brains/{id}/entries (api:write). Upserts a reference doc, a memory or a policy. Reference docs are chunked and embedded **server-side** (you do not pre-split: hand it a whole legal act or manual and it becomes many chunks in one pass); memory and policy entries are stored atomically. Embedding happens **synchronously** within the request, so a very large body makes a slower call (a multi-MB act is many embed batches; expect seconds, not milliseconds). The request body is capped at **100 MB**, sized for whole legal acts and manuals. Pass FC-Customer (or a user field) to bill the embedding to that customer.
- scope
- Optional path, default "/". The entry lives here.
- class
- reference | memory | policy. Default reference.
- type
- Optional. A type from the brain's taxonomy (for memory entries).
- title
- Optional title.
- body
- Required. The content.
- entry_id
- Optional. Provide to replace an existing entry in place.
curl -X PUT https://api.fightclub.pro/v1/brains/brn_abc/entries \
-H "Authorization: Bearer $RINGSIDE_KEY" \
-d '{ "scope": "/acme", "class": "reference",
"title": "Onboarding SOP", "body": "1. Verify identity ..." }'GET /v1/brains/{id}/entries?scope=/acme&class=memory (api:read) lists entries, optionally filtered by scope and class. Paginate with limit (1–500, default 100) and offset; the response carries has_more, limit and offset alongside data. Newest entries first. Each entry includes origin (native or reference) and source_mount_id, so you can tell a brain's own learnings apart from read-only knowledge inherited via a mounted Pack.
Read, edit and delete a single learning
Address one entry by id to display it in your own UI, correct it, or forget it. Sealed (standard/strict) brains decrypt the title and body **server-side** under the brain's data key and return plaintext over TLS — the encryption key never leaves the server and is never sent to the client.
- GET /v1/brains/{id}/entries/{entryId}
- (api:read) Returns one learning, decrypted on the fly. 404 if it does not exist in this brain.
- PATCH /v1/brains/{id}/entries/{entryId}
- (api:write) Edits in place. Send only the fields you want to change (
scope,class,type,title,body,trust). The entry id and itsuse_countare preserved. The body is re-sealed under the brain key, and the entry is re-embedded only whentitle,bodyorclasschange (a scope-only move relocates chunks without re-embedding); the response includesreindexedand the resultingchunkscount. PassFC-Customer(oruser) to bill any re-embed to that customer. - DELETE /v1/brains/{id}/entries/{entryId}
- (api:write) Forgets one learning and its chunks. Returns
{ "object": "brain.entry.deleted", "deleted": true }.
A learning with origin: "reference" was imported by a materialize mount. PATCH and DELETE on it return 409 entry_read_only — edit it in the source brain and republish the Pack, or unmount it.
# read one
curl https://api.fightclub.pro/v1/brains/brn_abc/entries/ent_123 \
-H "Authorization: Bearer $RINGSIDE_KEY"
# edit the body (re-embeds) — leave other fields untouched
curl -X PATCH https://api.fightclub.pro/v1/brains/brn_abc/entries/ent_123 \
-H "Authorization: Bearer $RINGSIDE_KEY" \
-d '{ "body": "Updated onboarding steps ..." }'
# forget one learning
curl -X DELETE https://api.fightclub.pro/v1/brains/brn_abc/entries/ent_123 \
-H "Authorization: Bearer $RINGSIDE_KEY"Recall
POST /v1/brains/{id}/recall (api:read). Returns ranked hits across the inherited scopes.
- query
- Required. The text to recall against.
- scope
- Optional, default "/". Recall sees this scope plus its ancestors.
- top_k
- Optional, default 8, max 100.
- min_score
- Optional. Drop hits below this composite score.
- classes
- Optional array. Restrict to reference, memory and/or policy.
- types
- Optional array. Restrict to these entry
typelabels.policy-class entries are exempt (guardrails always apply); memory and reference are filtered. - inherit
- Optional, default true. Set false to read only the leaf scope.
- subtree
- Optional, default false. When true, recall also covers every scope BENEATH this one (operator-wide search over your branch: agency-wide ancestors plus the whole subtree). Bounded to the brain you own.
- explain
- Optional. When true, each hit includes its factor breakdown.
- explain_misses
- Optional. When true, the response includes a
missesarray of scored-but-excluded candidates, each withdropped_by(class_filter → min_score → top_k, in precedence order). Suppressed underas_of. Bound the list withmisses_top_k. - misses_top_k
- Optional. Cap on the number of
missesreturned (default = top_k, max 100). - as_of
- Optional ISO timestamp. Bi-temporal read: returns the brain as it stood at that time (facts valid then, superseded ones excluded).
- user / FC-Customer
- Optional. Attribute this recall to a customer (cus_ id or external id, via the
userfield or the FC-Customer header) so brain.recall bills that customer's wallet instead of your dev pool.
curl https://api.fightclub.pro/v1/brains/brn_abc/recall \
-H "Authorization: Bearer $RINGSIDE_KEY" \
-d '{ "query": "where is the prod database",
"scope": "/acme/q3-audit", "top_k": 5, "explain": true }'Each hit: content is the recalled text (this is the field to read); score is the composite rank in [0,1]; class is reference | memory | policy; trust is high | low; source is the provenance. With explain: true each hit also carries a factors breakdown; subtree/ambient hits may carry explore: true. An empty data array means no hit cleared min_score. With explain_misses: true the response also carries a top-level misses array — the candidates that scored but did not make data, each tagged dropped_by — which is the fastest way to answer "why didn't my document come back?".
Observe (learn from a turn)
POST /v1/brains/{id}/observe (api:write). Feeds a finished transcript to the learn loop. Asynchronous by default (returns 202 with status learning); pass wait: true (or ?wait=true) to run synchronously and get the change counts back.
- transcript
- Required. The conversation text, e.g. lines of "user: ..." and "assistant: ...".
- scope
- Optional, default "/". Learned memories are written here.
- trust
- Optional, high | low. Mark low for external or tool-derived content.
- wait
- Optional. Run synchronously and return { changed, proposed, conflicts, used }.
- user / FC-Customer
- Optional. Attribute the learn pass (reconcile, consolidate, embed) to a customer so it bills their wallet instead of your dev pool.
curl https://api.fightclub.pro/v1/brains/brn_abc/observe?wait=true \
-H "Authorization: Bearer $RINGSIDE_KEY" \
-d '{ "scope": "/acme",
"transcript": "user: the prod db moved to 10.0.0.9\nassistant: noted" }'Default is fire-and-forget: 202 with status: "learning" returns immediately and the learn pass runs in the background. Pass wait: true (body) or ?wait=true to block and get status: "completed" with the counts: changed (entries written/updated), proposed (review-gated changes queued), conflicts (contradictions opened), used (count of existing memories the turn reinforced) and costUsd (metered cost of the reconcile/consolidate/embed pass). A no-op turn may also return "ignored": true. Use the async form on the hot path and subscribe to brain.learning.* webhooks; use wait: true for tests and backfills where you need the counts inline.
Forget
POST /v1/brains/{id}/forget (api:write). Provide exactly one of:
- scope
- Delete every entry at this scope and its descendants.
- source
- Delete every entry learned from this provenance source.
- entity
- Delete an entity, its edges and the entries linked to it.
- dry_run
- Optional, default false. Preview instead of deleting: returns
would_delete.native/would_skip.referencecounts and apreview_token. Reference (pack-mounted) rows are always skipped — unmount the pack to remove them. - preview_token
- Optional. The token from a
dry_run. If supplied, the delete runs only if the affected set is unchanged, else 409preview_stale.
Scopes and entities
Introspect what a brain holds without recalling. Both list endpoints take a required scope that bounds the listing to a subtree, plus limit (max 500) and offset; the response carries has_more.
- ·
GET /v1/brains/{id}/scopes?scope=/acme(api:read) — the scopes at or below/acme, each with anentriescount. - ·
GET /v1/brains/{id}/entities?scope=/acme(api:read) — the entities at or below/acme; add&name=Dana%20Leefor an exact lookup. - ·
GET /v1/brains/{id}/entities/{entityId}(api:read) — one entity by opaque id; cross-brain returns 404.
Reindex (change the embedding model)
The embedding model governs every vector in the brain, but it is not permanent. Reindex re-embeds the whole brain under a new model in one job, serving recall on the old vectors throughout and swapping atomically at the end.
- ·
POST /v1/brains/{id}/reindex(api:write) with{ embedding_model }returns a **cost estimate** (estimated_cost_usd,native_chunks). Add{ confirm: true }to start the job (201 with its id). - ·
GET /v1/brains/{id}/reindex/{jobId}(api:read) polls status (pending→in_progress→completed/failed), withchunks_done/chunks_totaland, once done,rollback_expires_at. - ·
POST /v1/brains/{id}/reindex/{jobId}/rollback(api:write) restores the prior model and vectors, within **7 days** of completion.
A reindex is blocked while a pack is mounted (they share the embedding space) — unmount first. A write that lands mid-job makes the swap refuse rather than lose the write; re-run if that happens. Subscribe to brain.reindex.completed / brain.reindex.failed for the completion signal.
Review queue and conflicts
- ·
GET /v1/brains/{id}/proposals(api:read) lists pending review-mode proposals. - ·
POST /v1/brains/{id}/proposals(api:write) with{ proposal_id, action: "approve" | "reject" }resolves one. - ·
GET /v1/brains/{id}/conflicts(api:read) lists open conflicts. - ·
POST /v1/brains/{id}/conflicts(api:write) with{ conflict_id }marks one resolved. - ·
POST /v1/brains/{id}/autotune(api:write) with{ action: "freeze" | "reset" }pins the learned tier weights or reverts to the baseline.
Webhook events
Subscribe a webhook endpoint to these to observe the learning loop:
- brain.learning.proposed
- A review-gated change is waiting in the proposals queue.
- brain.conflict
- A turn contradicted an existing memory; a conflict was opened.
- brain.autotune.frozen
- Auto-tune was frozen (manually or by the regression guard).
- brain.policy.changed
- A policy PATCH re-ranked stored memory. Carries
affected_entriesandchanged_types. - brain.learning.skipped
- A learn pass was skipped, e.g. the account was unfunded under
on_unfunded:recall_only. Carries areason. This is the correctly-timed signal for the async learn path (the Brain-Status header reports the pre-turn recall outcome only). - brain.reindex.completed
- A reindex job finished and the brain now serves the new model. Carries
job_idandto_embedding_model. - brain.reindex.failed
- A reindex job failed; the active space is untouched. Carries
job_idand areason.
Ambient headers (chat completions)
Request headers attach a brain to a POST /v1/chat/completions; the response carries Brain-Status so a mistyped or deleted brain id no longer fails silently.
| Header | Direction | Meaning |
|---|---|---|
| Brain | request | Brain id to attach to this completion. |
| Brain-Scope | request | Scope to recall and learn at. Default "/". |
| Brain-Trust | request | high (default) or low for the turn's learned facts. |
| Brain-Subtree | request | true to recall the whole subtree below Brain-Scope, not just ancestors. |
| Brain-Learn | request | false to recall without learning from the turn. |
| Brain-Status | response | attached (memory injected), attached:empty_recall (brain consulted, nothing relevant), or ignored:unknown_brain (unknown/cross-tenant id — failed open). Exposed via Access-Control-Expose-Headers. |
memory_policy fields
- extraction_rubric
- Natural-language guidance on what to remember and ignore.
- type_taxonomy
- Array of { type, tier, weight, decay?, anchor? }. Replaces the default preset. Set
anchorper type (created | updated | last_used) to override the brain-widedecay_anchor— e.g. keep tier C on last_used for spaced repetition while pinning tier D incident/state to created so they expire on their own clock. - consolidate_at
- Memory count per scope that triggers consolidation. Default 12.
- prune_grace_days
- Age before a cold soft memory becomes prune-eligible. Default 45.
- learn_mode
- autonomous | review.
- per_tier_review
- Per-tier override, e.g. { "A": "review", "C": "auto" }.
- tuning
- auto (live weight learning) | manual (fixed weights).
- decay_anchor
- created | updated | last_used (default last_used). Brain-wide anchor; per-type
anchoroverrides it. - on_unfunded
- fallback (default: learn anyway, dev-pool backstop) | recall_only (skip the learn pass when unfunded, preserve memory, emit brain.learning.skipped — recall is unaffected, recommended for a graceful degrade) | reject (402 on explicit write endpoints only, never the ambient path).
- ignore
- { rubric?, patterns?, require_task_relevance? } pre-gate for learning.
- chunking
- { strategy: "paragraph", max_chars }. Applies to reference docs only.