Detect and Explain
Detect and Explain answers "what changed, and why?" on one metric of an app's data model, on demand and as the person asking. Detect finds the segments (combinations of up to four dimensions) whose metric moved unusually in a window. Explain ranks what drove a change against a baseline. detect_and_explain does both.
It is already built; nobody writes code for it. The scheduled kind of detection ("patterns" that watch a KPI and raise incidents) is a separate part of Bicycle: see Pattern Engine.
Where you run it
| From | How |
|---|---|
| An app's analysis panel | Studio draws the panel; it lists the analyses the app declares, and the viewer runs one with their current window and filters. |
| The app's chat | "What changed in failed orders last week, and why?" |
| A coding agent over MCP | analysis_describe, analysis_run, analysis_result (below). |
| A script | REST under /api/data-apps/<app>/analyses and /analysis-jobs. |
It always needs an app: the app fixes the model and the calendar (time zone, week start). To analyse a model that has no app yet, create a minimal app bound to it first.
How a run works
- The caller asks Studio with the app id and either a declared analysis or an intent.
- Studio checks that the caller may read the app, fills in the platform fields (model, windows from the app's calendar), validates the request and queues a job.
- Studio asks Bicycle's analysis engine as the person, within a 30-minute budget.
- Studio returns its own normalised tables: findings (segment, severity, current, baseline, % change, contribution %) and drivers (per finding, ranked).
- The same question twice joins the running job or reuses a recent answer; runs count against the workspace's daily budget. A declared analysis with
scope: sharedis one answer for every viewer of the app; otherwise a job is visible only to whoever started it.
Over MCP
analysis_describe(app_id) # enabled?, declared analyses, the intent fields, budget used and left
analysis_run(app_id, intent={...}) # or analysis_id=<declared>; returns a job id
analysis_result(job_id, wait_s=60) # call until succeeded or failed; findings and drivers as tables (up to 200 rows)
An intent:
{
"kpi": "failed_orders",
"window": "last_week",
"dimensions": ["reason", "region", "channel"],
"mode": "detect_and_explain",
"sensitivity": "medium",
"direction": "both",
"baseline": "P7D",
"filters": [{ "field": "channel", "op": "in", "value": ["web", "app"] }]
}
window:yesterday,last_7_days,last_week,last_month, or{ "from": "YYYY-MM-DD", "through": "YYYY-MM-DD" }.dimensions: up to 4 fields.filters: up to 8, up to 20 values each.mode:detect,explainordetect_and_explain.direction:both,drop,spike.sensitivity:low,medium,high.baseline(explain): a period such asP7D.
A coding agent should report the findings and drivers with the numbers exactly as returned, naming the segment, the change and its contribution, and never add a cause the tables do not show.
Declared analyses in an app
"analyses": [
{ "id": "failed_orders_weekly", "kind": "detect", "title": "What changed in failed orders?",
"config": { "...": "the engine config the agent copied from a run it made" },
"bind": { "window": "viewer", "filters": "viewer" },
"scope": "shared" }
]
- At most 16 per app;
kindisdetectorexplain. bindlets the viewer's window and filters apply.scope: "shared"means one answer for everyone who opens the app;"user"means each viewer's own.- The app builds no panel UI; Studio's host draws it.
Why a metric moved, in words
For a narrative answer with evidence and figures, use the registered cause agent (agent_run("cause", ...) with the question, the model, the metric, the window and a baseline), then agent_result. It uses Detect and Explain as one of its tools. Run it only when the person agrees: it costs more than a plain analysis.
In workflows: not yet
The workflow step kinds detect and explain validate and plan, but every step is reported as not runnable ("run it from a panel, chat or MCP"). Do not build a workflow around them. If you want a weekly "what changed" in someone's inbox today, schedule a workflow that screenshots the app's analysis view, or ask the question in chat.
Limits
- A daily budget per workspace (
analysis_describeshows it, used and left). - Up to 4 dimensions, 8 filters, 20 values per filter; a 30-minute budget per run.
- Results are tables of up to 200 rows per read; ask for the next page rather than assuming the table is complete.
Worked example: What changed, and why.