cost-benefit
SkillCommerce & financeThis skill lets your AI run a full cost-benefit analysis on a project, policy, or investment you describe. It produces economic and financial net present value side by side, along with benefit-cost ratios, sensitivity checks, and a headline verdict. The analysis adjusts for optimism bias and can value wellbeing outcomes, so you get numbers you can compare across options.
Available today. Use it from your connected AI after setup.
No other account needed.
Add the skill, then describe the options, costs, and benefits you want assessed. Your AI will run the analysis and return the results with a headline verdict.
Then ask your AI: use the cost-benefit skill
What your AI can do with it
- Produce economic and financial NPV side by side
- Calculate benefit-cost ratios for each option
- Adjust results for optimism bias and marginal excess tax burden
- Value health and wellbeing outcomes using WELLBY, QALY, or VPF
- Run sensitivity checks and report switching values
- Compare options with unequal lifetimes and finish with a headline verdict
What this skill tells your AI
The instructions your AI receives, as published by brycewang-stanford/auto-empirical-research-skills in skills/58-charlescoverdale-econstack/cost-benefit/SKILL.md and read by ahel’s review.
Only stop to ask the user when: project description is missing, there are fewer than 2 options (including do-nothing), or cost / benefit magnitudes cannot be estimated. Never stop to ask about: perspective, additionality rates, stakeholder tagging, sensitivity method, output filename, or formatting. Pick sensible defaults and keep moving.
Before starting, run this silently. If it outputs UPDATE_AVAILABLE, tell the user:
"A new version of econstack is available. Run cd ~/.claude/skills/econstack && git pull to update."
Then continue with the skill normally.
~/.claude/skills/econstack/bin/econstack-update-check 2>/dev/null || true
After the update check, run this silently to load prior learnings for this project:
eval "$(~/.claude/skills/econstack/bin/econstack-slug)"
~/.claude/skills/econstack/bin/econstack-learnings-read --limit 3 2>/dev/null || true
If learnings are found, apply them. When a prior learning influences a decision, note: "Prior learning applied: [key]".
Capturing new learnings: After completing this skill, log new insights via:
~/.claude/skills/econstack/bin/econstack-learnings-log '{"skill":"...","type":"...","key":"...","insight":"...","confidence":N,"source":"observed|user-stated|inferred"}'
Types: framework (preferred appraisal framework), parameter (custom overrides), data-source (preferred data), output (past report references), operational (tool/env quirks), preference (formatting/style). Confidence: 9-10 observed/stated, 6-8 strong inference, 4-5 weak. User-stated never decays; observed/inferred lose 1 point per 30 days. All data stored locally. Nothing transmitted.
After the update check, verify the parameter database is available and check staleness:
PARAMS_DIR="$HOME/econstack-data/parameters"
if [ -d "$PARAMS_DIR" ]; then
PARAM_COUNT=$(find "$PARAMS_DIR" -name "*.json" 2>/dev/null | wc -l | tr -d ' ')
echo "PARAMS: $PARAM_COUNT files loaded from $PARAMS_DIR"
# Check for stale files (last_verified > 2 years ago)
STALE=$(find "$PARAMS_DIR" -name "*.json" -mtime +730 2>/dev/null | wc -l | tr -d ' ')
if [ "$STALE" -gt 0 ]; then
echo "PARAMS_WARNING: $STALE file(s) not updated in 2+ years. Run: cd ~/econstack-data && git pull"
fi
else
echo "PARAMS: not found. Using built-in defaults. For full parameter support: git clone https://github.com/charlescoverdale/econstack-data.git ~/econstack-data"
fi
If PARAMS_WARNING appears, tell the user which parameter files may be stale and recommend updating. Continue with the skill normally using whatever parameters are available.
Safety rules for this skill:
-
Parameter database is read-only. Never write to, modify, or delete files in
~/econstack-data/parameters/. These are shared, versioned parameters maintained separately. If a parameter needs updating, tell the user to update the econstack-data repo. -
Confirm before overwriting. Before writing an output file, check if a file with the same name already exists. If it does, ask the user: "A file named [filename] already exists. Overwrite it, or save with a new name?" Do not silently overwrite.
At the end of every skill run, report one of these statuses:
- DONE: Analysis complete, output generated, all sections finished.
- DONE_WITH_CONCERNS: Output generated but with caveats (e.g., data gaps, assumptions that need review, sections below expected depth).
- BLOCKED: Cannot proceed (e.g., missing critical input, parameter database unavailable, framework not supported).
- NEEDS_CONTEXT: Need more information from the user before continuing.
Format: STATUS: [status] | [one-line reason]
/cost-benefit: Cost-Benefit Analysis
Produces a Green Book-style economic case (NPV, BCR, optimism bias, sensitivity) alongside a parallel financial case (cash flow to the sponsor, Financial NPV, payback, DSCR if debt is involved), with a one-line headline verdict telling you whether the project is socially worthwhile and financially self-sustaining.
/longlist = "Brainstorm benefits and costs"
↓
/cost-benefit = "Now monetise and compute NPV" (this skill)
↓
/business-case = "Wrap in the Five Case Model"
Default output: one clean deliverable with headline verdict, options, costs, benefits, economic case, financial case, sensitivity, and recommendation. Power users can grab just one section via --section.
Arguments
/cost-benefit [project description] [options]
Examples:
/cost-benefit "New secondary school in Leeds, GBP 40m capex, 60-year appraisal"
/cost-benefit --from longlist-italy-city-greening-2026-04-10.md
/cost-benefit "Rural water project, Indonesia" --framework adb
/cost-benefit "Victorian level crossing removal" --framework au-vic
Options:
--framework <name>:uk-gb(default),eu-brg,wb,adb, orau-vic. Auto-detected from context if not set.--from <file.md>: Import project, options, costs, benefits, and Cash flow tags from a/longlistmarkdown file. Skips the interactive entry.--sponsor <type>:government(default),private,blended,philanthropic. Drives the financial case discount rate. Carried through from the longlist if--fromis used.--section <name>: Emit only one sub-component. Options:full(default),headline,costs,benefits,economic,financial,sensitivity,stakeholder,validation. Combinable with commas.--format <type>: Output format(s).markdown(default, always generated),xlsx,word,pptx,pdf, orall. Comma-separate for multiple.--distributional: Apply Green Book Annex A4 iso-elastic welfare weights (eta = 1.3, reference = median equivalised income). Silent if not set.--stage <name>:soc(Strategic Outline Case),obc(Outline Business Case, default),fbc(Full Business Case). Drives the optimism bias uplift.--ob-mitigation <pct>: Optimism bias mitigation factor in[0, 1]. Default0. Use0.3to0.5once an active risk register is in place. Greenbook:gb_apply_ob(mitigation = ...).--price-base <year>: Price base year for real-terms rebasing. Default = current calendar year. All cash inputs are re-based viagb_rebase()before discounting. Greenbook:gb_deflator()/gb_real()/gb_rebase().--carbon-scenario <name>:low/central(default) /high. Pulls from the consolidated DESNZ Nov-2023 series. Greenbook:gb_carbon_value().--schedule <name>:standard(default),health(1.5% baseline for QALY/WELLBY-monetised consequences only),catastrophic(3.0% for projects where catastrophic risk dominates). Greenbook:gb_stpr(schedule = ...).--horizon <years>: Override the default appraisal period (60 infrastructure / 30 programmes / 10 IT). For horizons > 30 years the kinked STPR schedule kicks in automatically.--cea: Cost-effectiveness mode. When monetisation of the dominant benefit is impossible (low-monetisability flag from /longlist), replaces BCR with cost per output unit. Greenbook:gb_cost_per_unit().--audit/--no-audit: Auto-run /econ-audit on the produced markdown at the end. Default:--audit.--validate-only: Run the validation gate against the longlist + parameters and exit with a structured report. No NPV produced. Useful in CI.
Supported frameworks
| Flag | Discount rate | Optimism bias | Carbon price | VPF / VSL | VTTS | METB | Wellbeing |
|---|---|---|---|---|---|---|---|
uk-gb | Kinked STPR: 3.5% y0-30, 3.0% y31-75, 2.5% y76-125, 2.0% y126-200, 1.5% y201-300 | Mott MacDonald 2002 by project type, with --ob-mitigation | DESNZ Nov-2023 single consolidated series, low/central/high | DfT TAG v2.03FC anchor 2023 = GBP 2.474m WTP, +2% real per capita growth | DfT TAG Data Book | 20% on tax-financed costs (mandatory) | WELLBY GBP 13k (2019 prices); QALY GBP 70k (2024 prices, DHSC) |
eu-brg | 3% advanced / 5% convergence (flat) | Not used; scenario sensitivity | EU ETS + EC shadow | EUR 3.6m (DG MOVE) | EU TEN-T values | n/a | n/a |
wb | 6% (country-specific ERR) | Not used; scenario sensitivity | WB shadow (USD 40-80/tCO2e, rising to 50-100 by 2030) | By country income group | Local shadow wages | n/a | n/a |
adb | 9% EIRR (6% for climate / health / education per 2017 revision) | Not used; switching values mandatory | ADB shadow (USD 36.30+/tCO2e) | Country-specific | ADB shadow wages | n/a | n/a |
au-vic | 4% infrastructure / 7% non-infrastructure (flat) | Vic DTF ILG risk allowance, P50 + P90 | Australian shadow carbon | AUD 5.4m | ATAP PV5 | n/a | n/a |
Auto-detection rules:
- "HVHR", "Victorian", "Melbourne", AUD context →
au-vic - "ADB", Asian DMC context →
adb - "World Bank", "IBRD", "IDA" →
wb - "EU", "regulation", "directive", EUR context →
eu-brg - Everything else →
uk-gb
Instructions
Step 0: Detect computation backend (silent)
Check whether the greenbook R package is reachable through the bridge script:
GB_VERSION="$(echo '{"action":"version"}' | ~/.claude/skills/econstack/bin/econstack-greenbook 2>/dev/null)"
GB_OK="$(echo "$GB_VERSION" | python3 -c 'import sys, json; d=json.loads(sys.stdin.read() or "{}"); print("yes" if d.get("ok") else "no")' 2>/dev/null || echo "no")"
- If
GB_OK=yes: setBACKEND=greenbook. Use the bridge for NPV / BCR / discount factors / OB / METB / VPF / QALY / WELLBY / EANC / carbon. Stash thedata_versionsarray for the KEY NUMBERS block. All numerical claims should matchgb_economic_case()to within ±0.01. - If
GB_OK=no: setBACKEND=skill. Compute internally using the formulas below. Add a footnote to the output: "Computed without greenbook backend; install withinstall.packages('greenbook')or setGREENBOOK_DEV_PATHfor full reproducibility and vintage stamping."
Do not narrate the backend choice to the user unless they ask. Continue with Step 1.
Step 1: Load project, options, costs, and benefits
If --from <file.md> specified: read the longlist markdown file and parse:
- Project name and counterfactual from the header block
- Framework and sponsor from the header block (default if missing)
- Benefits table: for each item, capture Name, Description, Materiality, Cash flow tag, Quantification method, Monetisation method
- Costs table: same six columns
- Excluded section (note for reference but do not include in NPV)
Skip the interactive entry and proceed to Step 2.
Otherwise: ask the user in ONE AskUserQuestion batch:
- Project: one or two sentences (what, where, why).
- Options: the alternatives being compared. Must include "Do nothing" (the counterfactual). Typically 3 options: do nothing, do minimum, preferred.
- Costs: total capital (phased over how many years) and annual operating cost. If an estimate doesn't exist, ask for a range and mark the field as "Estimated".
- Benefits: annual benefit at maturity, plus benefit type (e.g. "health QALYs", "user time savings", "avoided flood damage").
Do NOT ask perspective, referent group, distributional weights, sensitivity method, appraisal period, optimism bias rate, or discount rate. Detect sector from the description. Default:
- Appraisal period: 60 years (infrastructure), 30 years (programmes), 10 years (IT). Override with
--horizon. - Optimism bias: HMT supplementary Table 1 for the detected project type and stage. Mitigation factor 0 unless
--ob-mitigationis set. - Additionality: 20% deadweight, 25% displacement, 10% leakage (net factor 0.54) unless user provides different values.
- Perspective: social / national for government sponsors; investor for private sponsors.
- Referent group: all residents of the host country (or region for au-vic).
- Price base year: current calendar year unless
--price-baseoverrides. Real-terms rebasing applied to all cash inputs before discounting (uk-gb only; greenbookgb_rebase()). - Schedule:
standardfor the main appraisal. Thehealthschedule is applied only to QALY / WELLBY benefit lines; do not apply 1.5% to monetary or non-health benefits.
Step 2: Compute (silent)
Run the computations internally. Do not narrate; show results in the output. When BACKEND=greenbook, prefer the bridge over inline math — call econstack-greenbook with action appraise (or specific action for sub-computations) and read NPV / BCR / OB-adjusted streams / METB / discount factors back from JSON.
2.1 Real-terms rebasing (uk-gb only)
If any cash input is in a price base year other than --price-base:
rebased_value = gb_rebase(value, from = source_year, to = price_base_year)
# bridge:
echo '{"action":"appraise", ..., "base_year": <price_base>}' | econstack-greenbook
Greenbook bundles HMT's December-2025 GDP deflator. Outputs cite the deflator vintage in the KEY NUMBERS block. For non-uk-gb frameworks, the user supplies values already in the chosen base year.
2.2 Discount factors
When BACKEND=greenbook (uk-gb): factors come back from the appraise action; for ad-hoc factor lookup use action discount_factor. Greenbook schedules: standard (default), health (1.5% baseline; apply only to QALY/WELLBY rows), catastrophic (3.0%).
When BACKEND=skill (uk-gb), compute cumulatively across the kinked bands:
df(0) = 1.0
For t = 1 to horizon:
r = STPR(t): 3.5% (1-30), 3.0% (31-75), 2.5% (76-125), 2.0% (126-200), 1.5% (201-300)
df(t) = df(t-1) / (1 + r)
CRITICAL: cumulative compounding only. Never apply the lower rate from year 0.
For eu-brg, wb, adb, au-vic (flat rate): df(t) = 1 / (1 + r)^t.
2.3 Capital cost phasing (S-curve)
construction_years > 1: apply S-curve weights
5-year: [0.10, 0.20, 0.30, 0.25, 0.15]
3-year: [0.20, 0.50, 0.30]
construction_years == 1: all capex in year 0.
2.4 Optimism bias with mitigation (uk-gb)
Lookup the project category and apply the percentage from the Mott MacDonald 2002 table (greenbook: gb_optimism_bias() then gb_apply_ob(..., mitigation = ...)). Mitigation reduces the uplift proportionally:
ob_effective = ob_raw * (1 - mitigation)
adjusted_capex = capex * (1 + ob_effective)
Default mitigation = 0. Set --ob-mitigation 0.3 to 0.5 once an active risk register is in place. Typical raw uplifts: 24-44% at SOC stage, 12-24% at OBC, 3-10% at FBC. No optimism bias on opex unless the user explicitly states a duration uplift.
For eu-brg, wb, adb: skip OB; rely on scenario sensitivity. For au-vic: use Vic DTF ILG P50/P90 in place of OB.
2.5 METB (Marginal Excess Tax Burden) — uk-gb mandatory
For tax-financed costs (any cost line where the sponsor is government or where the longlist tag indicates public funding), apply 20% METB after optimism bias. Greenbook: gb_metb(rate = 0.20). Bridge action: metb.
costs_with_metb = costs_after_ob * (1 + 0.20)
This is mandatory under Green Book 2022 §5.36. Skip METB only when sponsor is private or philanthropic (no distortion from raising the funds). Show as a dedicated row in Table 2 (Costs).
2.6 Wellbeing valuation (WELLBY / QALY / VPF)
When a benefit row's quantification method is one of wellby, qaly, or vpf, route the monetisation through the dedicated greenbook function rather than generic prices. These rows are also discounted on the health schedule (1.5%) when --schedule is not overridden.
WELLBY: echo '{"action":"wellby","life_satisfaction_change":0.5,"persons":1000,"years":3}' | bridge
QALY: echo '{"action":"qaly","qalys":120,"scenario":"dhsc","base_year":2024}' | bridge
VPF: echo '{"action":"vpf","year":2026,"series":"central"}' | bridge
Vintage and base year flow through to the KEY NUMBERS block.
2.7 Benefit ramp-up
linear ramp over N years:
benefit(i) = full_annual_benefit * (i / N) for i = 1..N
post-ramp:
benefit(i > N) = full_annual_benefit * (1 + growth_rate)^(i - N)
Default ramp: 3 years for infrastructure, 1 year for programmes. growth_rate defaults to 0; override only for programmes with documented per-capita growth (e.g. transport demand).
2.8 Carbon valuation (DESNZ Nov-2023 single consolidated series)
For uk-gb, use the consolidated central series (DESNZ Nov-2023 collapsed the historical traded / non-traded split). Override with --carbon-scenario {low|central|high}. Bridge action: carbon_npv.
phases: 'embodied' (construction years, always a cost) and 'operational' (in-use)
For each year t:
carbon_value(t) = tCO2e(t) * carbon_price(t, scenario)
NOT adjusted for additionality (global externality).
For other frameworks: EU ETS + EC shadow (eu-brg); WB shadow USD 40-80 rising to 50-100 by 2030 (wb); ADB USD 36.30+ (adb); Australian shadow carbon (au-vic).
2.9 Do Nothing baseline
If the counterfactual has costs (deterioration, emergency repairs, rising congestion), compute their PV. For intervention options:
NPV = PV_benefits + PV_avoided_do_nothing_costs - PV_intervention_costs
Avoided counterfactual costs count as benefits of the intervention.
2.10 Additionality
Apply to all monetised benefits except: carbon (global externality), WELLBY/QALY/VPF (already net of relevant counterfactuals when computed correctly), tax-revenue items (excluded as transfers in social CBA).
adjusted_benefit = gross_benefit * (1 - deadweight) * (1 - displacement) * (1 - leakage)
2.11 Present values and economic-case metrics
PV_costs = sum over t of [adjusted_cost(t) * df(t)]
PV_benefits = sum over t of [adjusted_benefit(t) * df(t)]
Economic_NPV = PV_benefits - PV_costs
Economic_BCR = PV_benefits / PV_costs
VfM category (uk-gb only):
BCR < 1.0 -> Poor
1.0 - 1.5 -> Low
1.5 - 2.0 -> Medium
2.0 - 4.0 -> High
> 4.0 -> Very High
2.12 Distributional weighting (--distributional)
When set, weight cashflows by stakeholder income relative to median equivalised income, eta = 1.3 (Green Book Annex A4 iso-elastic). Bridge action: dist_weighted_npv. Add Table 8 (Distributionally weighted NPV by stakeholder group) to the output.
echo '{"action":"dist_weighted_npv","cashflow":[...],"recipient_income":[...],"eta":1.3}' | bridge
2.13 Cost-effectiveness fallback (--cea)
If the dominant benefit is flagged as low-monetisability on the longlist (or --cea is set), skip BCR and report cost per output unit. Greenbook: gb_cost_per_unit(). The economic NPV is still computed; only the BCR row is suppressed and replaced with cost per [unit].
Step 3: Financial case (silent)
If the longlist has Cash flow tags (cash_in / cash_out / non_cash), compute the financial case using only the cash items. Non-cash items (heat mortality avoided, WELLBYs, biodiversity, air quality, carbon unless credits are sold) are excluded entirely.
If the project was entered interactively without cash tags, auto-tag:
- Capital costs → cash_out
- Operating costs → cash_out
- User fees, tariffs, grants → cash_in
- Avoided municipal or sponsor expenditure → cash_in
- Everything else → non_cash
Financial discount rate by sponsor type (flat, not declining):
- government: 4.5% real
- private: 10% real (ask for hurdle rate if stated)
- blended: weighted average of sources by capex share
- philanthropic: 0% (grants, not repayable)
Financial computations:
For each year t:
Cash_inflow(t) = sum of cash_in items in year t
Cash_outflow(t) = sum of cash_out items in year t
Net_cash_flow(t) = Cash_inflow(t) - Cash_outflow(t)
Cumulative_cash_flow(t) = Cumulative_cash_flow(t-1) + Net_cash_flow(t)
Financial_NPV = sum over t of [Net_cash_flow(t) / (1 + r_financial)^t]
Total_funding_requirement = max over t of [-Cumulative_cash_flow(t)]
(the peak financing need: how much money the sponsor must commit before any net inflow)
Payback_period = smallest t such that Cumulative_cash_flow(t) >= 0
(if never, report "Does not pay back within appraisal period")
Financial_IRR = the r_financial value that makes Financial_NPV = 0
(compute numerically; report "Undefined" if no real positive root)
DSCR (only if project involves debt): if the user or longlist specifies debt parameters, compute DSCR per year of the debt term:
For each year t in the debt term:
Operating_cash_flow_for_debt(t) = Cash_inflow(t) - (Cash_outflow(t) excluding capex and debt service)
Debt_service(t) = scheduled interest + scheduled principal per repayment profile
DSCR(t) = Operating_cash_flow_for_debt(t) / Debt_service(t)
Minimum_DSCR = min over debt term
Average_DSCR = mean over debt term
Flag if minimum DSCR < 1.2: "Minimum DSCR of [val] is below the typical 1.2x lender covenant. The project cannot support this debt structure. Reduce gearing, extend tenor, or find non-debt funding."
Step 4: Headline verdict (silent)
economic_sign = "positive" if Economic_NPV > 0 else "negative"
financial_sign = "positive" if Financial_NPV > 0 else "negative"
If economic positive AND financial positive:
"Both cases positive. Project is socially worthwhile AND financially self-sustaining. Viable for commercial or blended funding."
If economic positive AND financial negative:
"Economic case positive, financial case negative. Project is socially worthwhile but requires public subsidy, grant, or philanthropic backing. Not viable for commercial debt on standalone cash flows."
If economic negative AND financial positive:
"Economic case negative, financial case positive. Project generates cash for the sponsor but destroys social value (often through displacement or unpriced external costs). Reconsider before proceeding."
If economic negative AND financial negative:
"Both cases negative. Do not proceed on these numbers."
Step 5: Sensitivity (silent)
Run four tests and summarise in one paragraph:
- Scenario sensitivity: Pessimistic (benefits -20%, costs +20%), Central, Optimistic (benefits +20%, costs -20%). Compute NPV and BCR for each.
- Switching values: For the top 2-3 variables, the percentage change that makes NPV = 0. Interpret correctly based on NPV sign.
- Tornado test: For the top 5 variables by PV magnitude, ±20% shifts holding other variables central. Report the widest-range variable.
- Discount rate sensitivity: Test the central framework rate plus one higher and one lower rate.
Report all four in one paragraph. No multi-table sensitivity section.
EANC for unequal-life options: if the options have different appraisal periods (e.g. 30-year vs 60-year), compute the equivalent annual net cost via greenbook gb_eanc() (bridge action: eanc) and add an extra row to Table 4. Without EANC, NPVs across options of unequal life are not directly comparable; flag this explicitly if EANC cannot be computed (e.g. BACKEND=skill).
echo '{"action":"eanc","npv":42.5,"years":60,"schedule":"standard"}' | bridge
Step 6: Referent group identity check (silent, uk-gb and au-vic)
For uk-gb and au-vic projects with a clear referent group, compute:
Efficiency_NPV = PV_all_benefits - PV_all_costs
Referent_Group_NPV = PV_referent_benefits - PV_referent_costs
Non_Referent_NPV = PV_non_referent_benefits - PV_non_referent_costs
Identity: Efficiency_NPV = Referent_Group_NPV + Non_Referent_NPV
If the identity does not hold, flag a tagging error. If Efficiency NPV is positive but Referent Group NPV is negative, note prominently that value is leaking outside the referent group.
Skip for wb and adb (distributional analysis by income decile replaces referent group for those frameworks).
Step 6.5: Validation gate (silent, abort on failure)
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 4k
- Forks
- 476
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
cost-benefit- Source
- github.com/brycewang-stanford/auto-empirical-research-skills