Skip to navigation

Brain & Memory

Persistent agent memory and per-project knowledge base

Overview

The SDK provides three related resources for AI agent memory and project intelligence:

  • r.memory — Persistent facts and decisions that survive across sessions. Network-scoped.
  • r.brain — Send messages to the Brain AI (response streams via WebSocket).
  • r.projectBrain — Per-project dashboard: tasks, milestones, team activity, usage stats.

Memory (r.memory)

Facts

Store and retrieve facts — things worth remembering across sessions such as patterns, conventions, preferences, and gotchas.

Store a fact

const { data: fact } = await r.memory.facts.add({
fact: 'This project uses Hono, not Express',
project_id: 'proj_123',
source: 'manual',
tags: ['architecture', 'routing'],
});
console.log(fact.id);
console.log(fact.fact);
console.log(fact.tags);

Input fields:

FieldTypeRequiredDescription
factstringYesThe fact to remember.
project_idstring?NoScope to a project.
organization_idstring?NoScope to an organization.
agent_idstring?NoAssociate with a specific agent.
user_idstring?NoAssociate with a specific user.
source'auto' | 'manual' | 'extraction'NoHow the fact was discovered. Default: 'manual'.
tagsstring[]?NoTags for categorization.

Memory rejects facts that appear to contain secrets (API keys, passwords, tokens). Store secrets in environment variables instead.

List facts

const { data: facts } = await r.memory.facts.list({
project_id: 'proj_123',
});
for (const fact of facts) {
console.log(`[${fact.source}] ${fact.fact}`);
console.log(` Tags: ${fact.tags.join(', ')}`);
}

Filter parameters:

ParameterTypeDescription
project_idstring?Filter by project.
organization_idstring?Filter by organization.
agent_idstring?Filter by agent.
user_idstring?Filter by user.
querystring?Full-text search within facts.

Remove a fact

await r.memory.facts.remove('fact_123');

Decisions

Log architectural, strategic, or technical decisions with context. Decisions are searchable and shared across the organization.

Log a decision

const { data: decision } = await r.memory.decisions.log({
decision: 'Use pgvector for semantic search',
context: 'Evaluated Pinecone, Weaviate, and pgvector. Chose pgvector for simplicity -- it runs in our existing Postgres instance with no additional infrastructure.',
tags: ['architecture', 'database', 'search'],
project_id: 'proj_123',
});
console.log(decision.id);
console.log(decision.decision);

Input fields:

FieldTypeRequiredDescription
decisionstringYesThe decision that was made.
contextstring?NoWhy the decision was made, alternatives considered.
tagsstring[]?NoTags for categorization.
project_idstring?NoScope to a project.
organization_idstring?NoScope to an organization.
agent_idstring?NoAssociate with an agent.

List decisions

const { data: decisions } = await r.memory.decisions.list({
project_id: 'proj_123',
topic: 'database',
limit: 10,
});
for (const d of decisions) {
console.log(`Decision: ${d.decision}`);
console.log(`Context: ${d.context}`);
console.log(`Tags: ${d.tags.join(', ')}`);
}

Search memory

Search across all memory types (facts, decisions, and conversations) with relevance ranking.

const { data: results } = await r.memory.search({
query: 'authentication approach',
project_id: 'proj_123',
limit: 10,
});
for (const result of results) {
console.log(`[${result.type}] Score: ${result.score}`);
console.log(` ${result.content}`);
}

Input fields:

FieldTypeRequiredDescription
querystringYesSearch query.
project_idstring?NoScope to a project.
organization_idstring?NoScope to an organization.
agent_idstring?NoFilter by agent.
limitnumber?NoMax results (default 10).

Returns: SingleResponse<MemorySearchResult[]>

interface MemorySearchResult {
type: 'fact' | 'decision' | 'conversation';
id: string;
content: string;
score: number;
metadata: Record<string, unknown>;
}

Build context injection

Build a formatted context block from relevant memories for a given message. Use this to enrich system prompts with past knowledge.

const { data: { context } } = await r.memory.context({
message: 'How should I implement the payment flow?',
project_id: 'proj_123',
max_tokens: 2000,
});
// Use the context in a system prompt
const systemPrompt = `You are a helpful assistant.
## Relevant context from memory:
${context}
Now answer the user's question.`;

Input fields:

