Embed it in a host
Introduction
Section titled “Introduction”Brain is four packages. A host takes the ones it needs and supplies the rest through ports, so Brain can sit inside an existing NestJS app with its own sign-in.
| Package | Holds |
|---|---|
@pilotoo/memory-protocol |
The zod schemas of the HTTP API and the MCP tools. Depends on zod only. |
@pilotoo/memory-core |
The domain: createBrain, services and ports. No Nest, no pg, no model SDK. |
@pilotoo/memory-server |
The Nest pieces: PostgreSQL and pgvector stores, REST and MCP controllers, model and embedding adapters, BrainKnowledgeSource. |
@pilotoo/web-auth |
Optional: Google sign-in the standalone service uses. |
The packages are not on a registry yet; install them as described in Installation.
Create the schema
Section titled “Create the schema”ensureBrainSchema creates the tables and the vector extension. It is idempotent and takes an advisory lock, so several instances may boot together. The database needs PostgreSQL with the pgvector extension available.
import { ensureBrainSchema } from '@pilotoo/memory-server';import { Pool } from 'pg';
export async function openBrainPool(databaseUrl: string): Promise<Pool> { const pool = new Pool({ connectionString: databaseUrl }); await ensureBrainSchema(pool, { schema: 'pilotoo_brain', embeddingDimensions: 1024 }); return pool;}embeddingDimensions fixes the width of the embedding column when the schema is first created. Pass the same value to brainProviders afterwards; without it the column takes vectors of any size.
Add the module
Section titled “Add the module”import { Module } from '@nestjs/common';import { brainControllers, brainProviders } from '@pilotoo/memory-server';
@Module({ controllers: brainControllers, providers: brainProviders({ pool, schema: 'pilotoo_brain', embeddingDimensions: 1024, ports: { directory }, }),})export class AppModule {}brainProviders provides BRAIN (the Brain object from createBrain) and an exception filter that gives every failure the shape {error: {code, message}}. The only required port is directory, a PeopleDirectory with get(userIds) that returns name, email and picture for the people Brain shows. The clock, ids and token hashing default to the system’s.
Identify the caller
Section titled “Identify the caller”The controllers read who is calling from the request. Your identity guard fills BrainRequest:
brainViewer:{userId, isWorkspaceAdmin}for a signed-in person.brainPrincipal: for a route markedAgentRoute(the MCP endpoint), the principal of an agent token.authenticateAgent(brain, directory, secret)returns it for apb_secret, ornull.
A request with neither is answered 401. Reject an agent token on every route that is not marked AgentRoute: its per-memory grants are honoured only by the agent service.
Add models and embeddings
Section titled “Add models and embeddings”All model ports are optional. Add the ones you want to ports:
| Port | Adapter | Notes |
|---|---|---|
extractor |
createTextExtractor() |
Text from plain text, Markdown, CSV, HTML and PDF uploads. |
embedder |
createBedrockTitanEmbedder({region, apiKey, dimensions}) |
Titan Text Embeddings V2 through Bedrock, with a Bedrock API key. model defaults to amazon.titan-embed-text-v2:0. |
embedder |
createOpenAiEmbedder({baseUrl?, apiKey, model, dimensions?}) |
Any OpenAI-compatible /embeddings endpoint; omit baseUrl for OpenAI. |
pageCompiler, answerer, labelSuggester |
createPageCompiler(model), createAnswerer(model), createLabelSuggester(model) |
Take a LangChain chat model, for example one resolved through the provider registry of @pilotoo/agent-runtime. |
import { createProviderRegistry } from '@pilotoo/agent-runtime';import { createAnswerer, createBedrockTitanEmbedder, createLabelSuggester, createPageCompiler, createTextExtractor } from '@pilotoo/memory-server';
const model = createProviderRegistry({ 'anthropic-bedrock': { region: 'eu-central-1', apiKey } }).resolveModel( { provider: 'anthropic-bedrock', modelId: 'eu.anthropic.claude-haiku-5-5' }, { maxTokens: 4096 },);
export const modelPorts = { extractor: createTextExtractor(), embedder: createBedrockTitanEmbedder({ region: 'eu-north-1', apiKey, dimensions: 1024 }), pageCompiler: createPageCompiler(model), answerer: createAnswerer(model), labelSuggester: createLabelSuggester(model),};brain.capabilities reports which of these are present: semanticSearch, answers, pageCompilation, labelSuggestions and fileExtraction.
Use memories as knowledge for kit agents
Section titled “Use memories as knowledge for kit agents”BrainKnowledgeSource implements the KnowledgeSource of @pilotoo/agent-runtime. An agent that declares memory slugs as its knowledge retrieves passages from them, and each search runs as the person making the run.
import { BrainKnowledgeSource } from '@pilotoo/memory-server';
export const knowledge = new BrainKnowledgeSource({ brain, limit: 5, viewerOf: (caller) => ({ userId: caller.identity.subject, isWorkspaceAdmin: false }),});Options
Section titled “Options”| Option | Default | Meaning |
|---|---|---|
brainProviders({pool}) |
required | The pool of a database where ensureBrainSchema has run. |
brainProviders({schema}) |
pilotoo_brain |
Schema the tables live in. |
brainProviders({embeddingDimensions}) |
none | Must match the width the schema was created with. |
brainProviders({ports}) |
directory required |
Everything the host decides: directory, and optionally clock, ids, tokenSecrets, embedder, extractor, pageCompiler, answerer, labelSuggester. |
Next steps
Section titled “Next steps”- Run the standalone service for a complete host.
- HTTP API for the routes the controllers serve.