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

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.

Availability

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).

Sharing a base across many brains

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}/reindex re-embeds the whole brain under a new model (returns a cost estimate first; pass confirm:true to 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) updates name, encryption or memory_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 its use_count are preserved. The body is re-sealed under the brain key, and the entry is re-embedded only when title, body or class change (a scope-only move relocates chunks without re-embedding); the response includes reindexed and the resulting chunks count. Pass FC-Customer (or user) 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 }.
Reference rows are read-only

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 type labels. 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 misses array of scored-but-excluded candidates, each with dropped_by (class_filter → min_score → top_k, in precedence order). Suppressed under as_of. Bound the list with misses_top_k.
misses_top_k
Optional. Cap on the number of misses returned (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 user field 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.reference counts and a preview_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 409 preview_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 an entries count.
  • ·GET /v1/brains/{id}/entities?scope=/acme (api:read) — the entities at or below /acme; add &name=Dana%20Lee for 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 (pendingin_progresscompleted / failed), with chunks_done/chunks_total and, 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.
Note

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_entries and changed_types.
brain.learning.skipped
A learn pass was skipped, e.g. the account was unfunded under on_unfunded:recall_only. Carries a reason. 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_id and to_embedding_model.
brain.reindex.failed
A reindex job failed; the active space is untouched. Carries job_id and a reason.

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.

HeaderDirectionMeaning
BrainrequestBrain id to attach to this completion.
Brain-ScoperequestScope to recall and learn at. Default "/".
Brain-Trustrequesthigh (default) or low for the turn's learned facts.
Brain-Subtreerequesttrue to recall the whole subtree below Brain-Scope, not just ancestors.
Brain-Learnrequestfalse to recall without learning from the turn.
Brain-Statusresponseattached (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 anchor per type (created | updated | last_used) to override the brain-wide decay_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 anchor overrides 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.