SDK methods
Three integration layers — from zero-config closed-loop to full low-level control.
MuBit SDKs expose three layers:
| Layer | What it does | When to use |
|---|---|---|
Learn (mubit.learn / learn) | Auto-ingest all LLM interactions + auto-inject lessons + auto-reflect | Zero-config closed-loop — agents learn with one line of setup |
Helpers on Client | 17 explicit methods for memory, context, reflection, multi-agent | Fine-grained control over what gets remembered and when |
Raw domains (auth, control, core) | 1:1 endpoint mappings | Wire debugging, async job polling, advanced routes |
Start with learn or helpers. Drop to raw domains only when you need exact payload control.
Learn module (closed-loop)
Before each LLM call, the learn module retrieves relevant lessons from MuBit and injects them into the system message. After the call, the interaction is ingested automatically. On run end, reflection extracts new lessons.
Helper method bundles
| Use case | Methods | What they do |
|---|---|---|
| Basic memory | remember, recall | Ingest content with intent classification; semantic query with evidence scoring |
| Prompt context | getContext / get_context | Token-budgeted context block for LLM injection (rules → lessons → facts) |
| Exact artifacts | archive, archiveBlock / archive_block, dereference | Bit-exact storage with stable reference IDs; retrieval without semantic search |
| Run lifecycle | checkpoint, reflect, recordOutcome / record_outcome, client.control.recordStepOutcome / record_step_outcome | Durable state; LLM lesson extraction; reinforcement feedback; per-step process rewards |
| Ingest lifecycle | client.control.getIngestJob / get_ingest_job, client.control.getRunIngestStats / get_run_ingest_stats | Poll async ingest jobs (details); per-run counters. remember() and ingest() return a job_id — call get_ingest_job(job_id) until done=True before reading the same run. |
| Multi-agent | registerAgent / register_agent, listAgents / list_agents, handoff, feedback | Scoped access per agent; task transfer |
| Diagnostics | memoryHealth / memory_health, diagnose, surfaceStrategies / surface_strategies, forget | Staleness metrics; error debugging; lesson clustering; deletion |
The learning loop
1. remember() → ingest facts, traces, lessons
2. record_step_outcome() → per-step process reward signals (optional, for dense RL)
3. reflect() → LLM extracts lessons from evidence
(recurring lessons promote: run → session → global)
4. get_context() → retrieve relevant lessons for the next call
5. record_outcome() → reinforce what worked at the run levelWith learn, steps 1–3 happen automatically. With helpers, you orchestrate them yourself.
Reflected lessons may start as pending candidates and only become active once enough evidence accrues — a lesson's score must cross the accept threshold (default 0.6) before it is surfaced in retrieval. Low-scoring candidates (≤0.25) are marked rejected and de-prioritized as stale. The control stream emits context.lesson_validation_passed / context.lesson_validation_failed alongside context.lesson_promoted. This validation gate is a server-side default; set MUBIT_CONTROL_LESSON_VALIDATION_ENABLED=false for the legacy "store immediately as active" behavior.
Current helper catalog
Step-level outcomes
Record per-step process rewards for dense RL signal within a run. Use after each agentic step, then reflect with the step outcomes folded in.
client.record_step_outcome(
step_id="tool_call_1",
step_name="search_api",
outcome="success",
signal=0.8,
rationale="Found the correct document on first try",
directive_hint="Keep using search before browsing",
)The Python reflect() helper only accepts session_id, include_linked_runs, user_id, and last_n_items — there is no include_step_outcomes kwarg. To fold step outcomes into reflection, set the include_step_outcomes field on the wire Reflect request (gRPC/HTTP), or call it from JS:
// Later: reflect with step outcomes included
await client.control.reflect({ run_id: "my-run", include_step_outcomes: true });Lane-scoped memory
Lanes partition memory within a shared run so each agent sees only relevant entries.
# Ingest into a specific lane
client.remember(content="Planning output: task A depends on B", intent="fact", lane="planning")
# Query only the planning lane
result = client.recall(query="task dependencies", lane="planning")
# Register an agent with lane participation
client.register_agent(agent_id="planner", role="planner", shared_memory_lanes=["planning", "shared"])lane (MAS memory isolation) is distinct from direct_lane (core data-plane retrieval routing). They serve different purposes and do not interact.
Step-wise reflection
Scope reflection to recent evidence for incremental lesson extraction.
# Reflect over only the 5 most recent items
client.reflect(last_n_items=5)To reflect with step outcomes included, use the wire include_step_outcomes field (gRPC/HTTP) or the JS control helper:
await client.control.reflect({ run_id: "my-run", include_step_outcomes: true });Auto-extraction in learn
Enable heuristic extraction of rules, lessons, and facts from LLM responses without an extra LLM call.
mubit.learn.init(
api_key="mbt_...",
agent_id="my-agent",
auto_extract=True, # extract structured items from LLM responses
extraction_mode="heuristic", # no LLM call needed
)When to use what
| Scenario | Use |
|---|---|
| Agents should learn with zero code | mubit.learn.init() (Python), learn.init() (JS), LearnSession::new() (Rust) |
| Passive trace capture only | mubit.auto.instrument() (Python only) |
| Control exactly what gets remembered | client.remember() + client.recall() |
| Token-budgeted context for prompts | client.get_context() / client.getContext() |
| Multiple agents with scoped access | client.register_agent() + client.handoff() |
| Bit-exact artifact storage | client.archive() + client.dereference() |
| Wire-level debugging | client.* / client.core.* |
When to use raw control methods directly
Use client.* when you need one of these explicitly:
control.ingestplusget_ingest_jobjob pollingcontrol.batch_insert- exact raw request/response debugging against HTTP or gRPC
- advanced or compatibility state-management routes
control.get_ingest_job,control.get_run_ingest_statsfor job pollingcontrol.list_run_history,control.link_run,control.unlink_run,control.delete_runfor run managementcontrol.context_snapshot/control.contextSnapshotfor full context snapshots
Ingest job tracking
remember() and the raw ingest() are asynchronous — they return a job_id and return immediately. If the next step in your code reads the same run (for example, recall() or get_context()), poll get_ingest_job(job_id) until done=True to guarantee the new item is visible. Framework adapters that advertise "synchronous put" semantics (e.g. MubitStore in mubit-langgraph) do this polling for you; the raw SDK does not.
Retrieve per-run statistics with get_run_ingest_stats() when you want aggregate counts without scanning activity.
For bulk writes, prefer one ingest({ items: [...] }) call with a list of items over many remember() calls — it is one job instead of N. Each ingest call accepts at most 1000 items; chunk larger workloads into multiple ingest calls (requests over the cap return 400 / InvalidArgument).
Run management
List run history, link, unlink, and delete runs. The server clamps the limit on run-history listing to a max of 1000 (default 100).
Context snapshot
Retrieve a full context snapshot for a run, including working memory, attention state, and active goals.
Temporal and quality features
Occurrence time
MuBit tracks two time dimensions for every memory entry: ingestion time (when the system learned it) and occurrence time (when the event actually happened). Set occurrence_time to record when an event happened, separate from when it was ingested.
Temporal queries
Use min_timestamp and max_timestamp to filter evidence to a specific time window. The filter checks occurrence_time first, falling back to ingestion time.
Without temporal bounds, queries like "What happened last week?" use natural language temporal intent detection and prioritize entries by occurrence time in the recency ranking.
Search budget
The budget parameter controls the depth of retrieval. Use "low" for real-time agents and "high" for accuracy-critical offline analysis.
| Budget | Behavior | Typical latency |
|---|---|---|
"low" | Fewer candidates, skip deep traversal | < 500ms |
"mid" | Standard retrieval (default) | 500ms–2s |
"high" | More candidates, deeper graph traversal | 1–5s |
Staleness detection
When a newer fact contradicts an older one, MuBit marks the older entry as stale and deprioritizes it in ranking. The staleness metadata is available in evidence responses.
Stale entries are still returned for transparency. The ranking penalty ensures they appear below the current fact. Filter them out in your application if you only want current information.
Mental models
The mental_model entry type stores consolidated entity summaries that are prioritized over raw facts in context assembly. Use this for entities your agent tracks over time.
Mental models are returned with higher priority than individual facts in recall() and get_context(). Update them periodically as your agent learns more about an entity.
Failure modes and troubleshooting
| Symptom | Root cause | Fix |
|---|---|---|
| SDK usage becomes inconsistent across teams | Raw and helper paths mixed arbitrarily | Set helpers as the default integration contract |
| Debugging a route contract is awkward | Helper layer hides wire details | Use the raw client.* call for that investigation |
| Docs and examples drift from SDK reality | Helpers undocumented | Treat the top-level helper surface as the public default |
Next steps
- See the concrete helper flow at Getting started.
- See the wire contract at Control HTTP reference.