What has to be true
for this business to work?
Turn operating assumptions into a forecast. Ask what changes when you believe something different. Keep the question, the rationale, and the computed result together.
Separate facts, logic, and beliefs.
Suppose you own half a lemonade stand. Last summer it sold 1,000 cups. You expect some growth, charge $2.50 per cup, and spend about 40% of revenue on variable costs. Would charging $3.00 make the business more valuable?
Burr makes that question explicit in four kinds of files:
- LogicTemplates define how drivers combine.
- FactsCSV files hold reported observations.
- BeliefsParameters hold assumptions and scenarios.
- LearningA journal keeps questions and results.
We will build the stand, inspect its forecast, try premium pricing, record the result, and share an interactive model. All numbers in this starter are illustrative. Its valuation treats modeled profit as free cash flow and omits the complexity of a real business.
Start with a complete workspace.
From the Burr source directory, install the package into a virtual environment. Use Python 3.11 or newer on macOS or Linux, with uv installed. Run the commands below in the same Bash or Zsh terminal.
uv venv
uv pip install --python .venv/bin/python -e .
source .venv/bin/activate
burr --json --versionShow JSON output · 1 command
Burr version output; environment setup tools print their own installation messages.
{
"engine_version": "1.0.0",
"ok": true,
"schema_version": "1.0.0"
}The Burr commands below use --json. Expand Show JSON output beneath each example to inspect results captured from a real run. Omit the flag for the usual terminal tables. Timestamps and fingerprints may differ in your workspace.
Create a new directory named tutorial-model. If it already contains a model, choose another name. init creates the lemonade template, company inputs, reported facts, and a bear scenario.
burr --json init tutorial-model
cd tutorial-model
burr --json test stand
burr --json compare standShow JSON output · 3 commands
{
"company": "companies/stand",
"guide_argv": [
"/Users/johnhorton/tools/ep/burr/.venv/bin/python3",
"-m",
"burr",
"guide",
"--json"
],
"next_argv": [
"/Users/johnhorton/tools/ep/burr/.venv/bin/python3",
"-m",
"burr",
"--json",
"-C",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/tutorial-model",
"next",
"stand"
],
"ok": true,
"template": "lemonade",
"workspace": "tutorial-model"
}{
"ok": true,
"scenarios": [
{
"checks": [
{
"check": "profit <= revenue",
"left": 1650.0,
"ok": true,
"period": 2027,
"right": 2750.0
},
{
"check": "profit <= revenue",
"left": 1773.75,
"ok": true,
"period": 2028,
"right": 2956.25
},
{
"check": "profit <= revenue",
"left": 1862.4375000000002,
"ok": true,
"period": 2029,
"right": 3104.0625000000005
},
{
"check": "revenue >= 0",
"left": 2750.0,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 2956.25,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 3104.0625000000005,
"ok": true,
"period": 2029,
"right": 0.0
}
],
"ok": true,
"scenario": "base",
"validation": [
{
"actual": 1000.0,
"key": "cups0",
"ok": true,
"opinion": 1000.0,
"period": 2026,
"tolerance": 0.005
}
],
"warnings": []
},
{
"checks": [
{
"check": "profit <= revenue",
"left": 1275.0,
"ok": true,
"period": 2027,
"right": 2550.0
},
{
"check": "profit <= revenue",
"left": 1300.5,
"ok": true,
"period": 2028,
"right": 2601.0
},
{
"check": "profit <= revenue",
"left": 1326.5099999999998,
"ok": true,
"period": 2029,
"right": 2653.0199999999995
},
{
"check": "revenue >= 0",
"left": 2550.0,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 2601.0,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 2653.0199999999995,
"ok": true,
"period": 2029,
"right": 0.0
}
],
"ok": true,
"scenario": "bear",
"validation": [
{
"actual": 1000.0,
"key": "cups0",
"ok": true,
"opinion": 1000.0,
"period": 2026,
"tolerance": 0.005
}
],
"warnings": []
}
]
}{
"ok": true,
"scenarios": [
{
"equity": 9073.567708333332,
"ev": 9073.567708333332,
"ok": true,
"per_share": 4536.783854166666,
"scenario": "base",
"terminal_weight": 0.5939226519337018
},
{
"equity": 6571.562499999999,
"ev": 6571.562499999999,
"ok": true,
"per_share": 3285.7812499999995,
"scenario": "bear",
"terminal_weight": 0.584074373484236
}
]
}| Path | What belongs here |
|---|---|
templates/lemonade.yaml | Formulas, parameter units, and checks such as profit ≤ revenue. |
companies/stand/actuals.csv | Reported cups and revenue for 2025 and 2026. |
companies/stand/params.yaml | Forecast years, assumptions, valuation settings, and the bear scenario. |
companies/stand/experiments/ | Append-only experiment records, initially empty. |
burr.lock | Engine and schema versions for the workspace. |
test checks the base case and every scenario. compare reports their valuations. From here onward, keep your terminal in tutorial-model. Alternatively, use burr -C tutorial-model … from the source directory; file paths are then relative to that workspace.
Follow the drivers to the forecast.
The starter template contains three model lines. Business assumptions live in parameters, so the same logic can evaluate different beliefs.
lines:
cups: grow(cups0, cup_growth)
revenue: cups * price
profit: revenue * (1 - cost_pct)grow compounds annual growth from the base-year cup count. Growth falls from 10% in 2027 to 5% in 2029, passing through 7.5% in 2028. The cost assumption is a distribution with a mean of 40%; an ordinary forecast uses that mean.
burr --json run stand
burr --json trace stand profit
burr --json show stand price
burr --json value standShow JSON output · 4 commands
{
"ok": true,
"rows": [
{
"entity": "stand",
"line": "cups",
"period": 2027,
"provenance": "templates/lemonade.yaml:lines.cups",
"scenario": "base",
"value": 1100.0
},
{
"entity": "stand",
"line": "cups",
"period": 2028,
"provenance": "templates/lemonade.yaml:lines.cups",
"scenario": "base",
"value": 1182.5
},
{
"entity": "stand",
"line": "cups",
"period": 2029,
"provenance": "templates/lemonade.yaml:lines.cups",
"scenario": "base",
"value": 1241.6250000000002
},
{
"entity": "stand",
"line": "profit",
"period": 2027,
"provenance": "templates/lemonade.yaml:lines.profit",
"scenario": "base",
"value": 1650.0
},
{
"entity": "stand",
"line": "profit",
"period": 2028,
"provenance": "templates/lemonade.yaml:lines.profit",
"scenario": "base",
"value": 1773.75
},
{
"entity": "stand",
"line": "profit",
"period": 2029,
"provenance": "templates/lemonade.yaml:lines.profit",
"scenario": "base",
"value": 1862.4375000000002
},
{
"entity": "stand",
"line": "revenue",
"period": 2027,
"provenance": "templates/lemonade.yaml:lines.revenue",
"scenario": "base",
"value": 2750.0
},
{
"entity": "stand",
"line": "revenue",
"period": 2028,
"provenance": "templates/lemonade.yaml:lines.revenue",
"scenario": "base",
"value": 2956.25
},
{
"entity": "stand",
"line": "revenue",
"period": 2029,
"provenance": "templates/lemonade.yaml:lines.revenue",
"scenario": "base",
"value": 3104.0625000000005
}
]
}{
"ok": true,
"periods": [
2027,
2028,
2029
],
"tree": {
"dependencies": [
{
"form": {
"dist": "normal",
"hi": 0.7,
"lo": 0.2,
"mean": 0.4,
"sd": 0.05
},
"kind": "binding",
"lagged": false,
"name": "cost_pct",
"rationale": "",
"values": [
0.4,
0.4,
0.4
]
},
{
"dependencies": [
{
"dependencies": [
{
"form": {
"end": 0.05,
"rationale": "word of mouth fades",
"start": 0.1
},
"kind": "binding",
"lagged": false,
"name": "cup_growth",
"rationale": "word of mouth fades",
"values": [
0.1,
0.07500000000000001,
0.05
]
},
{
"form": {
"source": "last summer's tally",
"value": 1000
},
"kind": "binding",
"lagged": false,
"name": "cups0",
"rationale": "",
"values": [
1000.0,
1000.0,
1000.0
]
}
],
"formula": "grow(cups0, cup_growth)",
"kind": "line",
"lagged": false,
"name": "cups",
"values": [
1100.0,
1182.5,
1241.6250000000002
]
},
{
"form": 2.5,
"kind": "binding",
"lagged": false,
"name": "price",
"rationale": "",
"values": [
2.5,
2.5,
2.5
]
}
],
"formula": "cups * price",
"kind": "line",
"lagged": false,
"name": "revenue",
"values": [
2750.0,
2956.25,
3104.0625000000005
]
}
],
"formula": "revenue * (1 - cost_pct)",
"kind": "line",
"name": "profit",
"values": [
1650.0,
1773.75,
1862.4375000000002
]
}
}{
"binding": "price",
"experiments": [],
"form": 2.5,
"ok": true,
"scenarios": [],
"section": "bindings",
"value": 2.5
}{
"equity": 9073.567708333332,
"ev": 9073.567708333332,
"ok": true,
"per_share": 4536.783854166666,
"terminal_weight": 0.5939226519337018
}| Year | Cups | Revenue | Profit |
|---|---|---|---|
| 2027 | 1,100.00 | $2,750.00 | $1,650.00 |
| 2028 | 1,182.50 | $2,956.25 | $1,773.75 |
| 2029 | 1,241.63 | $3,104.06 | $1,862.44 |
The starter discounts future profit at 20%, assumes zero growth after 2029, and divides equity value into two shares. The base value is $4,536.78 per share; the bear case is $3,285.78. trace follows profit back to the formulas and inputs that produce it.
Read the terminal assumption. About 59.4% of the base enterprise value comes from cash flows beyond the explicit forecast. A short forecast can still depend heavily on what you assume about later years.
What if customers accept a higher price?
Create a patch proposing a premium scenario. The price carries a rationale and source alongside its value. For this teaching example, the source is explicitly hypothetical.
cat > premium.yaml <<'YAML'
op: add_scenario
name: premium
thesis: Customers accept a higher price with unchanged volume growth and cost ratio.
bindings:
price:
value: 3.0
rationale: A premium for fresh ingredients and a convenient location.
source: hypothetical customer interviews for this tutorial
confidence: medium
YAML
burr --json try stand premium.yamlShow JSON output · 1 command
{
"attribution": [
{
"delta": 907.3567708333339,
"key": "price",
"metadata": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial"
},
"section": "bindings"
}
],
"base_per_share": 4536.783854166666,
"gap": 907.3567708333339,
"interactions": 0.0,
"ok": true,
"trial_per_share": 5444.140625
}try evaluates the proposal in memory and writes nothing. With volume and the cost ratio held constant, a 20% price increase raises forecast revenue, profit, and value by 20%. Premium value is $5,444.14 per share, a gain of $907.36.
The result is conditional on the model: it contains no relationship between a higher price and lower demand. That becomes a useful next question for research or a richer template.
Record the finding, then save the scenario.
Attach the question and interpretation to machine-computed results. On this fresh workspace, the first record is exp-001.
burr --json record stand premium.yaml \
--question 'What if customers accept a higher price?' \
--finding 'A 20% price increase raises value 20% when volume and the cost ratio hold.' \
--tags pricing
burr --json log stand --param price
burr --json replay stand exp-001Show JSON output · 3 commands
{
"experiment": {
"at": "2026-09-15T11:31:59+00:00",
"finding": "A 20% price increase raises value 20% when volume and the cost ratio hold.",
"fingerprint": "dbd879a3a37aa9ff83c6b0734091edeb96a5b8649c108da19c768261d6fa79b2",
"id": "exp-001",
"patch": {
"bindings": {
"price": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial",
"value": 3.0
}
},
"name": "premium",
"op": "add_scenario",
"thesis": "Customers accept a higher price with unchanged volume growth and cost ratio."
},
"question": "What if customers accept a higher price?",
"results": {
"attribution": [
{
"delta": 907.3567708333339,
"key": "price",
"metadata": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial"
},
"section": "bindings"
}
],
"base_per_share": 4536.783854166666,
"gap": 907.3567708333339,
"interactions": 0.0,
"ok": true,
"trial_per_share": 5444.140625
},
"scenario": "base",
"tags": [
"pricing"
]
},
"ok": true
}{
"entries": [
{
"at": "2026-09-15T11:31:59+00:00",
"finding": "A 20% price increase raises value 20% when volume and the cost ratio hold.",
"fingerprint": "dbd879a3a37aa9ff83c6b0734091edeb96a5b8649c108da19c768261d6fa79b2",
"id": "exp-001",
"patch": {
"bindings": {
"price": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial",
"value": 3.0
}
},
"name": "premium",
"op": "add_scenario",
"thesis": "Customers accept a higher price with unchanged volume growth and cost ratio."
},
"question": "What if customers accept a higher price?",
"results": {
"attribution": [
{
"delta": 907.3567708333339,
"key": "price",
"metadata": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial"
},
"section": "bindings"
}
],
"base_per_share": 4536.783854166666,
"gap": 907.3567708333339,
"interactions": 0.0,
"ok": true,
"trial_per_share": 5444.140625
},
"scenario": "base",
"stale": false,
"tags": [
"pricing"
]
}
],
"ok": true
}{
"current": {
"attribution": [
{
"delta": 907.3567708333339,
"key": "price",
"metadata": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial"
},
"section": "bindings"
}
],
"base_per_share": 4536.783854166666,
"gap": 907.3567708333339,
"interactions": 0.0,
"ok": true,
"trial_per_share": 5444.140625
},
"id": "exp-001",
"ok": true,
"recorded": {
"attribution": [
{
"delta": 907.3567708333339,
"key": "price",
"metadata": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial"
},
"section": "bindings"
}
],
"base_per_share": 4536.783854166666,
"gap": 907.3567708333339,
"interactions": 0.0,
"ok": true,
"trial_per_share": 5444.140625
},
"status": "HOLDS"
}record saves the experiment; it does not install the proposed scenario. replay reruns its calculation. Apply the patch to make premium a durable scenario, then ask Burr to explain its difference from base.
burr --json patch stand -f premium.yaml
burr --json test stand
burr --json compare stand
burr --json explain stand --frm base --to premiumShow JSON output · 4 commands
{
"files": [
"companies/stand/params.yaml"
],
"ok": true,
"op": "add_scenario",
"scenario": "premium"
}{
"ok": true,
"scenarios": [
{
"checks": [
{
"check": "profit <= revenue",
"left": 1650.0,
"ok": true,
"period": 2027,
"right": 2750.0
},
{
"check": "profit <= revenue",
"left": 1773.75,
"ok": true,
"period": 2028,
"right": 2956.25
},
{
"check": "profit <= revenue",
"left": 1862.4375000000002,
"ok": true,
"period": 2029,
"right": 3104.0625000000005
},
{
"check": "revenue >= 0",
"left": 2750.0,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 2956.25,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 3104.0625000000005,
"ok": true,
"period": 2029,
"right": 0.0
}
],
"ok": true,
"scenario": "base",
"validation": [
{
"actual": 1000.0,
"key": "cups0",
"ok": true,
"opinion": 1000.0,
"period": 2026,
"tolerance": 0.005
}
],
"warnings": []
},
{
"checks": [
{
"check": "profit <= revenue",
"left": 1275.0,
"ok": true,
"period": 2027,
"right": 2550.0
},
{
"check": "profit <= revenue",
"left": 1300.5,
"ok": true,
"period": 2028,
"right": 2601.0
},
{
"check": "profit <= revenue",
"left": 1326.5099999999998,
"ok": true,
"period": 2029,
"right": 2653.0199999999995
},
{
"check": "revenue >= 0",
"left": 2550.0,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 2601.0,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 2653.0199999999995,
"ok": true,
"period": 2029,
"right": 0.0
}
],
"ok": true,
"scenario": "bear",
"validation": [
{
"actual": 1000.0,
"key": "cups0",
"ok": true,
"opinion": 1000.0,
"period": 2026,
"tolerance": 0.005
}
],
"warnings": []
},
{
"checks": [
{
"check": "profit <= revenue",
"left": 1980.0,
"ok": true,
"period": 2027,
"right": 3300.0
},
{
"check": "profit <= revenue",
"left": 2128.5,
"ok": true,
"period": 2028,
"right": 3547.5
},
{
"check": "profit <= revenue",
"left": 2234.9250000000006,
"ok": true,
"period": 2029,
"right": 3724.875000000001
},
{
"check": "revenue >= 0",
"left": 3300.0,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 3547.5,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue >= 0",
"left": 3724.875000000001,
"ok": true,
"period": 2029,
"right": 0.0
}
],
"ok": true,
"scenario": "premium",
"validation": [
{
"actual": 1000.0,
"key": "cups0",
"ok": true,
"opinion": 1000.0,
"period": 2026,
"tolerance": 0.005
}
],
"warnings": []
}
]
}{
"ok": true,
"scenarios": [
{
"equity": 9073.567708333332,
"ev": 9073.567708333332,
"ok": true,
"per_share": 4536.783854166666,
"scenario": "base",
"terminal_weight": 0.5939226519337018
},
{
"equity": 6571.562499999999,
"ev": 6571.562499999999,
"ok": true,
"per_share": 3285.7812499999995,
"scenario": "bear",
"terminal_weight": 0.584074373484236
},
{
"equity": 10888.28125,
"ev": 10888.28125,
"ok": true,
"per_share": 5444.140625,
"scenario": "premium",
"terminal_weight": 0.5939226519337018
}
]
}{
"attribution": [
{
"delta": 907.3567708333339,
"key": "price",
"metadata": {
"confidence": "medium",
"rationale": "A premium for fresh ingredients and a convenient location.",
"source": "hypothetical customer interviews for this tutorial"
},
"section": "bindings"
}
],
"from": "base",
"gap": 907.3567708333339,
"interactions": 0.0,
"ok": true,
"to": "premium"
}patch validates the proposed workspace before committing it. explain attributes the valuation gap to changed inputs and reports any remaining interaction effect. Here there is only one changed input: price.
Journal records are never overwritten. Changes to facts, assumptions, logic, or environment can mark prior evidence stale. Use burr log stand --stale to find records worth revisiting.
Explore ranges as well as stories.
Sensitivity
A grid varies two inputs while holding the others fixed. See how pricing and the discount rate jointly affect value.
Monte Carlo
Repeated draws from declared distributions reveal the spread of outcomes implied by those assumptions. The starter varies its cost ratio.
burr --json sens stand --x price=2:3:.25 --y valuation.wacc=.15:.25:.025
burr --json mc stand --draws 1000 --seed 42Show JSON output · 2 commands
{
"grid": [
[
4865.784499054822,
5474.007561436675,
6082.230623818528,
6690.453686200381,
7298.676748582235
],
[
4158.985966500679,
4678.859212313264,
5198.732458125849,
5718.605703938433,
6238.478949751019
],
[
3629.427083333334,
4083.10546875,
4536.783854166666,
4990.462239583334,
5444.140625
],
[
3217.992503123698,
3620.2415660141596,
4022.490628904622,
4424.739691795085,
4826.988754685548
],
[
2889.2160000000003,
3250.3680000000004,
3611.5200000000004,
3972.672,
4333.8240000000005
]
],
"ok": true,
"x": {
"key": "bindings.price",
"values": [
2.0,
2.25,
2.5,
2.75,
3.0
]
},
"y": {
"key": "valuation.wacc",
"values": [
0.15,
0.175,
0.2,
0.225,
0.25
]
}
}{
"histogram": [
{
"count": 1,
"hi": 3248.8178934564985,
"lo": 3118.2605603813618
},
{
"count": 2,
"hi": 3379.3752265316357,
"lo": 3248.8178934564985
},
{
"count": 1,
"hi": 3509.932559606773,
"lo": 3379.3752265316357
},
{
"count": 2,
"hi": 3640.4898926819096,
"lo": 3509.932559606773
},
{
"count": 16,
"hi": 3771.0472257570464,
"lo": 3640.4898926819096
},
{
"count": 36,
"hi": 3901.6045588321836,
"lo": 3771.0472257570464
},
{
"count": 38,
"hi": 4032.1618919073208,
"lo": 3901.6045588321836
},
{
"count": 60,
"hi": 4162.7192249824575,
"lo": 4032.1618919073208
},
{
"count": 96,
"hi": 4293.276558057594,
"lo": 4162.7192249824575
},
{
"count": 121,
"hi": 4423.833891132732,
"lo": 4293.276558057594
},
{
"count": 140,
"hi": 4554.391224207869,
"lo": 4423.833891132732
},
{
"count": 129,
"hi": 4684.948557283005,
"lo": 4554.391224207869
},
{
"count": 117,
"hi": 4815.505890358143,
"lo": 4684.948557283005
},
{
"count": 91,
"hi": 4946.063223433279,
"lo": 4815.505890358143
},
{
"count": 64,
"hi": 5076.6205565084165,
"lo": 4946.063223433279
},
{
"count": 44,
"hi": 5207.177889583553,
"lo": 5076.6205565084165
},
{
"count": 24,
"hi": 5337.73522265869,
"lo": 5207.177889583553
},
{
"count": 11,
"hi": 5468.292555733828,
"lo": 5337.73522265869
},
{
"count": 6,
"hi": 5598.849888808963,
"lo": 5468.292555733828
},
{
"count": 1,
"hi": 5729.407221884101,
"lo": 5598.849888808963
}
],
"n": 1000,
"ok": true,
"percentiles": {
"p25": 4290.753105020259,
"p5": 3877.8151623394615,
"p50": 4543.901110148627,
"p75": 4806.245039347025,
"p95": 5172.1645465538095
},
"seed": 42
}The Monte Carlo JSON includes percentiles and a histogram; add --full to include each draw. A fixed seed makes the draws reproducible. These outputs describe the assumptions you supplied; uncertainty absent from the model is absent from the simulation.
Can stronger store activity restore margins?
Take the same workflow to Starbucks. This example separates company-operated, licensed, and other revenue. Company-operated revenue grows with three assumptions: store capacity, customer visits, and average ticket. Operating margin then connects revenue to profit and cash flow.
The baseline uses FY2024–FY2025 reported figures from Starbucks’ FY2025 results release. Revenue was $37,184.4 million in FY2025 and operating income was $2,936.6 million. Forecast growth rates and margins are tutorial assumptions.
A fixed FY2025 teaching baseline. The forecast covers FY2026–FY2030 and discounts from FY2025 year-end. Later results, guidance, and ownership changes are outside this snapshot. Values below describe the model’s assumptions, not a current price target.
| Scenario | Traffic growth | Operating margin | Value/share |
|---|---|---|---|
| Bear | 0% throughout | 8% → 10% | $21.15 |
| Base | 1% → 3% | 10% → 14% | $39.98 |
| Bull | 3% → 4% | 12% → 16% | $52.30 |
Each scenario holds annual capacity contribution at 2%, average-ticket growth at 2%, WACC at 9%, and terminal growth at 2.5%. The traffic and margin paths change together in bear and bull. To isolate traffic, the included patch holds visits flat while keeping the other base assumptions.
cd ..
burr --json -C examples/starbucks test starbucks
burr --json -C examples/starbucks compare starbucks
burr --json -C examples/starbucks trace starbucks revenue
burr --json -C examples/starbucks try starbucks patches/slower_traffic.yaml
burr --json -C examples/starbucks log starbucks --param traffic_growth
burr --json -C examples/starbucks replay starbucks exp-001Show JSON output · 6 commands
{
"ok": true,
"scenarios": [
{
"checks": [
{
"check": "revenue > 0",
"left": 39003.942819200005,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 41081.202513628115,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 43447.98552367938,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 46142.060806304624,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 49208.23955432948,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "ebit <= revenue",
"left": 3900.3942819200006,
"ok": true,
"period": 2026,
"right": 39003.942819200005
},
{
"check": "ebit <= revenue",
"left": 4518.932276499093,
"ok": true,
"period": 2027,
"right": 41081.202513628115
},
{
"check": "ebit <= revenue",
"left": 5213.758262841526,
"ok": true,
"period": 2028,
"right": 43447.98552367938
},
{
"check": "ebit <= revenue",
"left": 5998.467904819601,
"ok": true,
"period": 2029,
"right": 46142.060806304624
},
{
"check": "ebit <= revenue",
"left": 6889.153537606127,
"ok": true,
"period": 2030,
"right": 49208.23955432948
},
{
"check": "operating_margin >= 0",
"left": 0.1,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.11000000000000001,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.12000000000000001,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.13,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.14,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "operating_margin <= 1",
"left": 0.1,
"ok": true,
"period": 2026,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.11000000000000001,
"ok": true,
"period": 2027,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.12000000000000001,
"ok": true,
"period": 2028,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.13,
"ok": true,
"period": 2029,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.14,
"ok": true,
"period": 2030,
"right": 1.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2026,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2027,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2028,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2029,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2030,
"right": 1.0
},
{
"check": "da >= 0",
"left": 1833.1853125024002,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "da >= 0",
"left": 1930.8165181405213,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2042.0553196129308,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2168.6768578963174,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2312.7872590534853,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2535.2562832480003,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2618.9266602437924,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2715.4990952299613,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2826.201224386158,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2952.4943732597685,
"ok": true,
"period": 2030,
"right": 0.0
}
],
"ok": true,
"scenario": "base",
"validation": [
{
"actual": 30744.8,
"key": "company_revenue0",
"ok": true,
"opinion": 30744.8,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 4350.4,
"key": "licensed_revenue0",
"ok": true,
"opinion": 4350.4,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 2089.2,
"key": "other_revenue0",
"ok": true,
"opinion": 2089.2,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 37184.4,
"key": "revenue0",
"ok": true,
"opinion": 37184.4,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 36176.2,
"key": "revenue",
"ok": true,
"period": 2024,
"segments": [
"company_revenue",
"licensed_revenue",
"other_revenue"
],
"sum": 36176.200000000004
},
{
"actual": 37184.4,
"key": "revenue",
"ok": true,
"period": 2025,
"segments": [
"company_revenue",
"licensed_revenue",
"other_revenue"
],
"sum": 37184.4
}
],
"warnings": []
},
{
"checks": [
{
"check": "revenue > 0",
"left": 38684.073919999995,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 40244.231632768,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 41867.31256218782,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 43555.85452001446,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 45312.49767414986,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "ebit <= revenue",
"left": 3094.7259136,
"ok": true,
"period": 2026,
"right": 38684.073919999995
},
{
"check": "ebit <= revenue",
"left": 3420.7596887852806,
"ok": true,
"period": 2027,
"right": 40244.231632768
},
{
"check": "ebit <= revenue",
"left": 3768.0581305969035,
"ok": true,
"period": 2028,
"right": 41867.31256218782
},
{
"check": "ebit <= revenue",
"left": 4137.806179401374,
"ok": true,
"period": 2029,
"right": 43555.85452001446
},
{
"check": "ebit <= revenue",
"left": 4531.249767414986,
"ok": true,
"period": 2030,
"right": 45312.49767414986
},
{
"check": "operating_margin >= 0",
"left": 0.08,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.085,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.09,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.095,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.1,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "operating_margin <= 1",
"left": 0.08,
"ok": true,
"period": 2026,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.085,
"ok": true,
"period": 2027,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.09,
"ok": true,
"period": 2028,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.095,
"ok": true,
"period": 2029,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.1,
"ok": true,
"period": 2030,
"right": 1.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2026,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2027,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2028,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2029,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2030,
"right": 1.0
},
{
"check": "da >= 0",
"left": 1818.1514742399997,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "da >= 0",
"left": 1891.4788867400962,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "da >= 0",
"left": 1967.7636904228275,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2047.1251624406796,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2129.6873906850433,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2514.4648048,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2565.56976658896,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2616.707035136739,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2667.7960893508857,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2718.7498604489915,
"ok": true,
"period": 2030,
"right": 0.0
}
],
"ok": true,
"scenario": "bear",
"validation": [
{
"actual": 30744.8,
"key": "company_revenue0",
"ok": true,
"opinion": 30744.8,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 4350.4,
"key": "licensed_revenue0",
"ok": true,
"opinion": 4350.4,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 2089.2,
"key": "other_revenue0",
"ok": true,
"opinion": 2089.2,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 37184.4,
"key": "revenue0",
"ok": true,
"opinion": 37184.4,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 36176.2,
"key": "revenue",
"ok": true,
"period": 2024,
"segments": [
"company_revenue",
"licensed_revenue",
"other_revenue"
],
"sum": 36176.200000000004
},
{
"actual": 37184.4,
"key": "revenue",
"ok": true,
"period": 2025,
"segments": [
"company_revenue",
"licensed_revenue",
"other_revenue"
],
"sum": 37184.4
}
],
"warnings": []
},
{
"checks": [
{
"check": "revenue > 0",
"left": 39643.680617599995,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 42356.62633108195,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 45353.796089030635,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 48670.05838628044,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "revenue > 0",
"left": 52345.257670465704,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "ebit <= revenue",
"left": 4757.241674112,
"ok": true,
"period": 2026,
"right": 39643.680617599995
},
{
"check": "ebit <= revenue",
"left": 5506.361423040654,
"ok": true,
"period": 2027,
"right": 42356.62633108195
},
{
"check": "ebit <= revenue",
"left": 6349.53145246429,
"ok": true,
"period": 2028,
"right": 45353.796089030635
},
{
"check": "ebit <= revenue",
"left": 7300.508757942066,
"ok": true,
"period": 2029,
"right": 48670.05838628044
},
{
"check": "ebit <= revenue",
"left": 8375.241227274513,
"ok": true,
"period": 2030,
"right": 52345.257670465704
},
{
"check": "operating_margin >= 0",
"left": 0.12,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.13,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.14,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.15,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "operating_margin >= 0",
"left": 0.16,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "operating_margin <= 1",
"left": 0.12,
"ok": true,
"period": 2026,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.13,
"ok": true,
"period": 2027,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.14,
"ok": true,
"period": 2028,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.15,
"ok": true,
"period": 2029,
"right": 1.0
},
{
"check": "operating_margin <= 1",
"left": 0.16,
"ok": true,
"period": 2030,
"right": 1.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "tax_rate >= 0",
"left": 0.25,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2026,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2027,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2028,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2029,
"right": 1.0
},
{
"check": "tax_rate <= 1",
"left": 0.25,
"ok": true,
"period": 2030,
"right": 1.0
},
{
"check": "da >= 0",
"left": 1863.2529890271999,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "da >= 0",
"left": 1990.7614375608516,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2131.6284161844396,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2287.492744155181,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "da >= 0",
"left": 2460.227110511888,
"ok": true,
"period": 2030,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2576.8392401439996,
"ok": true,
"period": 2026,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2700.234928606474,
"ok": true,
"period": 2027,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2834.6122555644147,
"ok": true,
"period": 2028,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 2981.041076159677,
"ok": true,
"period": 2029,
"right": 0.0
},
{
"check": "capex >= 0",
"left": 3140.715460227942,
"ok": true,
"period": 2030,
"right": 0.0
}
],
"ok": true,
"scenario": "bull",
"validation": [
{
"actual": 30744.8,
"key": "company_revenue0",
"ok": true,
"opinion": 30744.8,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 4350.4,
"key": "licensed_revenue0",
"ok": true,
"opinion": 4350.4,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 2089.2,
"key": "other_revenue0",
"ok": true,
"opinion": 2089.2,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 37184.4,
"key": "revenue0",
"ok": true,
"opinion": 37184.4,
"period": 2025,
"tolerance": 0.005
},
{
"actual": 36176.2,
"key": "revenue",
"ok": true,
"period": 2024,
"segments": [
"company_revenue",
"licensed_revenue",
"other_revenue"
],
"sum": 36176.200000000004
},
{
"actual": 37184.4,
"key": "revenue",
"ok": true,
"period": 2025,
"segments": [
"company_revenue",
"licensed_revenue",
"other_revenue"
],
"sum": 37184.4
}
],
"warnings": []
}
]
}{
"ok": true,
"scenarios": [
{
"equity": 45448.04284986929,
"ev": 58063.2428498693,
"ok": true,
"per_share": 39.97540931468844,
"scenario": "base",
"terminal_weight": 0.7882779025537872
},
{
"equity": 24040.590729058607,
"ev": 36655.79072905861,
"ok": true,
"per_share": 21.14573905273868,
"scenario": "bear",
"terminal_weight": 0.7756749526001264
},
{
"equity": 59462.906243614736,
"ev": 72078.10624361473,
"ok": true,
"per_share": 52.30267063384179,
"scenario": "bull",
"terminal_weight": 0.7859566218080818
}
]
}{
"ok": true,
"periods": [
2026,
2027,
2028,
2029,
2030
],
"tree": {
"dependencies": [
{
"dependencies": [
{
"dependencies": [
{
"form": {
"rationale": "Annual revenue contribution from net capacity growth and store maturation; not a reported store-count forecast.",
"source": "tutorial assumption",
"value": 0.02
},
"kind": "binding",
"lagged": false,
"name": "footprint_growth",
"rationale": "Annual revenue contribution from net capacity growth and store maturation; not a reported store-count forecast.",
"values": [
0.02,
0.02,
0.02,
0.02,
0.02
]
},
{
"form": {
"rationale": "Annual average-ticket growth from price and mix, with no automatic demand elasticity.",
"source": "tutorial assumption",
"value": 0.02
},
"kind": "binding",
"lagged": false,
"name": "ticket_growth",
"rationale": "Annual average-ticket growth from price and mix, with no automatic demand elasticity.",
"values": [
0.02,
0.02,
0.02,
0.02,
0.02
]
},
{
"form": {
"end": 0.03,
"rationale": "Improving customer visits; applied as a simplified company-operated revenue driver.",
"source": "tutorial assumption",
"start": 0.01
},
"kind": "binding",
"lagged": false,
"name": "traffic_growth",
"rationale": "Improving customer visits; applied as a simplified company-operated revenue driver.",
"values": [
0.01,
0.015,
0.019999999999999997,
0.024999999999999998,
0.03
]
}
],
"formula": "(1 + footprint_growth) * (1 + traffic_growth) * (1 + ticket_growth) - 1",
"kind": "line",
"lagged": false,
"name": "company_growth",
"values": [
0.05080400000000007,
0.056006,
0.06120799999999993,
0.06640999999999986,
0.07161200000000001
]
},
{
"form": {
"as_of": "2025-09-28",
"rationale": "FY2025 consolidated company-operated store revenue, USD millions.",
"source": "https://investor.starbucks.com/news/financial-releases/news-details/2025/Starbucks-Reports-Q4-and-Full-Fiscal-Year-2025-Results/",
"value": 30744.8
},
"kind": "binding",
"lagged": false,
"name": "company_revenue0",
"rationale": "FY2025 consolidated company-operated store revenue, USD millions.",
"values": [
30744.8,
30744.8,
30744.8,
30744.8,
30744.8
]
}
],
"formula": "grow(company_revenue0, company_growth)",
"kind": "line",
"lagged": false,
"name": "company_revenue",
"values": [
32306.7588192,
34116.131153628114,
36204.31130927939,
38608.63962332862,
41373.48152403443
]
},
{
"dependencies": [
{
"form": {
"rationale": "Growth in product sales and royalties recognized from licensees.",
"source": "tutorial assumption",
"value": 0.04
},
"kind": "binding",
"lagged": false,
"name": "licensed_growth",
"rationale": "Growth in product sales and royalties recognized from licensees.",
"values": [
0.04,
0.04,
0.04,
0.04,
0.04
]
},
{
"form": {
"as_of": "2025-09-28",
"rationale": "Revenue recognized by Starbucks; excludes licensees' retail sales.",
"source": "sources/reported.csv; FY2025 consolidated licensed-store revenue",
"value": 4350.4
},
"kind": "binding",
"lagged": false,
"name": "licensed_revenue0",
"rationale": "Revenue recognized by Starbucks; excludes licensees' retail sales.",
"values": [
4350.4,
4350.4,
4350.4,
4350.4,
4350.4
]
}
],
"formula": "grow(licensed_revenue0, licensed_growth)",
"kind": "line",
"lagged": false,
"name": "licensed_revenue",
"values": [
4524.416,
4705.39264,
4893.6083456,
5089.352679424001,
5292.926786600961
]
},
{
"dependencies": [
{
"form": {
"rationale": "Growth in the consolidated other-revenue category.",
"source": "tutorial assumption",
"value": 0.04
},
"kind": "binding",
"lagged": false,
"name": "other_growth",
"rationale": "Growth in the consolidated other-revenue category.",
"values": [
0.04,
0.04,
0.04,
0.04,
0.04
]
},
{
"form": {
"as_of": "2025-09-28",
"rationale": "Consolidated revenue category, not the Channel Development segment total.",
"source": "sources/reported.csv; FY2025 consolidated other revenue",
"value": 2089.2
},
"kind": "binding",
"lagged": false,
"name": "other_revenue0",
"rationale": "Consolidated revenue category, not the Channel Development segment total.",
"values": [
2089.2,
2089.2,
2089.2,
2089.2,
2089.2
]
}
],
"formula": "grow(other_revenue0, other_growth)",
"kind": "line",
"lagged": false,
"name": "other_revenue",
"values": [
2172.768,
2259.67872,
2350.0658688,
2444.068503552,
2541.8312436940805
]
}
],
"formula": "company_revenue + licensed_revenue + other_revenue",
"kind": "line",
"name": "revenue",
"values": [
39003.942819200005,
41081.202513628115,
43447.98552367938,
46142.060806304624,
49208.23955432948
]
}
}{
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
}{
"entries": [
{
"at": "2026-09-15T11:01:32+00:00",
"finding": "Flat traffic reduces modeled value by $3.42 per share with ticket, capacity, and margin assumptions fixed.",
"fingerprint": "d28711564727a9cb3345b0a73aa9645b945fc0df9af46227361ab723f5d857f1",
"id": "exp-001",
"patch": {
"bindings": {
"traffic_growth": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment",
"value": 0.0
}
}
},
"question": "What if customer visits do not recover?",
"results": {
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
},
"scenario": "base",
"stale": false,
"tags": [
"traffic"
]
}
],
"ok": true
}{
"current": {
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
},
"id": "exp-001",
"ok": true,
"recorded": {
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
},
"status": "HOLDS"
}The flat-traffic experiment lowers base value by $3.42/share to $36.56. Base terminal value supplies about 78.8% of enterprise value, making the long-run cash-flow and discount assumptions especially influential.
In the dashboard, shift traffic growth or operating margin and inspect the result. These annual-profile sliders add percentage points to each saved year. Historical revenue remains fixed. Read the Starbucks model guide for cash-flow conventions, the capital bridge, source evidence, and regeneration commands, or download the verified Excel workbook.
| Goal | Reference |
|---|---|
| Write templates or richer assumptions | Language semantics |
| Plot history, scenarios, and dependencies | Plotting guide |
| Configure sliders and save choices | Dashboard guide |
| Automate commands | JSON contracts · burr --help · burr COMMAND --help |
Commands support --json for a single machine-readable document. Exit codes distinguish success (0), model or patch diagnostics (1), and usage or malformed-file errors (2).
Ask Burr what comes next.
An agent can use the installed guide and a read-only workspace inspection to follow the same modeling loop. Start here from the source directory; the Starbucks example already includes a recorded traffic experiment.
burr --json guide
burr --json -C examples/starbucks next starbucks \
--patch patches/slower_traffic.yaml \
--question 'What if customer visits do not recover?'Show JSON output · 2 commands
{
"guide": "# Burr agent guide\n\nRun `burr guide` to read this installed guide. Use `burr next COMPANY --json`\nafter material changes. `next` inspects current evidence and returns one action\nor explicit missing inputs. Execute `action.argv` as an argument array; it uses\nthe current Python interpreter, an absolute workspace, and the selected scenario.\nThe `shell` form is quoted for Bash/Zsh. Never concatenate unquoted input into it.\n\n## Golden path\n\n1. **Orient and validate.** Run `next`. It checks all scenarios and returns the\n selected scenario's assumptions, valuation comparison, and relevant journal\n evidence. Read rationales and the principal's question. `repair` or\n `repair_patch` means inspect diagnostics and correct their cause before\n continuing. Do not weaken a check just to get a pass.\n2. **Translate a belief.** Write a YAML patch with a thesis or rationale, keeping\n numeric business assumptions in parameters. Prefer a new scenario to changing\n base. Use `--patch PATH --question TEXT` on `next` to select this task.\n3. **Probe.** `next --patch PATH` evaluates the patch in memory and returns\n `evidence.trial` including attribution and interactions. `burr try` remains\n available for a standalone probe. Both commands write nothing.\n4. **Interpret and record.** Supply `--finding TEXT` after inspecting the results.\n Follow the returned `record` action. The question and interpretation come from\n the caller; `next` does not invent them. Recording preserves evidence without\n applying the patch. If a durable change is requested, use `patch` deliberately\n and call `next` again after the resulting fingerprint change.\n5. **Review evidence.** `next` replays the selected record in memory. A stale\n record remains stale even when its numeric result still holds. Review the new\n calculation and append a fresh record; never overwrite the original. If a\n source patch file is unavailable, write `evidence.suggested_patch` to a new\n YAML file and pass its path. A revised patch or question starts a different\n selection and does not require clearing unrelated journal history.\n6. **Export.** Choose `--deliverable dashboard` (default), `csv`, or `excel`, and\n optionally `--output PATH`. Execute the returned export action, then rerun\n `resume_argv`. The export action uses `--receipt` to write `OUTPUT.burr.json`\n alongside the artifact. Receipts bind its SHA-256 digest, workspace, scenario, command, and\n all scenario fingerprints. Old exports without receipts must be regenerated.\n7. **Conclude.** `complete: true` means the model validates, the selected finding\n is current and replays, and this one deliverable is current. Present the\n finding, assumptions, sources, and artifact. This is a technical completion\n condition; judge separately whether the principal's question is answered.\n\n`next` has no hidden progress file. It cannot know whether you have read an\nassumption or whether the user agrees with a finding. It performs inspect/probe/\nreplay checks itself so repeatedly running a read-only action does not trap the\nworkflow. `required_inputs` may be supplied from authorized task context; ask the\nprincipal only when their intent or missing evidence requires it.\n\nWithout `--patch` or `--question`, the most recent journal entry for the selected\nscenario is used. With either option, only matching entries are used. Patch\nmatching compares parsed content, including metadata. Keep passing the same\nselection options, or run the returned `resume_argv`. A new finding on an already\ncurrent record selects a new append-only record when it differs; supply the patch\npath and question as well. Exports describe saved scenarios; an unapplied trial remains\nin the journal rather than becoming the exported forecast.\n\n## Example (from a source checkout)\n\n```bash\nburr guide\nburr --json -C examples/starbucks next starbucks \\\n --patch patches/slower_traffic.yaml \\\n --question 'What if customer visits do not recover?'\n```\n\nThe bundled example already has a matching journal entry, so this may proceed\ndirectly to export. For a new question, inspect `evidence.trial`, supply a finding,\nexecute `action.argv`, and rerun `resume_argv` until complete or input is needed.\nInstalled packages do not include the example workspace. Start with\n`burr init my-model`, then `burr --json -C my-model next stand`.\n\nFor example, a price experiment in the starter can use `my-model/premium.yaml`:\n\n```yaml\nbindings:\n price:\n value: 3.0\n rationale: Illustrative premium for convenience; volume held fixed.\n source: tutorial assumption\n```\n\nRun `burr --json -C my-model next stand --patch premium.yaml --question 'What if\nprice rises to 3.00?'` as one command. Read the returned trial before supplying a\nfinding. A plain `bindings`/`valuation` envelope probes the saved assumptions\nwithout naming a new scenario. Durable `add_scenario` operations require a new name.\nUse `burr patch stand --help` for durable edits; the plain mapping above is for\n`try` and `record`, not a durable `patch` operation.\n\n## Modeling obligations\n\n- Distinguish reported facts, management guidance, and assumptions. Preserve\n source dates, rationales, units, fiscal periods, and share scaling.\n- Do not directly rewrite `actuals.csv` or factual `world.yaml` data during\n opinion exploration; use reviewed ingestion tooling for facts.\n- Preserve rationale metadata when replacing value forms. Cite sources for\n base-case changes. Never turn an illustrative assumption into a reported fact.\n- Treat stale findings as unverified until replayed and reviewed. Journal entries\n are append-only. Browser dashboard logs are separate from the workspace journal.\n- Use `trace`, `show`, and `explain` to connect results to drivers. Use `sens` for\n ranges and `mc` only when declared distributions represent intended uncertainty.\n- Valuation requires an explicit cash-flow line, discount assumptions, and\n consistent shares/currency units. Operating-only models can still use `run`\n and `plot`; the valuation golden path stops for missing valuation inputs.\n- No provider calls, spending, messaging, or publication is required by this\n local workflow. Respect the principal's authorized scope for durable edits.\n\n## Machine contract\n\n`--json` controls output, not input. Patch inputs accept YAML (including JSON).\nSuccessful guidance returns `ok`, `protocol_version`, `state`, `complete`,\n`action`, `next_steps`, `required_inputs`, `evidence`, `diagnostics`, `warnings`,\nand `resume_argv`. `action` is null when input is needed or the path is complete.\nThe states are `repair`, `repair_patch`, `review_stale`, `needs_input`, `record`,\n`export`, and `complete`. Guidance may return `ok: true` with `state: repair`:\nthe inspection succeeded but the model needs work. Do not equate `ok` with\ncompletion. Unreadable workspaces or malformed command inputs use normal errors.\n\nExit codes: 0 for successful commands, 1 for model/patch diagnostics, 2 for usage\nor malformed-file errors. Diagnostics include `code`, `where`, and `fix_hint`.\nRun `burr COMMAND --help --json` to inspect options. `ingest` is reserved;\nspreadsheet edits do not flow back into the workspace.\n",
"ok": true,
"protocol_version": "1"
}{
"action": {
"argv": [
"/Users/johnhorton/tools/ep/burr/.venv/bin/python3",
"-m",
"burr",
"--json",
"-C",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks",
"-s",
"base",
"dashboard",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks",
"-o",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html",
"--receipt"
],
"command": "dashboard",
"cwd": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks",
"expected": "An output file and receipt matching the current model and file contents.",
"mutates": true,
"reason": "missing_output",
"requires_network": false,
"shell": "/Users/johnhorton/tools/ep/burr/.venv/bin/python3 -m burr --json -C /private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks -s base dashboard /private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks -o /private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html --receipt",
"writes": [
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html.burr.json"
]
},
"company": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks",
"complete": false,
"deliverable": "dashboard",
"diagnostics": [],
"evidence": {
"artifact": {
"current": false,
"output": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html",
"reason": "missing_output",
"receipt": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html.burr.json"
},
"assumptions": {
"capex_pct": {
"end": 0.06,
"rationale": "Store investment and refurbishment as a share of revenue.",
"source": "tutorial assumption",
"start": 0.065
},
"company_revenue0": {
"as_of": "2025-09-28",
"rationale": "FY2025 consolidated company-operated store revenue, USD millions.",
"source": "https://investor.starbucks.com/news/financial-releases/news-details/2025/Starbucks-Reports-Q4-and-Full-Fiscal-Year-2025-Results/",
"value": 30744.8
},
"da_pct": {
"rationale": "Depreciation and amortization addback as a share of revenue; excludes equity compensation and lease addbacks.",
"source": "tutorial assumption; sources/reported.csv for historical cash-flow D&A",
"value": 0.047
},
"footprint_growth": {
"rationale": "Annual revenue contribution from net capacity growth and store maturation; not a reported store-count forecast.",
"source": "tutorial assumption",
"value": 0.02
},
"incremental_nwc_pct": {
"rationale": "Incremental working capital consumes 2% of the change in revenue; simplified aggregate cash-flow adjustment.",
"source": "tutorial assumption",
"value": 0.02
},
"licensed_growth": {
"rationale": "Growth in product sales and royalties recognized from licensees.",
"source": "tutorial assumption",
"value": 0.04
},
"licensed_revenue0": {
"as_of": "2025-09-28",
"rationale": "Revenue recognized by Starbucks; excludes licensees' retail sales.",
"source": "sources/reported.csv; FY2025 consolidated licensed-store revenue",
"value": 4350.4
},
"operating_margin": {
"end": 0.14,
"rationale": "Hypothetical margin recovery after store labor, rent, ingredients, overhead, depreciation, and equity compensation.",
"source": "tutorial assumption",
"start": 0.1
},
"other_growth": {
"rationale": "Growth in the consolidated other-revenue category.",
"source": "tutorial assumption",
"value": 0.04
},
"other_revenue0": {
"as_of": "2025-09-28",
"rationale": "Consolidated revenue category, not the Channel Development segment total.",
"source": "sources/reported.csv; FY2025 consolidated other revenue",
"value": 2089.2
},
"revenue0": {
"as_of": "2025-09-28",
"rationale": "Starting point for incremental working-capital investment.",
"source": "sources/reported.csv; FY2025 consolidated total net revenue",
"value": 37184.4
},
"tax_rate": {
"rationale": "Normalized tax on positive operating income.",
"source": "tutorial assumption",
"value": 0.25
},
"ticket_growth": {
"rationale": "Annual average-ticket growth from price and mix, with no automatic demand elasticity.",
"source": "tutorial assumption",
"value": 0.02
},
"traffic_growth": {
"end": 0.03,
"rationale": "Improving customer visits; applied as a simplified company-operated revenue driver.",
"source": "tutorial assumption",
"start": 0.01
}
},
"assumptions_file": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks/params.yaml",
"comparison": [
{
"equity": 45448.04284986929,
"ev": 58063.2428498693,
"ok": true,
"per_share": 39.97540931468844,
"scenario": "base",
"terminal_weight": 0.7882779025537872
},
{
"equity": 24040.590729058607,
"ev": 36655.79072905861,
"ok": true,
"per_share": 21.14573905273868,
"scenario": "bear",
"terminal_weight": 0.7756749526001264
},
{
"equity": 59462.906243614736,
"ev": 72078.10624361473,
"ok": true,
"per_share": 52.30267063384179,
"scenario": "bull",
"terminal_weight": 0.7859566218080818
}
],
"finding_warnings": [],
"journal": [
{
"finding": "Flat traffic reduces modeled value by $3.42 per share with ticket, capacity, and margin assumptions fixed.",
"id": "exp-001",
"question": "What if customer visits do not recover?",
"stale": false
}
],
"replay": {
"current": {
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
},
"id": "exp-001",
"ok": true,
"recorded": {
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
},
"status": "HOLDS"
},
"selected_experiment": "exp-001",
"trial": {
"attribution": [
{
"delta": -3.418933698299952,
"key": "traffic_growth",
"metadata": {
"rationale": "Hold visits flat in all forecast years while retaining base ticket, capacity, and margin assumptions.",
"source": "tutorial experiment"
},
"section": "bindings"
}
],
"base_per_share": 39.97540931468844,
"gap": -3.418933698299952,
"interactions": 0.0,
"ok": true,
"trial_per_share": 36.55647561638849
},
"validation": {
"ok": true,
"scenarios": [
"base",
"bear",
"bull"
]
}
},
"fingerprint": "d28711564727a9cb3345b0a73aa9645b945fc0df9af46227361ab723f5d857f1",
"message": "Current experiment evidence is available. Generate the requested deliverable from the saved scenario.",
"next_steps": [
{
"argv": [
"/Users/johnhorton/tools/ep/burr/.venv/bin/python3",
"-m",
"burr",
"--json",
"-C",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks",
"-s",
"base",
"dashboard",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks",
"-o",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html",
"--receipt"
],
"command": "dashboard",
"cwd": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks",
"expected": "An output file and receipt matching the current model and file contents.",
"mutates": true,
"reason": "missing_output",
"requires_network": false,
"shell": "/Users/johnhorton/tools/ep/burr/.venv/bin/python3 -m burr --json -C /private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks -s base dashboard /private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks -o /private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html --receipt",
"writes": [
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html.burr.json"
]
}
],
"ok": true,
"protocol_version": "1",
"required_inputs": [],
"resume_argv": [
"/Users/johnhorton/tools/ep/burr/.venv/bin/python3",
"-m",
"burr",
"--json",
"-C",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks",
"-s",
"base",
"next",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/companies/starbucks",
"--deliverable",
"dashboard",
"--output",
"/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/artifacts/starbucks-base.html",
"--patch=/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks/patches/slower_traffic.yaml",
"--question=What if customer visits do not recover?"
],
"scenario": "base",
"state": "export",
"warnings": [],
"workspace": "/private/tmp/burr-json-walkthrough-hfi8kh9p/examples/starbucks"
}next validates every scenario, returns the selected assumptions and comparison, tries the supplied patch, and replays matching journal evidence. It then recommends one executable action or lists missing inputs. For a new belief, provide a patch and question, inspect evidence.trial, and supply --finding with the interpretation.
- InspectValidate facts, checks, and assumptions.
- ProbeEvaluate a belief in memory.
- RecordKeep the reviewed result in the journal.
- ExportProduce a current deliverable.
| Field | What the agent should do |
|---|---|
state | Distinguish repairs, missing inputs, recording, export, and completion. ok: true alone does not mean the model is ready. |
action.argv | Execute this argument array within the authorized task. Inspect mutates, writes, and expected. |
resume_argv | Rerun the same inspection after the action, preserving the question, patch, scenario, and requested deliverable. |
required_inputs | Supply information from task context or inspected evidence. Clarify with the principal when their intent is missing. |
complete | Model checks pass, the selected experiment is current and replays, and the requested artifact matches its receipt. Present the result and assess whether it answers the question. |
Choose --deliverable dashboard, csv, or excel, optionally with --output PATH. Export actions use --receipt to write a small companion file holding model fingerprints and the artifact hash. Modified or outdated outputs are regenerated; a stale experiment is reviewed and recorded afresh.
Use the commands returned by your own run. Captured JSON above contains paths from the documentation build. next writes nothing and has no hidden progress file. The exported forecast reflects the saved scenario; recording a trial does not apply it to the model.
See the full agent guide and repository agent instructions. The guide also ships inside the installed Python package.