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 Observability → Swarm Traces. 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 | on | env var | Purged events are archived rather than dropped. Set it to 0, false or no to drop them instead. |
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.