Skip to main content
Authentication is by Authorization-header API token validated against team policy (per-user and per-org rate limits are enforced at ingress, and prompt text is redacted for obvious secrets/PII before queueing). The web frontend reaches these endpoints through its own BFF, which resolves the user’s session and budget/ownership checks against the Auth service — see Mother AI for the service’s own story.

Endpoints

Grouped by area; paths relative to the Mother AI origin.

Jobs

Workflows & prompts

Projects, capabilities, work

Approvals

Models & catalog

Slack, knowledge, misc

The SSE stream

GET /v1/jobs/:id/stream replays the durable backlog (the job’s event list in Redis) before joining the live pub/sub channel, and stays open until the job finishes or errors. The invariant: a reconnecting client never misses an event — replay first, then live, with monotonic sequence numbers to detect gaps.

The AgentEvent envelope

Every event is JSON with a discriminated kind:
Consumers must tolerate unknown kinds (render a generic timeline row) — the catalog grows. Canonical definitions: worker/worker/runtime/agent_messages.py (Python) mirrored by apps/frontend/lib/types/agent-event.ts (TypeScript).

Kind catalog

Payload contracts worth knowing

  • routing_decision — emitted per level during scenario runs (level_id, provider, model, tier, model_candidates). model is the intended model and may be "" (nothing pinned). The legacy job-level variant from the pre-scenario orchestrator carries no level_id; consumers must not attribute it to a level.
  • level_finished — ok, attempt, duration_ms, cost_usd, output_preview, optional verdict. Its optional provider/model name the model that actually answered, and are present only for levels that made an LLM call. Absence is the contract: gates, verifiers, and aggregators omit both, which is what lets the canvas keep a role glyph instead of painting a brand mark on a level that never talked to a provider. Do not default the field. A prompt level that was composed in code sets deterministic: true — a third state, distinct from both “model present” and a gate’s silent absence.
  • model_fallback — dispatch walked the band and a later candidate answered (from_model, to_model, to_provider, reason). It corrects the intended model a routing_decision already reported for the same level, live, instead of waiting for level_finished.
  • provider_fallback — the coarser, older signal: a level rerouted from paid to free transport entirely.
  • ask_user vs approval_requested — ask_user drives the inline question panel on the live stream and pauses the graph on an interrupt (resumable via POST /v1/jobs/:id/resume). approval_requested means a durable approvals row exists, so the decision can also land from Slack or the approvals page; both are addressable by call_id/approval_id.
  • scenario_chained — ScenarioOrchestrator re-dispatched the same job to a follow-up scenario (e.g. intent classification → QA); the next scenario_started arrives right after.
  • final — terminal, with agent_message, summary, and cumulative created_files; error is the other terminal kind and carries retryable.