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

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

RouteMethodPurposeRecommended SDK surface
/v2/control/ingestPOSTAsync ingest for facts, traces, lessons, rules, WM, and other typed memoryclient.memory.remember() for normal writes, client.raw.invoke("control.ingest", ...) when you need job control
/v2/control/batch_insertPOSTCompatibility bulk write pathclient.raw.invoke("control.batch_insert", ...)
/v2/control/ingest/jobs/:job_idGETIngest job status and completionclient.jobs.get(job_id, run_id=...) (an IngestJob: done, status, error)
/v2/control/queryPOSTAnswer-oriented routed retrievalclient.memory.recall() or client.raw.invoke("control.query", ...)
/v2/control/contextPOSTPre-assembled context block with disclosure modes and budget controlclient.memory.context(task, lane="legacy", ...)
/v2/control/activityPOSTChronological memory/activity browse surface with scope and type filtersclient.audit.run_history()
/v2/control/activity/exportPOSTExport chronological memory/activity as JSONLdirect HTTP or operator export tooling
/v2/control/archivePOSTWrite an exact reusable artifact block and return a stable reference_idclient.memory.archive()
/v2/control/dereferencePOSTFetch exact stored content by reference_idclient.memory.dereference()
/v2/control/diagnosePOSTFailure-path lesson surfacingclient.memory.diagnose()
/v2/control/memory_healthPOSTMemory quality, staleness, contradictions, and section healthclient.memory.health()
/v2/control/reflectPOSTExtract lessons and rules from run evidenceclient.lessons.reflect()
/v2/control/lessonsPOSTList stored lessons for a run/session scopeclient.lessons.transitions(run_id=...); the lesson set is client.lessons.list() (/v2/loop/lessons)
/v2/control/lessons/deletePOSTDelete a stored lessonclient.memory.forget() / client.lessons.delete()
/v2/control/lessons/resolve_promotionPOSTAccept or refuse a lesson's pending scope promotion (proposed / auditioning / quarantined)client.raw.invoke("control.resolve_lesson_promotion", ...)
/v2/control/lessons/updatePOSTSet a lesson's scope, validation_status, stale, or confidence (absolute, clamped to [0, 1]) directly (audited on the entry)client.raw.invoke("control.update_lesson", ...)
ℹ️Note

/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

RouteMethodPurposeRecommended SDK surface
/v2/control/agentsPOSTList registered agents for the runclient.agents.list()
/v2/control/agents/registerPOSTRegister an agent identity and its scopesclient.agents.register()
/v2/control/checkpointPOSTSave a pre-compaction or pre-transition checkpointclient.checkpoint()
/v2/control/outcomePOSTReinforce a lesson or rule after success/failure/partial outcomeclient.outcomes.record(); mubit.outcome() for the current run
/v2/control/step_outcomePOSTRecord a per-step process reward signal within a runclient.runs.steps.record(); step.outcome() inside mubit.step()
/v2/control/strategiesPOSTSurface repeated patterns from stored lessons and rulesclient.lessons.strategies()
/v2/control/handoffPOSTPersist a coordination handoff between agentsclient.agents.handoffs.create()
/v2/control/feedbackPOSTPersist a response to a handoff or review requestclient.agents.handoffs.feedback()

Explicit planning and state routes

⚠️Warning

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.

RouteMethodPurpose
/v2/control/goals/addPOSTAdd a goal
/v2/control/goals/updatePOSTUpdate a goal
/v2/control/goals/listPOSTList goals
/v2/control/goals/treePOSTRetrieve the nested goal tree
/v2/control/variables/setPOSTSet an explicit run-scoped variable
/v2/control/variables/getPOSTGet a variable
/v2/control/variables/listPOSTList variables
/v2/control/variables/deletePOSTDelete a variable
/v2/control/concepts/definePOSTDefine a concept
/v2/control/concepts/listPOSTList concepts
/v2/control/actions/submitPOSTRecord an action
/v2/control/actions/logPOSTRead the action log
/v2/control/cycles/runPOSTRecord a reasoning / planning cycle
/v2/control/cycles/historyPOSTRead cycle history

