Govern & operate
Analytics
Two views built on the same telemetry: workspace-level cost analytics at /analytics, and per-run swarm observability that replays a swarm execution node by node.
Cost analytics
The analytics page leads with four numbers — month-to-date spend, total tokens, average latency, and active agents — followed by:
- Spend over time — your daily spend charted over the selected window. Spikes are worth chasing the same day; they are usually one experiment, one loop, or one oversized context.
- Cost by provider — where the money goes across AgentSwarms AI, OpenAI, Anthropic, and any bring-your-own-key providers you've connected.
- Cost by agent — almost always the chart with the surprise in it: one agent on one expensive model tends to dominate.
Spend caps and alerts live in Budgets; per-run detail lives in traces.
These are estimates, and they can be undercounts
The sharper caveat: a model the price table does not know is recorded at zero, and zero is indistinguishable from cheap once it reaches a chart. Those calls are marked
pricing_missing on the trace, and calls whose token counts were estimated rather than reported by the provider are marked tokens_estimated — so a total that looks too low can be checked rather than guessed at. See how cost is computed.Tracing a spend spike
The charts above tell you that something changed. This is the path from there to the specific cause, in the order that narrows fastest — each step cuts the search space rather than adding detail.
- 1
Find the day on Spend over time
A step change and a spike mean different things. A spike is usually one experiment or one runaway loop and is over. A step up that never comes back down is a change you shipped — a new model, a bigger context, a schedule that now runs hourly. - 2
Narrow to a provider, then an agent
Cost by provider tells you which account is being charged; Cost by agent is where the surprise usually is. One agent on one expensive model routinely accounts for most of a bill. - 3
Open that agent's runs in Traces & Logs
Sort by cost. You are looking for whether the spend is many ordinary runs or a few enormous ones, because the fix is completely different — see Logs & traces. - 4
Open the most expensive run and read it step by step
Every step carries its own tokens and cost. The cause is nearly always visible as one of a few shapes: a loop that ran its full iteration count, a retrieval that pulled far more context than the answer needed, or a prompt that grew because history is being resent every turn.
| What you find | What it usually is | Where to fix it |
|---|---|---|
| Many runs, each ordinary | Volume, not waste — something is calling the agent more than you thought, often a schedule or an embed. | A per-key cap in Budgets, or a rate limit on the embed. |
| A few enormous runs | A loop hitting its ceiling, or a swarm branch nobody expected to be taken. | Lower maxIters, or fix the condition that routes into it — Swarm Canvas. |
| One step dominating a run | Too much retrieved context, or a strong model doing mechanical work. | Lower top-K, or split the step onto a smaller model — Models. |
| Input tokens climbing across a conversation | The whole history is being resent each turn. | Shrink the memory window or enable summarisation — Memory. |
Caps are how you stop it happening again
ENFORCE_BUDGET_CAP; unset, they alert and let the spend through. Any instance with a public embed on it should have both.Swarm observability
Swarm runs get their own deep-inspection view at Analytics → Swarm Observability. Opening a run shows three tabs:
- Canvas
- The swarm graph as it was at run time, so you can see the shape of what executed — including for runs of swarms you've since edited.
- Timeline
- The execution order, node by node, with each step's kind and model. Clicking a step opens its detail: input, output, thinking, and tool calls.
- Data flow
- Every message that crossed an edge — which node produced it, which node consumed it. This is where context-window problems become visible: you can see exactly how much text was handed to each node.
Service monitoring
Observability → Monitoring answers the operator’s question rather than the analyst’s: is every piece of this deployment actually running, and what is the machine doing right now? It is superadmin-only, because it reports hostnames, container limits and which internal services exist.
| Panel | What it shows |
|---|---|
| CPU | Utilisation sampled across all cores, with the core count, the container's CPU quota when one is set, and the 1/5/15-minute load averages. |
| Memory | Used against the total — and it says which total: a container's cgroup LIMIT when there is one, otherwise host RAM. Showing 3 GB of 64 GB while the container dies at 4 GB would be worse than showing nothing. |
| Disk | Usage of the filesystem the app is installed on, where the platform reports it. |
| App process | Resident memory, heap used against heap total, and how long this process has been up. |
| Services | One row per service — the app, Supabase, and every optional container — with its status, response time and the address that answered. |
Note
The view refreshes every 15 seconds while open (toggleable), and each probe reports what the service itself says — the document renderer’s LibreOffice availability, for instance, appears alongside its status rather than being assumed from the fact that it answered.
The audit timeline
The timeline merges three sources at read time, which is why an action can appear here without a matching row in any single table:
| Source | Contributes |
|---|---|
audit_events | User and admin activities — sign-ins, publishes, grants, deletes, agent chats |
execution_traces | Model calls, surfaced as the model.call action |
swarm_runs | Swarm executions, surfaced as swarm.run |
Non-administrators see only their own rows — the scoping is done by row-level security, not by the query — while a superadmin sees the whole workspace.
Retention
| Setting | Default | Range | Notes |
|---|---|---|---|
audit_retention_days | 365 | 1 – 365 | How long audit events are kept before the scheduled purge. |
trace_retention_days | 0 (keep forever) | 0 – 3650 | Zero means no trace purge at all. Set it deliberately — traces can hold prompt bodies. |
AUDIT_ARCHIVE_ON_PURGE | off | env var | Archive events on purge instead of dropping them. |
Traces are kept forever by default
trace_retention_days ships at 0, meaning nothing is ever purged. Combined with PERSIST_PROMPT_BODIES, that can mean full prompts and responses accumulating indefinitely — and on a busy instance execution_traces and swarm_runs are the fastest-growing tables you have. Set a window in Admin → IAM → Settings → Trace retention. The purge has always run on the scheduled maintenance pass; until that field is non-zero it simply has nothing to do. See also Budgets & cost.Export
The audit log exports as NDJSON — one JSON object per line — which streams into most log pipelines without transformation and stays readable when the file is large.