Build a dashboard briefing
Build a Markdown brief one step at a time, from a dashboard's forecasts to their movement between runs.
Turn a dashboard into a Markdown brief: each forecast's latest number and how much it moved since the previous run. These are the same dashboards you see in the Mantic web app.
Full script: dashboard_brief.py.
1. Fetch the dashboard's forecasts
python dashboard_brief.py --list prints your dashboard IDs. iter_dashboard_questions then reads every page of the dashboard's forecasts, each with its latest run:
return paginate(
client,
f"/dashboards/{dashboard_id}/questions",
"questions",
{"show_forecasts": "true"},
)2. Turn the latest run into a headline
latest_forecast is null until the forecast's first run completes, so check that first:
if forecast is None:
return "First run pending"The headline function then branches on the run's type. For an event run, the probability becomes a percentage:
return f"{forecast['probability']:.0%}"For example, 0.64 becomes 64%. The full function handles every type; see Read a forecast's latest run.
3. Find the previous run
The dashboard gives only the latest run. Request the forecast's history with GET /questions/{question_id}/forecasts, newest first:
history = paginate(
client,
f"/questions/{question_id}/forecasts",
"forecasts",
{"show_forecasts": "true"},
)A new run could complete between the dashboard request and the history request. Find the run you displayed by its id, then take the next, older one:
for forecast in history:
if forecast["id"] == latest["id"]:
return [forecast, *islice(history, 1)]
return []4. Calculate movement
For two runs of an event forecast, latest_change subtracts the previous run's probability and converts the difference to percentage points (pp):
points = 100 * (latest["probability"] - previous["probability"])
return f"{points:+.1f}pp"From 0.57 to 0.64, this returns +7.0pp. For other types, see Measure the change.
Connect these functions for each forecast on the dashboard:
latest = question["latest_forecast"]
change = "Change unavailable"
if latest is not None and latest["type"] not in {"redacted", "unknown"}:
pair = previous_forecast(client, question["id"], latest)
change = latest_change(pair) if pair else "Displayed run missing from history"5. Assemble the Markdown entry
render_brief starts with the dashboard title. For each forecast, it adds a linked heading, the two values you just calculated, then the run's completion time and ID:
lines.extend(
[
(
f"## [{escape_link_label(question['title'])}]"
f"(https://app.mantic.com/question/{question['id']})"
),
"",
f"**{headline(latest)}** · {change}",
"",
]
)Run and inspect the brief
List your dashboards, then replace YOUR_DASHBOARD_ID with one of the returned IDs:
python dashboard_brief.py --list
python dashboard_brief.py YOUR_DASHBOARD_ID > dashboard-brief.mdOpen dashboard-brief.md. Example output:
# UK macro outlook
## [Will UK CPI inflation be below 2.5% in December 2026?](https://app.mantic.com/question/123)
**64%** · +7.0pp
Run completed: `2026-09-21T08:30:00Z` · Run ID: `987`Create forecasts in bulk from a template
Validate a CSV of company names, preview every rendered draft, then create the forecasts one at a time with a resumable checkpoint.
Compare Mantic with prediction markets
Pair Mantic event forecasts with Polymarket markets, compare Mantic's probability with the market midpoint, and rank the largest gaps.