Skip to main content
← All use cases

The scenario

A researcher agent gathers facts. A writer agent turns them into copy. They are separate agents with separate prompts, and each accumulates notes the other should never see — the writer’s drafting angles are not findings, and the researcher’s raw scraps are not a brief. The naive options are both bad. One space each means the writer cannot see what the researcher learned, so you end up passing findings through the orchestrator by hand. One space with no separation means every read returns both agents’ working notes mixed together, and quality degrades as the pile grows. What you want is one space, two working sets, and a handoff that costs nothing.

Step 1 — Each agent writes under its own scope

agent_id works like user_id, but it identifies the writer rather than the end user.

Step 2 — A scoped read is that agent’s working set

Returns the writer’s notes and nothing else. The researcher’s findings are in the same space and do not appear, because the read asked for one scope.

Step 3 — An unscoped read is the handoff

Returns everything the space knows, whoever wrote it. This is the whole mechanism — the writer’s prompt pulls the researcher’s findings without knowing who produced them, without an orchestrator passing state, and without a second API call to stitch two spaces together. Add a scope to narrow. Leave it off to hand off.

Evals

A handoff either carries the knowledge or it does not, and that is testable:
  1. Have agent A write three facts under agent_id="a", and agent B write two notes under agent_id="b".
  2. Read with agent_id="b" — assert none of A’s three come back.
  3. Read with no scope, asking A’s question — assert A’s facts come back.
  4. Grow B’s notes to fifty and repeat step 3. If A’s facts stop surfacing, the unscoped read is competing against B’s volume and the handoff needs a narrower query, not a bigger limit.
Step 4 is the one worth automating. A handoff that works on day one and degrades at scale is the failure mode this design is exposed to.

Guardrails

Scoping is not a security boundary between your own agents. Any caller holding the API key can read any scope in the space — the separation is about relevance, not access control. For a boundary that holds against a different organization, share the space and use per-space roles instead.
  • A scoped query is strict. Memories written before you adopted agent_id carry no scope, so a scoped read will never match them. Adopt scoping at the start of a space’s life, or backfill.
  • Unscoped writes stay unscoped. Calls without a scope key produce exactly the request they always did, so adding agent_id to one agent does not change what the other already stored.
  • Pick the right key for the job. agent_id identifies the writer, user_id the end user this is about, and session_id one run or conversation. They compose — a support agent serving many customers uses both agent_id and user_id. See Scoping Memory by User, Agent, or Session.
  • Observations consolidate per user, not per agent. Synthesis across an agent’s notes follows the user scope first. If you need per-agent synthesis, that is a memory model, not a scope.

The script

Complete and runnable: multi_agent_shared_space.py. See also One space, many end users for the same mechanism applied to end users rather than agents.