Run management and agent lifecycle routes

RouteMethodPurposeRecommended SDK surface
/v2/control/runsGETList recent runsclient.runs.history(...)
/v2/control/runs/linkPOSTLink a child run to a parent runclient.runs.link(...)
/v2/control/runs/unlinkPOSTUnlink a previously linked runclient.runs.unlink(...)
/v2/control/delete_runPOSTDelete a run and its associated dataclient.runs.delete(run_id)
/v2/control/agents/heartbeatPOSTAgent liveness heartbeat signalclient.raw.invoke("control.agent_heartbeat", ...)
/v2/control/activities/appendPOSTAppend an activity record to a runHTTP / gRPC only — no SDK helper
/v2/control/context/snapshotPOSTFull context snapshot including working memory and attentionclient.raw.invoke("control.context_snapshot", ...)
/v2/control/events/subscribeGETStream control events via SSE; empty/absent run_id = every run the actor ownsclient.audit.subscribe(...)
/v2/control/ingest/statsPOSTGet per-run ingest statisticsclient.raw.invoke("control.get_run_ingest_stats", ...)

Operating guidance

  • Prefer the Client namespaces (and the global helpers inside a run) for normal application code.
  • Use client.raw.invoke(op, payload) when you need exact request-shape control, ingest-job polling, or contract debugging; op is the contract name (control.<route>).
  • Treat /v2/control/context as the default compaction-safe context assembly surface for long-running systems.
  • Treat /v2/control/activity as the chronological audit surface for stored Mubit data. It is separate from semantic query.
  • Use /v2/control/archive plus /v2/control/dereference when later steps need exact artifact fidelity rather than only semantic discovery.
  • Use client.memory.diagnose, client.memory.health, and client.lessons.strategies before changing prompts blindly.

Temporal query parameters

POST /v2/control/query and POST /v2/control/context accept temporal filtering and budget control:

FieldTypeRequiredDescription
min_timestampint64noLower bound for temporal filter (unix seconds, inclusive). Filters by occurrence_time with created_at fallback.
max_timestampint64noUpper bound for temporal filter (unix seconds, inclusive).
budgetstringnoSearch 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:

FieldTypeDescription
is_staleboolWhether this entry has been superseded by a newer version
superseded_bystringID 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:

FieldTypeRequiredDescription
occurrence_timeint64noWhen 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, or working_memory
  • reference_id: stable exact-reference ID when available
  • referenceable: whether the source can be dereferenced later
  • origin_entry_type: typed LTM source such as fact, lesson, rule, archive_block, or checkpoint

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_used
  • budget_remaining
  • source counts by entry type
  • source counts by retrieval mode
  • evidence_candidates_considered
  • evidence_dropped_by_budget
  • exact_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:

FieldTypeRequiredDescription
entry_idsstring[]noAdditional 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_keystringnoClient-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 client.outcomes.record()

Step-level outcome request shape

POST /v2/control/step_outcome records a per-step process reward signal, complementing the run-level /v2/control/outcome.

FieldTypeRequiredDescription
run_idstringyesSession/run identifier
step_idstringyesUnique step identifier within the run
step_namestringnoHuman-readable step label
outcomestringyesOne of success, failure, partial, neutral
signalfloatnoReward signal from -1.0 to 1.0
rationalestringnoWhy this outcome was assigned
directive_hintstringnoHindsight guidance for future runs
agent_idstringnoAgent that performed the step
user_idstringnoLogical user scope
metadata_jsonstringnoArbitrary 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 client.lessons.reflect()): send it through the raw operation, e.g. client.raw.invoke("control.reflect", {"run_id": ..., "include_step_outcomes": True}) (Python) or client.raw.invoke("control.reflect", { run_id, include_step_outcomes: true }) (JS).

Lane parameters

Lanes partition memory within a shared run for multi-agent isolation.

