Decision
decision forecasts the outcome under each alternative of a choice you control. Each row states one outcome question and lists that decision's mutually exclusive alternatives; the outcome is then forecast under each alternative as its own hypothetical.
"If I fund this organization at $0 / $300k / $2M, will it ship its study by 2027?" is a decision. So is "if we move all-team offsites from every 3 months to every 2 or every 1, will ARR grow more than 200% year on year?" In both cases the "if" clause is something you get to choose.
The outcome under each alternative can be a probability, a numeric quantity, or a date, selected with forecast_type.
All alternatives are researched jointly, so the differences between them reflect the decision's real effect rather than three unrelated forecasts.
Decision or conditional forecast?
This is the distinction that matters most, and it is easy to get wrong.
forecastwith aconditionanswers the correlational question: "in worlds where X happens, what else is true?" Observing X may be evidence about the kind of world you are in.decisionanswers the causal question: "what does choosing X actually cause?" It reasons through mechanism, never through what your choice would reveal about the world.
Use decision whenever the "if" clause is a choice you control. Use a conditional forecast when the "if" is something you merely observe.
Examples
Every operation is a coroutine. Run it with asyncio.run() as below, or await it directly in a Jupyter notebook. Later snippets on this page omit the wrapper for brevity.
Binary
The default. forecast_type="binary" gives one probability (0 to 100) per alternative: the chance the outcome resolves YES if that alternative is chosen.
import asyncio
import json
from pandas import DataFrame
from futuresearch.ops import decision
decisions = DataFrame([
{
"question": "Will the study be published in a peer-reviewed journal before 2028-01-01?",
"grant_size": json.dumps(["$0 (no grant)", "$300k", "$2M"]),
"resolution_criteria": "Resolves YES if the study appears in a peer-reviewed journal before January 1, 2028.",
"background": "The lab has published two related papers since 2024 and currently has no dedicated funding for this work.",
},
])
async def main():
result = await decision(
input=decisions,
alternatives_field="grant_size",
)
print(result.data[["question", "probabilities", "rationale"]])
asyncio.run(main())
| Column | Type | Description |
|---|---|---|
probabilities |
str | JSON object mapping each alternative to the outcome's probability (0 to 100) given that alternative is chosen |
rationale |
str | Reasoning with citations from web research, covering all alternatives together |
Numeric
forecast_type="numeric" gives a percentile estimate (p10 through p90) per alternative. Requires output_field and units.
result = await decision(
input=DataFrame([
{
"question": "How many full-time researchers will the lab employ at the end of 2027?",
"grant_size": json.dumps(["$0 (no grant)", "$300k", "$2M"]),
"background": "The lab has three researchers today, all part-time.",
},
]),
alternatives_field="grant_size",
forecast_type="numeric",
output_field="headcount",
units="researchers",
)
print(result.data[["percentiles", "units", "rationale"]])
| Column | Type | Description |
|---|---|---|
percentiles |
str | JSON object mapping each alternative to its percentile record {p10, p25, p50, p75, p90} (numbers) given that alternative is chosen |
units |
str | The units provided as parameter |
rationale |
str | Reasoning with citations, covering all alternatives together |
Date
forecast_type="date" gives a percentile date (p10 through p90, as YYYY-MM-DD) per alternative. Requires output_field.
result = await decision(
input=DataFrame([
{
"question": "When will the study be published?",
"grant_size": json.dumps(["$0 (no grant)", "$300k", "$2M"]),
},
]),
alternatives_field="grant_size",
forecast_type="date",
output_field="publication_date",
)
print(result.data[["percentiles", "rationale"]])
| Column | Type | Description |
|---|---|---|
percentiles |
str | JSON object mapping each alternative to its percentile record {p10, p25, p50, p75, p90}, each value a YYYY-MM-DD string (or the literal "never" for percentiles in the indefinite future), given that alternative is chosen |
rationale |
str | Reasoning with citations, covering all alternatives together |
Whatever the outcome type, each alternative is a separate hypothetical, not a share of a single distribution. The values across alternatives need not sum to 100 and need not be monotonic.
Input columns
| Column | Required | Description |
|---|---|---|
question |
Yes | The outcome question, phrased to match forecast_type: a yes/no question for binary, a "how much / how many" question for numeric, a "when" question for date |
| (alternatives column) | Yes | Named by alternatives_field. A JSON array of 2 to 50 unique numbers or strings. A binary "do X / don't do X" decision is the 2-alternative case. |
resolution_criteria |
Recommended | What counts as the outcome |
resolution_date |
Recommended | When the outcome resolves |
background |
Recommended | Context the forecaster should start from |
All columns in the table are used in the forecast, so any extra context you supply is read.
Parameters
| Name | Type | Description |
|---|---|---|
input |
DataFrame | UUID | TableResult | The input table |
alternatives_field |
str | Required, keyword-only. Name of the column holding each row's alternatives as a JSON array |
forecast_type |
"binary" | "numeric" | "date" |
Outcome type forecast under each alternative. Defaults to "binary". |
output_field |
str | Name of the quantity being forecast. Required when forecast_type is "numeric" or "date" (e.g. "headcount", "publication_date") |
units |
str | Units for the outcome. Required when forecast_type is "numeric" (e.g. "researchers", "USD") |
context |
str | Optional batch-level context applied to every row. Leave unset when rows are self-contained |
intervention |
str | Optional. The intervention assumptions (see below) |
session |
Session | Optional, auto-created if omitted |
Intervention assumptions
A decision forecast has to assume something about what actually executing an alternative means: whether it is public, when it happens, and how everyone else reacts. Left unset, the defaults are that the decision is made soon, all downstream consequences count (including other agents' reactions), the world responds realistically in every branch, and the forecast reasons through mechanism rather than through what the choice would reveal.
Supplying intervention replaces those defaults wholesale, so state the full set of assumptions rather than just the one you want to change:
result = await decision(
input=decisions,
alternatives_field="grant_size",
intervention=(
"Assume the grant is announced publicly at the time it is made, that no "
"other funder backfills a declined application, and that the decision is "
"made within the next quarter."
),
)
Via MCP
MCP tool: futuresearch_decision
| Parameter | Type | Description |
|---|---|---|
data |
list[object] | Inline data as a list of row objects |
artifact_id |
string | Alternatively, an artifact ID from a previous upload |
alternatives_field |
string | Name of the column holding each row's alternatives as a JSON array |
forecast_type |
string | "binary" (default), "numeric", or "date": the outcome type forecast under each alternative |
output_field |
string | Name of the quantity being forecast (required for numeric and date) |
units |
string | Units for the outcome (required for numeric) |
context |
string | Optional table-level context for every row |
intervention |
string | Optional intervention assumptions |
Provide either data or artifact_id, not both. See the MCP server reference for the rest of the lifecycle (progress, results, status).
Related docs
- forecast: ordinary and conditional forecasts, including the world-modeling pass.
- World modeling: the shared model of the world every forecast draws on.
Case studies
- Which CEO Replacement Maximizes Share Price: three calls price every option a board has, with a named-candidate ladder against an unnamed control.
- Forecast a Decision: Grant Funding at Three Levels: the same outcome priced under three funding levels for 18 proposals.