Control HTTP API
Current public MuBit control-plane HTTP routes for memory, context, diagnostics, coordination, and explicit planning state.
This page documents the current public HTTP control surface. In application code, prefer the helper-first SDK methods where they exist and use these routes as wire-contract and debugging references.
Core memory routes
| Route | Method | Purpose | Recommended SDK surface |
|---|---|---|---|
/v2/control/ingest | POST | Async ingest for facts, traces, lessons, rules, WM, and other typed memory | remember() for normal writes, raw client.ingest(...) when you need job control |
/v2/control/batch_insert | POST | Compatibility bulk write path | raw client.batchInsert(...) / batch_insert(...) |
/v2/control/ingest/jobs/:job_id | GET | Ingest job status and completion | raw client.getIngestJob(...) / get_ingest_job(...) |
/v2/control/query | POST | Answer-oriented routed retrieval | recall() or raw client.query(...) |
/v2/control/context | POST | Pre-assembled context block with disclosure modes and budget control | getContext() / get_context() |
/v2/control/activity | POST | Chronological memory/activity browse surface with scope and type filters | HTTP / gRPC only — no SDK helper |
/v2/control/activity/export | POST | Export chronological memory/activity as JSONL | direct HTTP or operator export tooling |
/v2/control/archive | POST | Write an exact reusable artifact block and return a stable reference_id | archive() / archive_block() |
/v2/control/dereference | POST | Fetch exact stored content by reference_id | dereference() |
/v2/control/diagnose | POST | Failure-path lesson surfacing | diagnose() |
/v2/control/memory_health | POST | Memory quality, staleness, contradictions, and section health | memoryHealth() / memory_health() |
/v2/control/reflect | POST | Extract lessons and rules from run evidence | reflect() |
/v2/control/lessons | POST | List stored lessons for a run/session scope | raw client.lessons(...) |
/v2/control/lessons/delete | POST | Delete a stored lesson | forget() or raw lesson delete |
/v2/control/ingest and /v2/control/batch_insert accept at most 1000 items per request; larger requests return HTTP 400 (InvalidArgument). Chunk bigger writes client-side.
MAS and learning-loop routes
| Route | Method | Purpose | Recommended SDK surface |
|---|---|---|---|
/v2/control/agents | POST | List registered agents for the run | listAgents() / list_agents() |
/v2/control/agents/register | POST | Register an agent identity and its scopes | registerAgent() / register_agent() |
/v2/control/checkpoint | POST | Save a pre-compaction or pre-transition checkpoint | checkpoint() |
/v2/control/outcome | POST | Reinforce a lesson or rule after success/failure/partial outcome | recordOutcome() / record_outcome() |
/v2/control/step_outcome | POST | Record a per-step process reward signal within a run | recordStepOutcome() / record_step_outcome() |
/v2/control/strategies | POST | Surface repeated patterns from stored lessons and rules | surfaceStrategies() / surface_strategies() |
/v2/control/handoff | POST | Persist a coordination handoff between agents | handoff() |
/v2/control/feedback | POST | Persist a response to a handoff or review request | feedback() |
Explicit planning and state routes
The goals, actions, and decision-cycle routes are deprecated — track tasks in your orchestration framework (LangGraph, CrewAI) or a task system (Linear, Jira) and persist only the resulting lessons and outcomes in MuBit. The variables and concepts routes remain supported. All of these are HTTP/gRPC-only — none are exposed as typed SDK helpers. See State management.
| Route | Method | Purpose |
|---|---|---|
/v2/control/goals/add | POST | Add a goal |
/v2/control/goals/update | POST | Update a goal |
/v2/control/goals/list | POST | List goals |
/v2/control/goals/tree | POST | Retrieve the nested goal tree |
/v2/control/variables/set | POST | Set an explicit run-scoped variable |
/v2/control/variables/get | POST | Get a variable |
/v2/control/variables/list | POST | List variables |
/v2/control/variables/delete | POST | Delete a variable |
/v2/control/concepts/define | POST | Define a concept |
/v2/control/concepts/list | POST | List concepts |
/v2/control/actions/submit | POST | Record an action |
/v2/control/actions/log | POST | Read the action log |
/v2/control/cycles/run | POST | Record a reasoning / planning cycle |
/v2/control/cycles/history | POST | Read cycle history |
Run management and agent lifecycle routes
| Route | Method | Purpose | Recommended SDK surface |
|---|---|---|---|
/v2/control/runs | GET | List recent runs | client.control.listRunHistory(...) / client.advanced.list_run_history(...) |
/v2/control/runs/link | POST | Link a child run to a parent run | raw client.linkRun(...) / link_run(...) |
/v2/control/runs/unlink | POST | Unlink a previously linked run | raw client.unlinkRun(...) / unlink_run(...) |
/v2/control/delete_run | POST | Delete a run and its associated data | raw client.deleteRun(...) / delete_run(...) |
/v2/control/agents/heartbeat | POST | Agent liveness heartbeat signal | raw client.agentHeartbeat(...) / agent_heartbeat(...) |
/v2/control/activities/append | POST | Append an activity record to a run | HTTP / gRPC only — no SDK helper |
/v2/control/context/snapshot | POST | Full context snapshot including working memory and attention | client.control.contextSnapshot(...) / client.advanced.context_snapshot(...) |
/v2/control/events/subscribe | GET | Stream control events via SSE | raw client.subscribe(...) |
/v2/control/ingest/stats | POST | Get per-run ingest statistics | raw client.getRunIngestStats(...) / get_run_ingest_stats(...) |
Operating guidance
- Prefer helper methods for normal application code.
- Use raw route-level control when you need exact request-shape control, ingest-job polling, or contract debugging.
- Treat
/v2/control/contextas the default compaction-safe context assembly surface for long-running systems. - Treat
/v2/control/activityas the chronological audit surface for stored MuBit data. It is separate from semanticquery. - Use
/v2/control/archiveplus/v2/control/dereferencewhen later steps need exact artifact fidelity rather than only semantic discovery. - Use
diagnose,memory_health, andstrategiesbefore changing prompts blindly.
Temporal query parameters
POST /v2/control/query and POST /v2/control/context accept temporal filtering and budget control:
| Field | Type | Required | Description |
|---|---|---|---|
min_timestamp | int64 | no | Lower bound for temporal filter (unix seconds, inclusive). Filters by occurrence_time with created_at fallback. |
max_timestamp | int64 | no | Upper bound for temporal filter (unix seconds, inclusive). |
budget | string | no | Search budget tier: "low", "mid" (default), "high". Controls latency/quality tradeoff. |
Staleness fields in query evidence
Evidence items in query and context responses may include staleness metadata:
| Field | Type | Description |
|---|---|---|
is_stale | bool | Whether this entry has been superseded by a newer version |
superseded_by | string | ID of the superseding entry (empty if not stale) |
Stale entries are returned with a ranking penalty. Filter them in your application if you only want current information.
Occurrence time on ingest
POST /v2/control/ingest items accept an occurrence time field:
| Field | Type | Required | Description |
|---|---|---|---|
occurrence_time | int64 | no | When the event actually occurred (unix seconds). Distinct from ingestion time. Used for temporal queries and recency ranking. |
Evidence provenance and context pressure
/v2/control/query and /v2/control/context now expose reuse provenance on surfaced evidence:
retrieval_mode:semantic,exact_reference,checkpoint,rule_overlay,lesson_overlay, orworking_memoryreference_id: stable exact-reference ID when availablereferenceable: whether the source can be dereferenced laterorigin_entry_type: typed LTM source such asfact,lesson,rule,archive_block, orcheckpoint
The /v2/control/query response also includes a citations array — 0-based indices into evidence marking which items grounded final_answer (empty when the answer cites no specific evidence or was an abstention). Indices are validated server-side against the evidence length, so every value is a valid index into evidence. Use them to render citations or audit answer grounding.
/v2/control/context also reports context-pressure telemetry:
- requested token budget
budget_usedbudget_remaining- source counts by entry type
- source counts by retrieval mode
evidence_candidates_consideredevidence_dropped_by_budgetexact_references_surfaced
Run-level outcome request shape
POST /v2/control/outcome reinforces a lesson or rule after a success/failure/partial outcome. Beyond the core fields (reference_id, outcome, signal, rationale, agent_id, user_id, verified_in_production), the wire request accepts two attribution fields:
| Field | Type | Required | Description |
|---|---|---|---|
entry_ids | string[] | no | Additional contributing memory entry IDs for multi-entry attribution. Each is resolved within the run and scope-checked; unknown or out-of-scope IDs are skipped. The primary reference_id is never double-counted if it also appears here |
idempotency_key | string | no | Client-supplied dedup token. When set, the outcome is applied at most once for the token — a retry with the same key (e.g. after a transport timeout) returns success WITHOUT re-applying the signal, so reinforcement counts aren't double-counted. A wire-level field; it is not exposed on the record_outcome() SDK helper |
Step-level outcome request shape
POST /v2/control/step_outcome records a per-step process reward signal, complementing the run-level /v2/control/outcome.
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Session/run identifier |
step_id | string | yes | Unique step identifier within the run |
step_name | string | no | Human-readable step label |
outcome | string | yes | One of success, failure, partial, neutral |
signal | float | no | Reward signal from -1.0 to 1.0 |
rationale | string | no | Why this outcome was assigned |
directive_hint | string | no | Hindsight guidance for future runs |
agent_id | string | no | Agent that performed the step |
user_id | string | no | Logical user scope |
metadata_json | string | no | Arbitrary JSON metadata |
Response: { "step_outcome_id": "...", "accepted": true }.
Use after each agentic step where you want dense reward signal. To produce step-attributed lessons, set include_step_outcomes on the reflect request. This is a wire-level ReflectRequest field (not a kwarg on the Python reflect() helper): send it via the raw control surface, e.g. client.advanced.reflect({"run_id": ..., "include_step_outcomes": True}) (Python) or client.control.reflect({ run_id, include_step_outcomes: true }) (JS).
Lane parameters
Lanes partition memory within a shared run for multi-agent isolation.
| Route | Field | Description |
|---|---|---|
/v2/control/ingest | lane (on each item) | Tags ingested items with a named lane |
/v2/control/query | lane_filter | Retrieves only entries tagged with the specified lane |
/v2/control/context | lane_filter | Filters context assembly by lane |
/v2/control/agents/register | shared_memory_lanes | Declares which lanes an agent participates in |
Items without a lane are visible to all queries. Items with a lane are visible only when lane_filter matches or is empty.
lane (MAS memory isolation) is distinct from the core data-plane retrieval lane concept used in direct search routing. See Core Direct Lanes for the data-plane concept.
Step-wise reflection parameters
POST /v2/control/reflect now accepts additional fields for targeted reflection:
| Field | Type | Description |
|---|---|---|
step_id | string | Scope reflection to a specific step |
last_n_items | int32 | Reflect only over the N most recent evidence items |
include_step_outcomes | bool | Include recorded step outcomes as reflection input |
These compose with existing fields (run_id, checkpoint_id). Use last_n_items for incremental after-each-step reflection, and include_step_outcomes when step reward signals should influence lesson extraction.
Activity routes request shapes
POST /v2/control/activity
List chronological memory/activity entries.
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | no | Session/run scope. When empty, lists activity across runs visible to the actor |
user_id | string | no | Logical user scope |
agent_id | string | no | Filter by agent |
entry_types | string[] | no | Filter by entry type (e.g. ["fact", "lesson"]) |
created_after | string | no | Inclusive lower-bound timestamp (RFC3339) |
created_before | string | no | Inclusive upper-bound timestamp (RFC3339) |
sort | string | no | "desc" (default, newest first) or "asc" |
limit | uint32 | no | Page size. Defaults to 100 and is clamped to [1, 500] — an omitted or 0 limit resolves to 1, not 100 |
page_token | string | no | Opaque pagination cursor returned as next_page_token from the previous page (currently a numeric offset string) |
exclude_derived | bool | no | When true, exclude promoted/derived facts from the listing |
projection | string | no | "full" (default) or "compact" (truncates content to 200 chars and strips verbose metadata) |
Response: { "entries": [...], "next_page_token": "...", "total_visible": int }. next_page_token is empty when the last page has been reached.
POST /v2/control/activity/export
Export activity as JSONL.
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Session/run identifier |
format | string | no | Export format, default "jsonl" |
entry_types | string[] | no | Filter by entry type |
Response: JSONL stream of activity entries.
POST /v2/control/activities/append
Append manual activity traces.
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Session/run identifier |
entries | object[] | yes | Activity entries to append |
entries[].type | string | yes | Entry type (e.g. "observation", "action") |
entries[].content | string | yes | Entry content |
agent_id | string | no | Agent that produced the entries |
Response: { "appended": int }.
Run management request shapes
POST /v2/control/runs/link
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Parent run identifier |
linked_run_id | string | yes | Child run to link |
Response: { "linked": true }.
POST /v2/control/runs/unlink
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Parent run identifier |
linked_run_id | string | yes | Child run to unlink |
Response: { "unlinked": true }.
POST /v2/control/delete_run
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Run to delete |
Response: { "deleted": true }.
POST /v2/control/context/snapshot
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Session/run identifier |
include_working_memory | bool | no | Include working memory state |
include_goals | bool | no | Include active goals |
Response: { "snapshot": { "working_memory": {...}, "attention": {...}, "goals": [...] } }.
POST /v2/control/ingest/stats
| Field | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | Session/run identifier |
Response: { "total_ingested": int, "by_type": {...}, "last_ingest_at": string }.
GET /v2/control/ingest/jobs/:job_id
No request body. Returns:
| Field | Type | Description |
|---|---|---|
job_id | string | Job identifier |
status | string | One of pending, processing, completed, failed |
items_total | int | Total items in the job |
items_processed | int | Items processed so far |
created_at | string | ISO timestamp |
completed_at | string | ISO timestamp (if completed) |
Managed resources: Projects, Agents, Skills, Prompts
Managed MuBit deployments expose a resource model so you can configure agents declaratively instead of re-encoding them in every run. Projects group related agents, each agent owns a versioned system prompt and a set of skills (tools/playbooks), and all of it is versioned with a candidate → active promotion flow.
Project CRUD
| Route | Method | Purpose | Recommended SDK surface |
|---|---|---|---|
/v2/control/projects | POST | Create a project | client.createProject(...) / create_project(...) |
/v2/control/projects/list | POST | List projects | client.listProjects(...) / list_projects(...) |
/v2/control/projects/get | POST | Get a single project | client.getProject(...) / get_project(...) |
/v2/control/projects/update | POST | Rename / describe | client.updateProject(...) / update_project(...) |
/v2/control/projects/delete | POST | Delete a project | client.deleteProject(...) / delete_project(...) |
POST /v2/control/projects request:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Project name (shown in the console) |
description | string | no | Short description |
Response: { "project": { "project_id": "proj-...", "name": "...", "description": "...", "agent_ids": [], "created_at": "...", "updated_at": "..." } }.
Agent Definition CRUD
Agents belong to a project and own a role, description, and active system prompt.
| Route | Method | Purpose |
|---|---|---|
/v2/control/projects/agents | POST | Create agent definition |
/v2/control/projects/agents/list | POST | List agents in a project |
/v2/control/projects/agents/get | POST | Get a single agent |
/v2/control/projects/agents/update | POST | Update role / description / prompt |
/v2/control/projects/agents/delete | POST | Delete an agent |
POST /v2/control/projects/agents request:
| Field | Type | Required | Description |
|---|---|---|---|
project_id | string | yes | Owning project |
agent_id | string | yes | Stable agent identifier |
role | string | no | Short role description |
description | string | no | Longer description |
system_prompt_content | string | no | Initial prompt — creates the first active PromptVersion |
Run history for a project
| Route | Method | Purpose |
|---|---|---|
/v2/control/projects/runs | POST | List run history for a project |
/v2/control/projects/runs/get | POST | Get a specific run history record |
Run history records expose lessons_extracted, prompt_changes, avg_outcome_score, outcome_count, and ingest_count per run — so you can observe how an agent's behavior evolves.
Prompt versioning + optimization
Every agent has at most one active PromptVersion and zero or more candidate PromptVersions awaiting approval. The control plane can mint candidates automatically via optimize_prompt.
| Route | Method | Purpose |
|---|---|---|
/v2/control/prompt/set | POST | Write a new version (activate=true promotes immediately) |
/v2/control/prompt/get | POST | Get the current active prompt |
/v2/control/prompt/versions | POST | List all versions for an agent |
/v2/control/prompt/activate | POST | Promote a candidate to active |
/v2/control/prompt/optimize | POST | LLM-powered candidate generation from recent outcomes |
/v2/control/prompt/diff | POST | Diff two versions (returns unified diff_text) |
Version statuses: active, candidate, retired, archived. Sources: manual, optimization, rollback.
POST /v2/control/prompt/optimize request:
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string | yes | Agent whose prompt is being optimized |
project_id | string | yes | Containing project |
llm_override | object | no | { provider, model, temperature, max_tokens, timeout_ms }. timeout_ms is clamped server-side to [1000, 600000] ms (10 min); out-of-range values are silently adjusted |
Response: { success, candidate, optimization_summary, confidence, activated }.
Skill CRUD + optimization
Skills are named tools or playbooks attached to a project (or optionally to a specific agent). They version identically to prompts.
| Route | Method | Purpose |
|---|---|---|
/v2/control/skills | POST | Create skill |
/v2/control/skills/list | POST | List skills |
/v2/control/skills/get | POST | Get a skill |
/v2/control/skills/update | POST | Update definition |
/v2/control/skills/delete | POST | Delete a skill |
/v2/control/skills/versions | POST | List versions |
/v2/control/skills/activate | POST | Promote a candidate skill version |
/v2/control/skills/optimize | POST | Generate a candidate skill version from recent outcomes |
/v2/control/skills/diff | POST | Diff two skill versions |
POST /v2/control/skills request:
| Field | Type | Required | Description |
|---|---|---|---|
project_id | string | yes | Owning project |
agent_id | string | no | If set, attaches the skill to a specific agent |
name | string | yes | Skill name |
description | string | no | Short description |
parameters_schema | string | no | JSON schema describing parameters |
instructions | string | no | Instructions/playbook text |
skill_type | string | no | "tool" (default) or "playbook" |
Control sessions
Sessions are long-lived handles the control plane uses to coordinate multi-turn agent work. In typical SDK usage, run_id serves the same purpose; sessions are exposed for tools that need explicit lifecycle control.
| Route | Method | Purpose |
|---|---|---|
/v2/control/sessions/create | POST | Create a control session |
/v2/control/sessions/get | POST | Fetch session state (phase, ingest count, last activity) |
/v2/control/sessions/close | POST | Close a session |
Platform health endpoints
These unauthenticated routes live at the root of each MuBit node (alongside /v2/core/* and /v2/control/*). Use them for Kubernetes probes, load-balancer checks, and operational monitoring — not from application code.
| Route | Method | Purpose | Typical use |
|---|---|---|---|
/livez | GET | Liveness: the process is running and its HTTP stack is responsive. Always returns 200 while the server accepts connections. | Kubernetes livenessProbe; triggers pod restart on failure. Keep the threshold forgiving — a busy node should not be killed. |
/readyz | GET | Readiness: the node is ready to serve real traffic. Returns 503 while background ACL and sparse-index rebuilds are still running (reads would see stale state in that window). | Kubernetes readinessProbe and load-balancer health check; a 503 temporarily removes the node from rotation without restarting it. |
/v2/core/health | GET | Coarse legacy health probe. Unauthenticated. Returns the literal string "OK" when the HTTP layer is up. | External checks that only need "is the endpoint reachable". Prefer /livez + /readyz for K8s. |
/metrics | GET | Prometheus scrape endpoint — includes mubit_llm_calls_total, mubit_llm_tokens_total, mubit_llm_call_duration_seconds, storage and ingest counters. | Prometheus / Grafana scraping. |
GET /livez
Response: 200 OK with body ok.
Liveness is intentionally cheap. It does not query storage, Redis, or any downstream dependency — that is the job of /readyz. A failing /livez means the process is wedged and should be restarted.
GET /readyz
Responses:
- Ready:
200 OK{ "status": "ready" } - Not ready:
503 Service Unavailable{ "status": "not_ready", "reason": "acl_rebuild_in_progress" }
The node flips to ready once the initial ACL warmup, sparse-index prewarm, and partitioned sparse prewarm complete. During that window, the process accepts connections (so /livez stays 200) but returns 503 from /readyz so the load balancer can route around it.
Typical reason values: starting, acl_rebuild_in_progress, sparse_prewarm_in_progress. Treat reason as a diagnostic hint — it is advisory, not API-stable.
The platform-api service (which fronts the console and the managed-instance API) exposes its own /healthz on port 8080. That is a separate surface from the data-plane /livez//readyz probes above, which sit on each instance's port 3000.
Next steps
- Compare the proto surface at Control gRPC reference.
- Review explicit planning routes at State management endpoints.