RouteFieldDescription
/v2/control/ingestlane (on each item)Tags ingested items with a named lane
/v2/control/querylane_filterRetrieves only entries tagged with the specified lane
/v2/control/contextlane_filterFilters context assembly by lane
/v2/control/agents/registershared_memory_lanesDeclares 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.

ℹ️Note

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:

FieldTypeDescription
step_idstringScope reflection to a specific step
last_n_itemsint32Reflect only over the N most recent evidence items
include_step_outcomesboolInclude recorded step outcomes as reflection input
lessonsReflectLesson[]Bring-your-own extractor: when non-empty, skip the built-in reflection agent and run the validation gate, persistence, promotion ladder and events over these lessons instead. Same shape as the response lessons (content, lesson_type, scope, importance, conditions, rationale); lesson_id is ignored. Empty lesson_type/scope/importance default to observation/run/medium; unknown values are rejected
confidencefloatBatch confidence the validation gate scores lessons with, clamped to [0,1]; absent = 1.0. Only read when lessons is non-empty

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. Use lessons when your own agent already extracted the lessons and you want them gated, stored and promoted exactly as reflected ones are — the response decisions are the same, and stored rows carry auto_extracted: false.

Activity routes request shapes

POST /v2/control/activity

List chronological memory/activity entries.

FieldTypeRequiredDescription
run_idstringnoSession/run scope. When empty, lists activity across runs visible to the actor
user_idstringnoLogical user scope
agent_idstringnoFilter by agent
entry_typesstring[]noFilter by entry type (e.g. ["fact", "lesson"])
created_afterstringnoInclusive lower-bound timestamp (RFC3339)
created_beforestringnoInclusive upper-bound timestamp (RFC3339)
sortstringno"desc" (default, newest first) or "asc"
limituint32noPage size. Defaults to 100 and is clamped to [1, 500] — an omitted or 0 limit resolves to 1, not 100
page_tokenstringnoOpaque pagination cursor returned as next_page_token from the previous page (currently a numeric offset string)
exclude_derivedboolnoWhen true, exclude promoted/derived facts from the listing
projectionstringno"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. The request takes the same filter fields as the browse call — there is no format request field; the response is always JSONL.

FieldTypeRequiredDescription
run_idstringnoRun scope (same filter semantics as /v2/control/activity)
user_idstringnoLogical user scope
agent_idstringnoFilter by agent
entry_typesstring[]noFilter by entry type
created_after / created_beforestringnoInclusive RFC3339 bounds
sortstringno"desc" (default) or "asc"

Response: { "format": "jsonl", "content": "<serialized entries>", "entry_count": int }.

POST /v2/control/activities/append

Append a manual activity trace. Each request appends a single activity record — issue one request per record.

FieldTypeRequiredDescription
run_idstringyesRun identifier
agent_idstringnoAgent that produced the record
activityobjectyesThe activity record to append
activity.typestringyesRecord type (e.g. "observation", "action")
activity.payloadstringyesRecord content
activity.tool_name / activity.input_ref / activity.output_ref / activity.tsstringnoOptional provenance fields

Response: { "success": true, "event_id": "evt_..." }.

Run management request shapes

POST /v2/control/runs/link

FieldTypeRequiredDescription
run_idstringyesParent run identifier
linked_run_idstringyesChild run to link

Response: { "linked": true }.

POST /v2/control/runs/unlink

FieldTypeRequiredDescription
run_idstringyesParent run identifier
linked_run_idstringyesChild run to unlink

Response: { "unlinked": true }.

POST /v2/control/delete_run

FieldTypeRequiredDescription
run_idstringyesRun to delete

Response: { "deleted": true }.

POST /v2/control/context/snapshot

FieldTypeRequiredDescription
run_idstringyesSession/run identifier
include_working_memoryboolnoInclude working memory state
include_goalsboolnoInclude active goals

Response: { "snapshot": { "working_memory": {...}, "attention": {...}, "goals": [...] } }.

POST /v2/control/ingest/stats