FieldTypeRequiredDescription
messagestringYesThe current message/task to find context for.
project_idstring?NoScope to a project.
organization_idstring?NoScope to an organization.
agent_idstring?NoFilter by agent.
max_tokensnumber?NoToken budget for the context string (default 2000).

Purge memory

Delete all memory (facts and decisions) for a project. This is irreversible.

const { data: result } = await r.memory.purge('proj_123');
console.log(`Deleted ${result.factsDeleted} facts and ${result.decisionsDeleted} decisions`);

Purging memory is irreversible. All facts and decisions for the project will be permanently deleted.

Brain (r.brain)

Send messages to the Brain AI. The response streams back via WebSocket.

const { data: { message_id } } = await r.brain.sendMessage({
message: 'What should I work on next?',
history: [
{ role: 'user', content: 'I just finished the auth module.' },
{ role: 'assistant', content: 'Great! The next priority is the billing integration.' },
],
context: {
current_route: '/dashboard',
org_slug: 'my-org',
},
});
console.log('Message ID:', message_id);
// Listen on WebSocket for the streamed response

Project Brain (r.projectBrain)

Per-project intelligence dashboard with tasks, milestones, team activity, and usage stats.

List tasks

const { data: tasks } = await r.projectBrain.tasks('proj_123', {
status: 'pending',
milestone: 'v1-launch',
});
for (const task of tasks) {
console.log(`${task.title} [${task.status}] — effort: ${task.effort}`);
}

Get project stats

const { data: stats } = await r.projectBrain.stats('proj_123');
console.log(stats);

List milestones

const { data: milestones } = await r.projectBrain.milestones('proj_123');
for (const m of milestones) {
console.log(`${m.name}: ${m.task_progress.completed}/${m.task_progress.total} tasks`);
console.log(` ${m.task_progress.percentage}% complete`);
}

List project decisions

const { data: decisions } = await r.projectBrain.decisions('proj_123', {
limit: 5,
});

List project agents

const { data: agents } = await r.projectBrain.agents('proj_123');
for (const agent of agents) {
console.log(`${agent.name} (@${agent.username}) — ${agent.model}`);
}

Team activity

const { data: activity } = await r.projectBrain.teamActivity('proj_123');
for (const member of activity.team) {
console.log(`${member.name}: ${member.completed_count} completed, ${member.active_claim_count} active`);
if (member.current_work) {
for (const work of member.current_work) {
console.log(` Working on: ${work.task_title}`);
}
}
}
console.log('\nActive claims:');
for (const claim of activity.active_claims) {
console.log(` ${claim.task_title} — claimed by ${claim.agent_id}`);
}

Complete a task

await r.projectBrain.completeTask('proj_123', 'task_456', 'Implemented and tested');

Get usage stats

const { data: usage } = await r.projectBrain.usage('proj_123');
console.log(`Total requests: ${usage.total_requests}`);
console.log(`Input tokens: ${usage.input_tokens}`);
console.log(`Output tokens: ${usage.output_tokens}`);
console.log(`Cost: $${usage.cost_dollars.toFixed(4)}`);

Golden path: agent with persistent memory

Here is a complete example of an agent that uses memory to maintain context across sessions:

import { Recursiv } from '@recursiv/sdk';
const r = new Recursiv();
const PROJECT_ID = 'proj_123';
const AGENT_ID = 'agent_456';
// 1. Load relevant context from memory
const { data: { context } } = await r.memory.context({
message: 'Review the latest code changes',
project_id: PROJECT_ID,
agent_id: AGENT_ID,
max_tokens: 1500,
});
// 2. Chat with the agent, injecting memory context
const { data: reply } = await r.agents.chat(AGENT_ID, {
message: `Context from memory:\n${context}\n\nPlease review the latest code changes and suggest improvements.`,
});
console.log('Agent response:', reply.content);
// 3. Store what the agent learned
await r.memory.facts.add({
fact: 'Code review completed on 2025-01-15. Found 3 issues in auth module.',
project_id: PROJECT_ID,
agent_id: AGENT_ID,
source: 'auto',
tags: ['code-review', 'auth'],
});
// 4. Log the decision
await r.memory.decisions.log({
decision: 'Refactor auth middleware to use async validation',
context: 'Current sync validation blocks the event loop under load. Agent review identified this as the primary performance bottleneck.',
project_id: PROJECT_ID,
agent_id: AGENT_ID,
tags: ['auth', 'performance'],
});