Skip to content
Pilotoo
v0.1

Models

A Brain installation has one chat model and one embedding model from its settings. Each memory can keep those, or choose others from a list the installation declares: a cheaper model for a memory that is only searched, a stronger one for a memory that is written into pages, a model on your own computer for a memory that must not leave it, or no embedding model at all.

The installation says which models exist. A memory says which of them it uses.

Field What it does Memories that have it
extract Finds the names a source mentions and decides which labels read each passage. Graph
compile Writes and updates the pages. Graph
answer Answers Ask, and decides what a new fact does to the ones a personal memory already holds. Every kind
embedding Turns passages into vectors so search finds a question worded differently from the source. A model id, or none. Graph and collection

A field left out follows the installation default. A field the kind does not use is refused.

In the web app, open Settings (or New memory) and use the Models section. Each field is a list that starts with Installation default, followed by the declared models. A model the installation cannot run at the moment is marked unavailable.

PATCH /api/memories/:mid
{ "models": { "compile": "claude-cloud", "embedding": "none" } }

models replaces the whole setting: a field you leave out goes back to the installation default. Only an admin of the memory can change it, and the change is recorded in the audit log.

Changing extract, compile or answer recompiles nothing. The new model is used from the next call.

The default models come from the settings you already have: BRAIN_MODEL and the BRAIN_EMBEDDINGS_* variables become the entries with the id default. More come from one JSON file named by BRAIN_MODELS_FILE.

models.json
{
"providers": [
{ "id": "ollama", "kind": "openai-compatible", "baseUrl": "http://127.0.0.1:11434/v1", "apiKeyEnv": "OLLAMA_API_KEY" }
],
"chat": [
{ "id": "local-qwen", "label": "Qwen 3 on this machine", "model": "ollama:qwen3:8b", "maxTokens": 4096 },
{ "id": "claude-cloud", "label": "Claude Sonnet", "model": "anthropic-bedrock:eu.anthropic.claude-sonnet-5", "reasoningEffort": "low" }
],
"embeddings": [
{ "id": "local-embed", "label": "Nomic embed", "provider": "openai-compatible", "model": "nomic-embed-text", "baseUrl": "http://127.0.0.1:11434/v1", "apiKeyEnv": "OLLAMA_API_KEY", "dimensions": 768 }
]
}
brain.env
BRAIN_MODELS_FILE=/etc/brain/models.json
OLLAMA_API_KEY=ollama
Field Meaning
id A stable slug such as local-qwen. A memory stores it. default and none are reserved.
label What people read in the web app. Defaults to the id.
model provider:modelId. The provider is one of the built-in ones (openai, anthropic, anthropic-bedrock, deepseek), configured by the same environment variables as BRAIN_MODEL, or one declared under providers.
maxTokens, reasoningEffort Optional. reasoningEffort is low, medium or high. A model on a built-in provider is called with the same settings as BRAIN_MODEL; a model on an openai-compatible provider sends no effort unless you set one.
Field Meaning
id, label As above.
provider bedrock-titan or openai-compatible.
model Required for openai-compatible. bedrock-titan defaults to amazon.titan-embed-text-v2:0.
baseUrl openai-compatible only. Without it, OpenAI.
region Required for bedrock-titan.
dimensions The width of the vectors. bedrock-titan defaults to 1024. Every vector the model returns is checked against it.
apiKeyEnv The name of the environment variable that holds the key, ending in _KEY. Required for openai-compatible. bedrock-titan defaults to AWS_BEARER_TOKEN_BEDROCK.

An entry with "runs": "worker" has no model, provider or key in this file: a worker on a machine you control answers it. It takes only id, label and, for an embedding model, dimensions.

models.json
{ "chat": [{ "id": "local-qwen", "label": "Qwen 3 on my Mac", "runs": "worker" }] }

A provider declares an openai-compatible endpoint with its own baseUrl, which is how Brain reaches a local server. baseUrl must be https, except for localhost, 127.0.0.1 and [::1]. apiKeyEnv names a variable ending in _KEY; a server that ignores keys, such as Ollama, still needs the variable set to any value.

Boot stops, naming the reason, when the file is not valid JSON, has a field it does not know, repeats an id (across chat and embedding models alike) or uses a reserved one. A model whose key is not in the environment is not an error: it stays listed and is marked unavailable.

A memory can name a model the installation no longer declares, or whose provider has no key. Brain never falls back to the default model, because that would send the memory’s text somewhere its owner did not choose.

Where What happens
A source waiting to be read or compiled The document fails with Model <id> is not available on this installation.
A source added to a memory whose embedding model is unavailable The source fails with the same reason.
Ask Answers with the same error.
Search Drops to full-text.
Settings The model is marked unavailable.

Every vector records the model that made it. Search embeds the question with the memory’s model and compares it only with passages that model embedded; the others are still found by their words. Vectors of two models are never compared, so changing the model never returns garbage, only less semantic recall until the passages are embedded again.

A memory that follows the installation default shows its embedding as default.

Set embedding to none and the memory embeds nothing: search is full-text and its vectors are removed at once.

When you change the embedding model, Brain queues one job that embeds the memory’s passages again, in batches, newest documents first. The job can stop and resume: it takes only the passages the model has not embedded, so what is done stays done. A second change while the job waits does not queue a second one. Until it ends, search works as described above.

New documents, and passages cut again by labelling, use the memory’s current model.

The count of passages not embedded by the current model is derived, never stored. A memory returns it as embedding:

GET /api/memories/:mid
{ "models": { "embedding": "local-embed" }, "embedding": { "model": "local-embed", "pending": 120, "passages": 480 } }

Only a memory admin sees pending and passages; everyone else reads 0. The settings screen shows the count and an Embed again button while it is above zero.

When the installation default changes under a memory that follows it (a different BRAIN_EMBEDDINGS_MODEL, region, base URL or width), nothing runs on its own. The count shows the passages the new default has not embedded, and Embed again starts the job.

Terminal window
curl -X POST -b cookies.txt https://brain.example.com/api/memories/$MID/reembed

Point an openai-compatible provider at the server on your machine. Brain calls it from the machine it runs on, so for a local Ollama Brain must run there too, or the server must be reachable at a baseUrl Brain can open.

  1. Pull a chat model and an embedding model in Ollama.
  2. Declare them as in the example above, with the Ollama URL ending in /v1.
  3. Set OLLAMA_API_KEY to any value.
  4. In the memory’s settings, choose the local models.
Setting Default Meaning
BRAIN_MODELS_FILE none Path of the JSON file above.
BRAIN_MODEL, BRAIN_EMBEDDINGS_* off The models with the id default.