FieldTypeRequiredDescription
run_idstringyesSession/run identifier

Response: { "total_ingested": int, "by_type": {...}, "last_ingest_at": string }.

GET /v2/control/ingest/jobs/:job_id

No request body. Returns:

FieldTypeDescription
job_idstringJob identifier
run_idstringRun the job belongs to
statusstringOne of queued, running, completed, failed
doneboolTrue once the job reached a terminal state — poll on this
errorstringError message when status == "failed"
created_at / started_at / finished_atstringISO timestamps for the job lifecycle

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

RouteMethodPurposeRecommended SDK surface
/v2/control/projectsPOSTCreate a projectclient.projects.create(...)
/v2/control/projects/listPOSTList projectsclient.projects.list(...)
/v2/control/projects/getPOSTGet a single projectclient.projects.get(...)
/v2/control/projects/updatePOSTRename / describeclient.projects.update(...)
/v2/control/projects/deletePOSTDelete a projectclient.projects.delete(...)

POST /v2/control/projects request:

FieldTypeRequiredDescription
namestringyesProject name (shown in the console)
descriptionstringnoShort 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.

RouteMethodPurpose
/v2/control/projects/agentsPOSTCreate agent definition
/v2/control/projects/agents/listPOSTList agents in a project
/v2/control/projects/agents/getPOSTGet a single agent
/v2/control/projects/agents/updatePOSTUpdate role / description / prompt
/v2/control/projects/agents/deletePOSTDelete an agent

POST /v2/control/projects/agents request:

FieldTypeRequiredDescription
project_idstringyesOwning project
agent_idstringyesStable agent identifier
rolestringnoShort role description
descriptionstringnoLonger description
system_prompt_contentstringnoInitial prompt — creates the first active PromptVersion

Run history for a project

RouteMethodPurpose
/v2/control/projects/runsPOSTList run history for a project
/v2/control/projects/runs/getPOSTGet 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.

RouteMethodPurpose
/v2/control/prompt/setPOSTWrite a new version (activate=true promotes immediately)
/v2/control/prompt/getPOSTGet the current active prompt
/v2/control/prompt/versionsPOSTList all versions for an agent
/v2/control/prompt/activatePOSTPromote a candidate to active
/v2/control/prompt/optimizePOSTLLM-powered candidate generation from recent outcomes
/v2/control/prompt/diffPOSTDiff two versions (returns unified diff_text)

Version statuses: active, candidate, retired, archived. Sources: manual, optimization, rollback.

POST /v2/control/prompt/optimize request:

FieldTypeRequiredDescription
agent_idstringyesAgent whose prompt is being optimized
project_idstringyesContaining project
llm_overrideobjectno{ 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.

RouteMethodPurpose
/v2/control/skillsPOSTCreate skill
/v2/control/skills/listPOSTList skills
/v2/control/skills/getPOSTGet a skill
/v2/control/skills/updatePOSTUpdate definition
/v2/control/skills/deletePOSTDelete a skill
/v2/control/skills/versionsPOSTList versions
/v2/control/skills/activatePOSTPromote a candidate skill version
/v2/control/skills/optimizePOSTGenerate a candidate skill version from recent outcomes
/v2/control/skills/diffPOSTDiff two skill versions

POST /v2/control/skills request:

FieldTypeRequiredDescription
project_idstringyesOwning project
agent_idstringnoIf set, attaches the skill to a specific agent
namestringyesSkill name
descriptionstringnoShort description
parameters_schemastringnoJSON schema describing parameters
instructionsstringnoInstructions/playbook text
skill_typestringno"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.

RouteMethodPurpose
/v2/control/sessions/createPOSTCreate a control session
/v2/control/sessions/getPOSTFetch session state (phase, ingest count, last activity)
/v2/control/sessions/closePOSTClose 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.

RouteMethodPurposeTypical use
/livezGETLiveness: 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.
/readyzGETReadiness: 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/healthGETCoarse 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.
/metricsGETPrometheus 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.

ℹ️Note

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