Guides / Use cases

Multi-agent systems

For systems where several agents work on one job: a planner, a researcher, a writer, a reviewer. Recall gives each agent its own memory of what it saw, a shared memory the team can ask, and a signal when new knowledge is ready, so agents stop passing whole transcripts to each other.

What memory adds

Without memory, what one agent learns reaches another only if your orchestrator copies it into a prompt, and it is gone when the job ends. With it:

Without memoryWith Recall
The researcher finds that competitor A raised its priceThe planner knows only if the orchestrator pastes the researcher's output into its prompt.The planner's own view of the researcher holds it, because both were in the job.
A week later, a new job on the same marketThe research starts from zero."What do we know about competitor pricing?" is answered from the team's earlier jobs.
The orchestrator crashes and retries step 2The findings are stored twice.The retry carries the same idempotency key, and nothing is stored twice.

Recall does not run, route or schedule agents. Your orchestrator decides who speaks and when; Recall keeps what was said and what each agent learned from it.

How to model it

In your systemIn RecallWhy
A team of agents, or one deploymentWorkspace, e.g. acme-agentsAgents in it can share memory; nothing crosses into other workspaces.
Each agentPeer agent-planner, agent-researcherAn agent speaks like anyone else. Leave it observed when what it says is worth learning (findings); set observeMe: false on agents whose output need not be remembered, such as a formatter.
The person who gave the jobPeer user-8412What the agents learn about the person, and the one id to erase if they ask.
A job, task or threadSession, e.g. job-58213The job's messages in order, with a summary of older steps.
What one agent knowsThat agent's view: observeOthers: true in the sessions it takes part inBuilt only from jobs the agent was in. Read it with peerPerspective, or ask with chat and target.
What the team knowsA scope, e.g. team-pricing, or the whole workspaceAsk across every job in the scope with recall.chat.

Build it

Install the SDK (npm install @recall-memory/sdk or pip install recall-mem) and set RECALL_API_KEY. One session per job; each agent that needs its own view gets observeOthers, and the job joins the team's scope.

import { constructWebhookEvent, Recall } from "@recall-memory/sdk";

const recall = new Recall({ workspaceId: "acme-agents" });

const user = recall.peer("user-8412");
const planner = recall.peer("agent-planner");
const researcher = recall.peer("agent-researcher");

// One session per job. Each agent in it builds its own view of the others from what it saw.
// The job also joins the team's scope, the memory the whole team shares.
const job = recall.session("job-58213", {
  peers: {
    "user-8412": {},
    "agent-planner": { observeOthers: true },
    "agent-researcher": { observeOthers: true },
  },
  scopes: ["team-pricing"],
});

Record every step, under a key. The SDKs make each write safe to retry within one call. Across processes, after a crash, only a key you choose helps: name the step in it, and a second write with the same key in the same session returns the messages already stored.

// The orchestrator records each step under a key that names it. A retry after a crash or a
// timeout returns the stored messages instead of storing them twice.
const step = (n: number) => ({ idempotencyKey: `job-58213:step-${n}` });
await job.addMessages(
  [user.message("Compare our Pro plan with the three biggest competitors by Friday.")],
  step(1),
);
const findings = [
  researcher.message("Competitor A raised its Pro plan to €49 a month in September."),
  researcher.message("B and C still charge €39; C gives two months free on yearly plans."),
  planner.message("Next: draft a price proposal. Researcher, check annual discounts at A."),
];
await job.addMessages(findings, step(2));
await job.addMessages(findings, step(2)); // the retry: nothing is stored twice

Each agent reads through its own eyes. "What does agent X know about Y" is a chat from X with target: Y: a few seconds, with a model call. For an agent's next prompt, read context with peerPerspective instead: no model call, a fraction of a second.

// What does the planner know about the researcher's findings? Its own view: only what it saw.
// (waitForIdle is for this demo; agents rarely block on learning.)
await recall.waitForIdle();
const known = await planner.chat("What has the researcher found about competitor prices?", {
  target: researcher,
  reasoningLevel: "low",
});
// The researcher's view of the user, as prompt context for its next step (no model call).
const ctx = await job.context({ peerTarget: user, peerPerspective: researcher, tokens: 2000 });
const prompt = ctx.toOpenAI(researcher);

Shared memory: ask the team's scope. A question with scope reads every job filed under it, from no single agent's point of view. Leave out scope to ask across the whole workspace.

// Shared team memory: ask across every job in the team's scope, not through one agent's eyes.
const shared = await recall.chat("What do we know about competitor pricing?", {
  scope: "team-pricing",
  reasoningLevel: "low",
});

React when new knowledge is ready. Learning runs in the background. Instead of polling, register a webhook: Recall sends queue.empty when background work for a session finishes, with the session and the observer whose view changed. Register once per workspace (at most 10 endpoints; private addresses are refused):

