AIRO is a standing panel of frontier language models that forecasts AI-related
catastrophic-risk questions, re-elicited on a twice-weekly schedule so the forecasts
form a time series rather than a snapshot. It is a project of the
Forecasting Research Institute (FRI). The
live dashboard is at https://airo.forecastingresearch.org, and an accompanying white paper
(linked from the dashboard's FAQ) describes the method and results. The
questions are FRI's Auto-ARC set; the models answer them under grounded,
agentic web search, and the same models are benchmarked for calibration and
skill on ForecastBench and on two simulators, and asked for forecasts
conditional on policy and capability scenarios. The project was called
"Redlines" and then "Auto-ARC" before it became AIRO, so the Python package is
still named redlines and some file and blob names carry the old names.
One page, index.html, assembled from the chunks under web/demo/. Its panels:
- Timeline — the lead panel of the Forecasts tab: how the bottom-line
forecasts move between elicitation dates. Before 2026-10-21 only the ensemble
median is shown; hovering or selecting it reveals the models as ink-gray dots.
From 2026-10-21 each pooled prompt condition has a consistently colored dot
for its panel median, with the prompt and model answers available on hover,
click, tap, or keyboard selection. The legend identifies conditions rather
than models. The series starts at the agentic-harness cutover on
2026-09-02 (
redlines/runlog.py::SERIES_START); earlier elicitations stay in the run log and the download but are not drawn on the same axis. A model that leaves the panel keeps its historical answers in the details. The five pooled prompts' mean is each model's published number. The unpooled sixth call stays in the download and is never drawn (experiments/airo.toml:pooled). - Graph 1 — the current forecasts by horizon: the cross-cutting questions (general catastrophe, AI catastrophe, human disempowerment) and one expected-loss row per AI-related incident cause, with prior human panels (XPT, LEAP) as hollow diamonds where a comparable question exists.
- Graph 2 — the incident severity ladders: probability against a severity
threshold for four AI-related incident causes, on two charts since 2026-10-19
— one for deaths (or equivalent morbidity), one for economic damages, each
rung a separate question on each (
docs/severity-legs-2026-10-19.md; since 2026-10-21 damages exclude monetized mortality,docs/damages-without-mortality-2026-10-21.md) — plus a resolution-free coherence check (P of a stronger event must never exceed P of a weaker event it implies). - Data bank — the bottom-line forecasts collated with their resolution criteria; the download bundle (every forecast and rationale) is linked here and from the page header.
- Capability — the same questions conditional on the level of the frontier Epoch Capabilities Index (ECI): the model first forecasts its own p25/p50/p75 for the frontier ECI at a target date, then conditions on each.
- Policy levers — the same questions conditional on each LEAP Wave 12 policy scenario (built and elicited every run; hidden from the launch page).
- Graph 3 — calibration and resolution against ForecastBench, one round
with a human superforecaster arm (
docs/methodology.mdexplains why one). - Graph 4 — calibration and skill on rare (1–9%) events, a two-simulator average (FreeCiv and a Starsim pandemic) correlated with ECI.
- Graph 5 — observational conditionals: told "suppose A happened" about paired weather questions, does the conditional shift track the association in the resolution data? Rank correlation with ECI, under the noise ceiling.
- Graph 6 — causal conditionals: given a vaccination campaign in a simulated epidemic, does the forecast move the way the simulator does? CRPS skill vs ECI, from the locked Starsim causal dataset.
- FAQ — the questions readers ask, with the elicitation prompt as it was actually sent, and Graphs 4, 5 and 6 inside the relevant answers.
Two runtime tiers, and the split is deliberate. Rebuilding every dashboard
blob from the committed inputs is stdlib-only, needs no keys and no network,
and is checked byte-for-byte against the tracked output by the golden tests.
Eliciting new forecasts needs the FRI Forecaster harness
(packages/fri-forecaster/: stdlib Python, and pi on node) and API keys (next
section).
python3 -m redlines build # rebuild all 14 views and mirror them to results/*.json
python3 -m redlines build --views g1 # any subset: g1,g2,g3,g4,observational,causal,databank,
# timeline,conditional,capability,axes,method,rationales,csv
python3 -m redlines build --list # list view names and exit
python3 -m redlines assemble # rebuild index.html from web/demo/ chunks + fresh blobs
python3 -m redlines export-fb # the provisional ForecastBench-2.0 ingest artifact
python3 -m redlines paper # paper/fig/*.pdf + paper/numbers.tex (needs matplotlib:
# pip install -e '.[paper]'; --backend agg needs no TeX)build and assemble round-trip to the same tracked bytes (see
docs/architecture.md). Graph 3 and Graph 4 are derived from external inputs
(the ForecastBench forecast sets and the forecastbench-sim corpus); when
those are absent the build reads the tracked mirrors results/graph3_data.json
and results/graph4_combined.json, so a fresh clone rebuilds and assembles the
page without sibling checkouts. Re-deriving them needs FB_DATASETS_ROOT /
FBSIM_ROOT and results/eval_full.json (see "Data provenance").
Use Python 3.11+ and Node 22.19+ (22.x) with npm. For example, on Debian/Ubuntu x86-64, install the tools with:
sudo apt-get update
sudo apt-get install -y python3-venv python3-pip curl xz-utils
curl -fsSL https://nodejs.org/dist/v22.19.0/node-v22.19.0-linux-x64.tar.xz -o /tmp/node.tar.xz
sudo tar -xJf /tmp/node.tar.xz -C /usr/local --strip-components=1
node --version
npm --versionOn other platforms, use the matching Node 22 distribution and install Python with venv/pip support through your package manager. From the repository root, in a fresh clone:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[test,paper]' -e './packages/fri-forecaster[dev]'
(cd packages/fri-forecaster && npm ci)
# Local-only exclusions for development artifacts (not shared repository changes).
printf '\n.venv/\nredlines.egg-info/\n' >> .git/info/exclude
# Use disk-backed temporary space: the suite can exceed a small /tmp tmpfs.
mkdir -p .venv/tmp
# Isolate tests from any existing Pi coding-provider login; do not remove it.
TMPDIR="$PWD/.venv/tmp" PI_CODING_AGENT_DIR="$(mktemp -d "$PWD/.venv/tmp/pi.XXXXXX")" \
python -m pytest -q -rs
python3 -m redlines build
python3 -m redlines assemble
git diff --exit-code # on a fresh clone, tracked outputs must be byte-identicalThe root pytest configuration collects both tests/ and
packages/fri-forecaster/tests/. The latter includes real Pi tool-loop tests
against a local scripted model: no forecasting keys, provider login, or paid
calls are needed. Do not omit npm ci: it installs Pi 0.99.2 from the committed
lockfile; without Node and Pi these tests silently skip. Dependency installation
needs network access, but rebuilding uses committed inputs and tracked Graph 3/4
mirrors, not new forecasts. The optional paper extra above enables matplotlib
tests too.
Read the -rs skip summary: external ForecastBench/simulator inputs, internal
LEAP sources, missing current-instrument forecasts and the not-yet-plotted human
timeline can still cause skips. Missing Node/Pi is not an expected skip for
this setup. Do not run acquisition, scheduling or publishing scripts to test or
rebuild the dashboard.
pip install -e . -e ./packages/fri-forecaster # the harness (the pi loop)
(cd packages/fri-forecaster && npm ci) # pi 0.99.2, pinned there
python code/run_unified.py --dry-run # print each condition's prompt, call nothing
python code/run_unified.py --experiment airo --workers 2 # what the cron runs
python code/run_unified.py --experiment airo --condition ai-banned --smokeWhat a run asks is an experiment (experiments/<name>.toml,
redlines/experiments.py): a set of conditions, each one configured way of
running the instrument (the scenario set, the prompt variant, the minimal or
standard instrument, the loop, the models, a URL guard, whether its rows
publish), with settings shared at the top of the file and overridden per
condition. experiments/airo.toml is the published series; pooled names the
conditions whose mean is each model's published number. Rows carry the
experiment, the condition and condition_sha256, a hash of its settings.
--condition runs some of an experiment's conditions; --smoke one model,
into results/experiments/. A condition's cadence says when the cron runs it
(weekdays, UTC, "1st wed" for monthly, or "manual"):
python -m redlines.experiments due prints what is due today, one group a line.
Every call goes through pi (redlines/pi_loop.py) by way of the FRI
Forecaster harness in packages/fri-forecaster/ (its README, "Requirements"):
node 22 and pi 0.99.2, whose cli.js FORECASTER_PI names. The harness hands
pi the prompt on stdin since 2026-10-19; an earlier one passed it as one
argument, which Linux caps at 128 KiB, and the runner refuses a prompt past
that rather than let pi fail. pi has been the published loop since
combined-v9 and the only one since 2026-10-22, when the litellm loop before it
left the repo.
Keys go in ~/.config/redlines/env (mode 600), one KEY=value per line:
ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY,
XAI_API_KEY, TAVILY_API_KEY. A repo-local .env is read as a fallback;
REDLINES_ENV_FILE=<path> pins the run to exactly one file. An already-set
environment variable always beats every file. code/cron_run.sh sources the
same file, and tests/test_llm.py pins the two parsers to agree.
TAVILY_API_KEY is required rather than optional: without it every model still
answers, from parametric memory with no current evidence, and the run looks
identical from the outside, so the runner refuses instead;
--allow-ungrounded makes that an explicit choice.
The published protocol (since 2026-08-27; rows are tagged with a protocol
id, currently unified-joint-combined-v12, see redlines/conditional.py) is the
single instrument: one call per model that answers every question ×
horizon cell unconditionally and under each scenario in one submission, with
no coherence relation stated in the prompt (coherence is measured afterwards).
The prompt calls the scenarios "conditions", LEAP's word, and so do the set
files and the rows written before 2026-10-21 (condition, which
redlines.logs.read_row renames on reading); the code, the newer rows and the
download say scenario.
The prompt is 73 questions (four AI incident types × 9 severity rungs on the
deaths ladder and × 8 on the damages ladder — since 2026-10-19 each rung is a
deaths question and a damages question, docs/severity-legs-2026-10-19.md —
plus five cross-cutting questions: the two 10%-of-population catastrophe
questions, human disempowerment, and since 2026-09-15 the two extinction
questions in XPT's wording, docs/extinction-questions-2026-09-15.md) over six
horizons, two of them rolling. Since
2026-09-02 each model is asked once per run (repeats = 1); the same-day
repeats that preceded it bought a re-asking spread, and their budget went to
the agentic search harness instead, so the views draw no interval on a
single-draw day. The model panel is the top four runnable models by ECI in the
newest Epoch snapshot, one seat per model family (redlines.registry.panel(),
docs/model-set.md). The unconditional slice lands in
results/runs/<stamp>.jsonl, the series every panel reads; the whole
instrument is appended to results/conditional_runs*.jsonl.
A condition's scenarios names its scenario set: data/combined_conditions.json
(the LEAP policies plus the model's own capability percentiles, what the
published series asks), data/eci_conditions.json (fixed ECI levels),
data/axes_conditions.json (risk against an x-axis quantity). See
docs/conditional-forecasts.md. A cron on the serving box pulls main
(code/pull.sh, so what is merged is what runs) and runs
code/cron_run.sh at 12:00 UTC, which refreshes the panel from Epoch's index
(code/refresh_panel.sh), runs whatever is due (the published series on
Wednesdays and Fridays) and publishes the rebuilt page with
code/publish_dashboard.sh.
Each call ends with a debrief turn (since 2026-09-15): per question group, the
sources that mattered most, the most compelling arguments, the most likely
pathway to catastrophe and the base rate, in the model's own words, exported
as results/debriefs.csv. The
axes instruments left the schedule on 2026-09-14; run them by hand with
--experiment axes (or paperaxes) when a fresh axes date is wanted.
The Auto-ARC question workbook and its definitions under data/auto-arc/ are
the single source: code/make_autoarc_questions.py generates
data/autoarc_ladder.json and data/autoarc_crosscutting.json from them, the
runner and every panel read only the generated files, and
tests/test_autoarc_generator.py fails if either is hand-edited. Definition
changes are versioned as instruments (redlines/instrument.py): damages
without monetized mortality (2026-10-21,
docs/damages-without-mortality-2026-10-21.md) is instrument
airo-incidents-prospective-v3, the 2026-10-19 split of every rung into a
deaths question and a damages question was airo-incidents-prospective-v2,
the 2026-09-10 counting rules
(docs/counting-rules-specification-2026-09-10.md) were
airo-incidents-prospective-v1, each superseded instrument's generated
questions are archived under data/instruments/<version>/, and rows carry the
instrument id so a view never answers a revised question with an older
probability.
From inside the forecastbench-sim checkout:
cp /path/to/this-repo/code/mine_lowprob_corpus.py worlds/freeciv/scripts/
uv run python worlds/freeciv/scripts/mine_lowprob_corpus.py \
--data-dir data/games --snapshot-turn 40 \
--rate-lo 0.01 --rate-hi 0.09 --min-n 40 --workers 8 \
--out-dir data/lowprobProduces data/lowprob/{lowprob_classes,lowprob_selected_classes,lowprob_questions}.json.
The reference run (1,019 games, snapshot turn 40) yields 425,270 binary
questions in 564 classes, of which 35 tail classes (1–9%) with 25,919 resolved
instances feed Graph 4; data/lowprob_classes.json records min_n: 40. The
pandemic side is code/pandemic_build_corpus.py in the same environment. The
model evals that ran on these corpora (run_eval.py, pandemic_smoke.py; API
keys + FBSIM_ROOT) called litellm and are archived in archive/litellm-runners/.
index.html BUILD ARTIFACT: the one page; `redlines build`/`assemble` write it
web/
demo/ the page's source: numbered chunks + manifest.json (Timeline is 19-live-timeline.jsx)
shared/ question-rail.jsx, responsive.jsx — helpers the chunks share
img/ the FRI logo and the ForecastBench parity figure (web/fonts/ is ignored:
Season Sans is licensed for the live site only; clones use the fallback stack)
packages/fri-forecaster/ the FRI Forecaster harness -- pi, the research tools, the ForecastBench
driver -- as its own distribution, pip-installable from this repository
(its README). It was the agent-box repository from 2026-10-11 to
2026-10-19 and rejoined with its history.
redlines/ the pipeline package (stdlib only)
__main__.py CLI: build / assemble / export-fb / paper
config.py paths (env-overridable), round pins, thresholds
registry.py the single model table (ids, labels, ECI, colors) + panel()
eci.py the Epoch Capabilities Index: fri_forecaster.eci (one implementation,
shared with the ForecastBench rounds) bound to data/ and the pinned vintages
questions.py schema-checked loaders for the Auto-ARC question set
instrument.py question-version boundaries and dated incident onset windows
experiments.py experiments and their conditions (experiments/*.toml); the prompt variants
logs.py row files, one per run, and read_row (old rows' field names)
runlog.py run-log loading, the series start, replicate pooling
coherence.py every coherence constraint the question set implies
conditional.py per-model deltas under a scenario vs the same-call baseline
historical.py, rail.py, roster.py historical severity markers; the shared question rail; the bench roster
stats.py deciles / brier / bss / spearman / wilson — one implementation each
hydrate.py, pages.py window.__NAME__ blob injection; manifest-driven page assembly
export.py forecasts.csv, rationales.csv, the download bundle, the ForecastBench export
llm.py, tools.py ACQUISITION ONLY: key loading + the agentic tool-use loop; the Tavily tools
pi_loop.py call_tools through FRI's agent-box (pi): the published loop since combined-v9
views/ one pure build() per panel: graph1..graph4, observational, causal,
databank, timeline, conditional, capability, axes, method
paper/ the paper's figures (graph1, graph3, graph4, incident_ladders,
conditional, capability, causal) and numbers.tex; style.py
experiments/ what runs ask: airo.toml (the published series), axes.toml, paperaxes.toml
code/ acquisition scripts, generators and thin shims (see each docstring)
run_unified.py THE forecast runner; --experiment, --condition, --dry-run
cron_run.sh, publish_dashboard.sh the weekly run and the box-side publish
pull.sh, refresh_panel.sh what every box job runs first: the code, then the panel
make_autoarc_questions.py the question generator: data/auto-arc/* -> data/autoarc_*.json
make_*_conditions.py the scenario sets (LEAP policies, ECI levels, self-elicited, axes, combined)
make_eci_trend*.py, eci_projection_metrgraph.py the ECI trend / projection inputs
validate_launch_run.py, audit_cyber.py launch-run audits
mine_lowprob_corpus.py, pandemic_build_corpus.py the Graph 4 corpus (needs forecastbench-sim)
graph3_comparability.py the Graph 3 methodology decomposition (needs FB_DATASETS_ROOT)
observational/ Graph 5: the observational bench, vendored (spec.md, mining, scoring)
data/
auto-arc/ the Auto-ARC question workbook (.xlsx) and definitions (.md) by date
autoarc_ladder.json, autoarc_crosscutting.json the generated question sets (never hand-edited)
instruments/ the previous instrument's definitions and question sets, archived by date
epoch_capabilities_index_<date>.csv Epoch ECI snapshots (2026-07-07 pinned for Graph 4; newest picks the panel;
fetched before every scheduled run since 2026-10-01)
eci_projection_*.json, eci_trend_*.json the ECI trend inputs
live_metr_eci_frontier.json the METR frontier the capability prompt quoted 2026-09-10 .. 09-18 (record only)
leap_policies.json, leap_reference.json the LEAP-derived scenario set and panel aggregates (the
survey documents and raw pull under data/leap/ are internal, gitignored)
*_conditions.json the scenario sets experiments ask (`scenarios`)
human_baselines.json prior human-panel forecasts of comparable questions (XPT, LEAP)
historical_events.json, recent_incidents_2026-09.json severity-axis markers; recent-incident context
lowprob_classes.json, lowprob_selected_classes.json the FreeCiv question classes (564) and the 35 tail classes
observational/ Graph 5 inputs: pairs_selected.json, noise_ceiling.json, candidate provenance
causal/ Graph 6: the LOCKED Starsim causal dataset (README, MANIFEST.sha256, models.csv)
results/
runs/ the unconditional series, one dated .jsonl per run
forecast_runs_unified.jsonl the historical run log before per-run files
conditional_runs*.jsonl the whole instrument per scenario set; *_runs/ the per-run copies
*_data.json, graph4_combined.json the tracked view blobs (mirrors of what the page embeds)
eval_panel2/, pandemic/, observational/ Graph 4 and Graph 5 eval outputs and logs
experiments/, validation/ held arms (e.g. the ECI top-4 arm) and the launch-run audits
coherence_experiment.json the joint-elicitation experiment (docs/coherence-experiment.md)
paper/ figures, numbers.tex and dashboard screenshots for the white paper
tests/ golden tests for build/assemble/paper, the generators, the runner's guards
docs/ see below
archive/ dead scripts, retired question sets and forecasts, superseded runs (archive/README.md)
causal/ Graph 6: the Starsim causal bench's generating code, frozen at causal-v4-locked
litellm-runners/ the research runners that called litellm (the Graph 4 eval, the coherence
experiment, the observational roster run), archived 2026-10-22
archive/jason-demo.html the original mock dashboard the live page grew from (Jason Abaluck)
- Epoch Capabilities Index.
data/epoch_capabilities_index_<date>.csvare snapshots of Epoch AI's ECI leaderboard.redlines/eci.pyis the one reader: the 2026-07-07 vintage is pinned for Graph 4, the newest picks the panel, and a snapshot older than 31 days raises a warning. - ForecastBench (Karger et al., ICLR 2025), CC BY-SA 4.0. Graph 3 reads the
processed forecast sets published on forecastbench.org;
docs/methodology.mdgives the download and why the numbers move when it is re-pulled. - forecastbench-sim (
forecastingresearch/forecastbench-sim, pinned at commit24d88de) supplies the FreeCiv worlds, the question generator and resolver, the Starsim pandemic world and the model eval harness behind Graph 4 and Graph 6.code/mine_lowprob_corpus.pyand the eval scripts run inside that repo'suvenvironment. The 1,019 recorded games and the 25.9k instance corpus are regenerated deterministically there, not committed here; the small class files underdata/and the eval outputs underresults/are. - LEAP survey scenarios. The LEAP survey documents and the raw pull of
panel answers are internal to FRI and are not in this repository
(
data/leap/is gitignored). What is tracked is derived from them:data/leap_policies.json(the Wave 12 policy scenarios the models are prompted with, verbatim in the prompt shown on the FAQ),data/leap_reference.json(each panel's n and median per asked percentile for the questions the page draws as reference lines, extracted bycode/make_leap_reference.py), and the axes scenario sets. The generators that read the internal files exit with a message when they are absent, and their tests skip. - Internal sources, not published. The 31-model ECI table was first
transcribed from an internal FRI analysis; the runner's LLM layer was
vendored on 2026-08-28 from an internal FRI checkout (
redlines/llm.py,redlines/tools.py), so nothing in the run path depends on it; the Graph 6 dataset was locked from FRI's ForecastBench-Sim ICLR work. Where a doc names one of those checkouts it is describing history, not a dependency. - The download. The page's "Download forecasts" button serves
results/forecasts.csv,results/rationales.csvand the bundleresults/redlines-data.zip(both CSVs, the raw logs, the questions and scenarios, a README), all built bypython3 -m redlines build --views csv(redlines/export.py) and not tracked. One line per (call, question, horizon, scenario) for every model in every run; theprotocolcolumn separates the elicitations (the combined instrument'sunified-joint-combined-v*tags, the earlier joint and batch pilots) — do not pool across them.
docs/architecture.md— the acquire → artifact → build → render pipeline, its invariants, external boundaries and open items.docs/methodology.md— Graph 3 comparability (why one ForecastBench round), the grounding tools, the simulator corpora and the Graph 4 subsetting.docs/model-set.md— model selection: the top-k-by-ECI panel, one seat per family, reachability and Graph 4's roster.docs/conditional-forecasts.md— the LEAP Wave 12 policy conditionals, the capability and self-elicited capability conditionals, the combined and axes instruments.docs/conditional-benches.md— Graphs 5 and 6: can the models forecast conditionals? (observational weather pairs; Starsim interventions).docs/coherence-experiment.md— joint elicitation vs one question per call, and why the constraints are measured, not stated.docs/question-swap.md— the design record of the move to the Auto-ARC question set.docs/extinction-questions-2026-09-15.md— the extinction pair: why, whose wording, what it compares with, what changed, what is still the team's call.docs/eci-top4-arm.md— the ECI-ranked panel: where the selection rule came from and what it changed.docs/counting-rules-specification-2026-09-10.md— the incident counting rules (onset windows, cyber campaign boundaries) behind instrumentairo-incidents-prospective-v1.docs/cyber-validation-2026-09-10.md,docs/cyber-validation-prospective-2026-09-10.md,docs/cyber-source-review-prospective-2026-09-10.md— the September 2026 audits of the cyber forecasts and their sources (with.jsonevidence files beside them).
Code is MIT; the data, documentation and figures are CC BY 4.0 (cite "AIRO,
Forecasting Research Institute, https://airo.forecastingresearch.org"). Three
things are not covered: archive/causal/ (a frozen copy from
forecastbench-sim, GPL-3.0), the Epoch Capabilities Index snapshots (Epoch
AI's), and the Season Sans web fonts, which are not in the repository (licensed for the live site only).
See LICENSE (MIT) and LICENSE-DATA (CC BY 4.0 and the carve-outs).