Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content
Concepts

Runs, sessions, and scopes

How run_id isolates memory, how sessions wrap runs, and how knowledge widens from run to session, global, and org scope.

Every piece of memory in Mubit belongs to a run, and every query names the run it's asking on behalf of. Read this page when you're designing how your agents partition memory — per ticket, per user, per agent — and how validated knowledge should escape those partitions. Getting scoping right up front is the difference between clean isolation and "why didn't my recall find it."

The mental model: runs isolate, scopes share. A run_id is a hard boundary — writes land in it, queries read from it. The scope ladder (run → session → global → org) is the controlled path by which individual entries earn visibility beyond their run.

Runs: the unit of isolation

A run is the memory scope for one unit of work. At Nimbus, Ari (the support agent) opens a fresh run per ticket — nimbus:ari:ticket-1042 — so evidence from one ticket never bleeds into another. Every write and every query carries the run id; two runs share nothing by default.

ℹ️Note

In the SDK helpers the kwarg is named session_id for historical reasons — remember(session_id="nimbus:ari:ticket-1042", ...) sends run_id on the wire. Whenever a helper asks for session_id, it means the run id.

Sessions: the lifecycle wrapper

A session is a lifecycle object that wraps a run — it tracks status, creation and close time, and ingest activity. Create one (client.advanced.create_session(...)) to get a server-managed run with auto-generated ids; close it (client.advanced.close_session(...)) when the work is done. Closing with reflect_on_close=True triggers a final reflection pass over the run, so lessons are extracted at the natural end of the work rather than on a timer.

Runs don't require sessions — you can use bare run ids everywhere — but sessions give you an explicit close moment, which is the right hook for end-of-task reflection. (Core branch sessions — reversible scratch forks — are a different primitive; see Sessions & branching.)

The scope ladder

Entries that carry a scope (lessons are the main case) are visible beyond their run according to a four-rung ladder. Wider scope also earns a retrieval-confidence bonus — broadly validated knowledge outranks single-run knowledge:

ScopeVisible toHow memory gets thereConfidence bonus
runOnly the writing runDirect write (the default)+0.00
sessionRelated runsDirect write (lesson_scope="session") or promotion+0.05
globalEvery run on the instanceDirect write (lesson_scope="global") or promotion+0.10
orgEvery instance in the tenantPromotion only — never a direct write+0.15

Promotion is recurrence-driven: a lesson that keeps re-emerging across runs becomes a candidate for the next rung. Two gates protect the wider scopes:

  • Shadow A/B validation. A candidate doesn't promote on recurrence alone — it auditions. Runs that would see it at the wider scope split deterministically into an exposed arm (lesson injected) and a control arm (withheld); outcomes accrue per arm, and the promotion only lands once each arm has enough samples and the exposed arm is doing no worse.
  • Distinct actors. Widening scope multiplies an entry's injection reach, so it requires outcome provenance from multiple distinct principals. A single agent reinforcing its own lesson cannot push it into shared scope — below the bar the lesson is quarantined until its provenance broadens.

This is how Nimbus's CSV-export lesson travels: Ari learns it in one ticket run, it recurs, survives its shadow audition, and eventually lands at org scope — where Sana (the analytics agent, on a different instance in the same tenant) picks it up while compiling the weekly digest, having never handled a ticket.

Run linking

Sometimes one run legitimately needs to read another — Rex (the reviewer agent) auditing Ari's work is the canonical case. Linking makes a run's memory reachable from another run without merging them; the reader opts in per query with include_linked_runs:

# Ari worked the ticket in its own run
client.remember(
    session_id="nimbus:ari:ticket-1042",   # run_id on the wire
    agent_id="ari",
    content="Export timed out at 500k rows; batched exporter resolved it",
    intent="observation",
)
 
# Rex reviews in a separate run, with Ari's run linked in
client.advanced.link_run(run_id="nimbus:rex:review-7", linked_run_id="nimbus:ari:ticket-1042")
evidence = client.recall(
    session_id="nimbus:rex:review-7",
    query="What did Ari already try for the CSV export timeout?",
    include_linked_runs=True,
)

reflect() accepts include_linked_runs too, so a review run can extract lessons from the combined history. Unlink with client.advanced.unlink_run(...) — see Run management.

Lanes: channels inside a shared run

When several agents share one run, lanes give each a named channel. Write with lane="planning" and queries filtered to that lane (lane= on recall(), lane_filter on the wire) see only planning-lane evidence — the planner's scratch reasoning stays out of the executor's context while shared, unlaned entries remain visible to all. Agents declare their lanes at registration (register_agent(..., shared_memory_lanes=[...])). See the lane-scoped memory recipe for a full walkthrough.

Pinning retrieval to the active run

Scope overlays mean a query can surface session- and global-scoped knowledge alongside run-local evidence. When you want the current task to dominate — mid-task, where this run's own recent evidence matters more than accumulated general knowledge — pass prefer_current_run=True on recall() to weight retrieval toward the active run.

Users: partitioning by end-user

user_id partitions memory per end-user, orthogonally to runs. Pass it on writes and queries and entries are scoped to that user across all their runs — Acme's preferences surface in every Acme conversation and never in another customer's. This is the standard mechanism for cross-session recall keyed to a person; see cross-session recall.

ℹ️Note

Configuration. Promotion gating is instance configuration: MUBIT_CL_SHADOW_PROMOTION (shadow validation, on by default), MUBIT_CL_SHADOW_MIN_PER_ARM (samples per arm before a decision), and MUBIT_CL_PROMOTION_MIN_ACTORS (distinct-principal bar for widening). Org scope additionally requires the instance to be configured with a tenant namespace.

Related