curl $RECALL_URL/v3/workspaces/acme-agents/webhooks \
  -H "Authorization: Bearer $RECALL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://agents.example.com/recall-webhook"}'

The SDKs do the same with recall.webhooks.create(url). Each delivery is signed: X-Recall-Signature is the HMAC-SHA256 of the raw body, keyed with your webhook secret (under Settings in the dashboard). Verify it before you trust the event, keep the X-Recall-Event-Id values you have handled to drop retries, and answer 2xx quickly.

// Your HTTP handler for Recall's webhook: verify the raw body before you parse it.
async function onRecallWebhook(rawBody: string, signature: string | null, secret: string) {
  const event = await constructWebhookEvent<{ observer: string; session_id: string }>(
    rawBody,
    signature,
    secret,
  );
  // queue.empty: learning for this session is done. Wake the agent whose view changed.
  if (event.type !== "queue.empty" || event.data.observer !== planner.id) return null;
  return planner.chat("What is new in this job since my last step?", {
    session: event.data.session_id,
    reasoningLevel: "minimal",
  });
}

A key per agent

An agent that reads untrusted text can be talked into calling tools it should not. Give each agent a key that reaches no further than it needs:

Key scoped toIt canGive it to
A workspaceEverything in that workspace: record, read any view, ask a scope, forget a person.The orchestrator.
A peerAsk as that peer (chat, with target), read its card and context, and read the sessions it is a member of. It cannot record messages, ask a scope, or delete a peer (401).An agent that only needs to consult its own memory.
A sessionOnly that session: record in it and read its messages and context. No peer routes, no other sessions.A sandboxed worker on one job.

Create keys under API keys in the dashboard, or mint them in code with an account-wide key. Minted keys are revoked together with the key that minted them, and expiresAt suits short-lived workers:

// TypeScript
const plannerKey = await recall.createKey({ workspaceId: "acme-agents", peerId: "agent-planner" });
const workerKey = await recall.createKey({ workspaceId: "acme-agents", sessionId: "job-58213" });

# Python
planner_key = recall.create_key(workspace_id="acme-agents", peer_id="agent-planner")
worker_key = recall.create_key(workspace_id="acme-agents", session_id="job-58213")

Settings that matter

SettingUse
observeOthers: true per agent, per sessionThe agent builds its own view of the others in that job. At most 10 members of a session can have it; give it to the agents that need their own view, not to all.
observeMe: false on an agentIts messages are kept and read, but nothing is learned from them. Use it for agents that only reformat or route.
peerPerspective on context or turnRead the target through one agent's eyes. Without it, an agent sees what Recall learned from every job, including ones it was never in.
target on chatAsk what one peer knows about another.
scopes on the session, scope on recall.chatShared team memory, limited to the jobs filed under the scope.
idempotencyKeyYour own key per step, so a retry from a restarted process stores nothing twice.
reasoningLevel: "minimal"For quick checks an agent makes often, such as after a webhook. See Reasoning levels and models.

Cost and speed

Measured from Europe against the hosted API (Frankfurt), October 2026: a context read took 0.3 to 0.7 seconds, a search about 0.9 seconds, and a question at minimal or low 2 to 4.5 seconds. high and max run a tool loop and are slower. Learning usually finishes within about 20 seconds of a write; the webhook tells you when.

Context, search and storage are included. You pay for learning, $1.75 per million message tokens with every message counting as at least 50, and for questions. A message is billed once, however many agents observe it. A user who starts 40 jobs a month, each with a 150-token brief, 30 agent messages of about 250 tokens and 4 questions:

ItemPer month
Briefs: 40 × 150 tokens × $1.75 / 1M$0.0105
Agent messages: 40 × 30 × 250 tokens × $1.75 / 1M$0.525
Questions at low: 160 × $0.005$0.80
Context readsincluded
Totalabout $1.34 a month, or 3.3 cents a job

The agents' messages are most of the learning cost. Agents that write long drafts nobody needs remembered are cheaper with observeMe: false: their messages then count only what Recall reads of them. More in Cost and speed.

Privacy and forgetting

Agents pass on what users told them, so personal data ends up in agents' messages too. When a user asks to be forgotten, user.delete() erases their messages and every fact about them or from their view, including each agent's view of them. Facts about other peers that merely mention them stay: "the researcher found the user's budget is €20,000" is a fact about the researcher. Delete those by id, or delete the job's sessions. See Forget a person.

Do not let agents write credentials or tool output into messages. Webhook deliveries carry ids, not content. Recall stores data in Frankfurt; text is processed by AI model providers in the US through OpenRouter, restricted to providers that do not collect it, and never used for training. See Privacy, consent and forgetting and the DPA.

Pitfalls

Next: Coding agents · Designing workspaces, peers and sessions