Explain why your numbers moved.
OpenVariance is an open source FP&A tool for budget vs. actual analysis. Give it a company's numbers, and it tells you what changed, why it changed, and what it means for the rest of the year. It also produces Excel workbooks and dashboards you can hand to a CFO.
- Variance analysis. Compare actual results with a budget, a forecast, the prior period, or another scenario, line by line. Each line gets a dollar variance, a percent variance and a favorable/unfavorable flag, with materiality thresholds and department drill-down.
- Driver bridges that reconcile. It splits a miss into its causes: volume, mix, price, unit cost, headcount, pay rate and each spend line. It uses Shapley attribution, so the pieces always add up exactly to the total and don't depend on which driver you look at first.
- Three-statement forecasts. It builds a driver-based income statement, balance sheet and cash flow statement with base, upside and downside cases. It checks that every period balances and that cash ties, and it never forces a balance with a plug.
- Real public-company data. Type a ticker and it pulls quarterly statements from SEC EDGAR for free. It removes duplicate and restated values, turns year-to-date figures into quarters, derives Q4 from the annual report, and ties the balance sheet to the filed totals.
- Messy private-company files. It reads QuickBooks, Xero and NetSuite style exports, budget spreadsheets and GL dumps. It skips subtotals, handles "in thousands" and accounting number formats, suggests an account mapping with reasons, and ties the result back to the file's own totals.
- Excel output. Workbooks use live formulas, blue inputs and check cells that read 0, so a finance team can audit them. The test suite recalculates the exported model with an independent formula engine to prove it matches the Python engine.
- Built for AI agents. A local MCP server lets Claude, ChatGPT, Cursor and other agents use every feature. The engine does all the math, so an agent can't make up a number.
You need uv (or Python 3.10+ and pip).
uvx --from git+https://github.com/wavebyrd/openvariance openvariance demo --openThis runs September 2026 for Demo Co., a fictional software company. It prints the variance report and bridge, opens the dashboard, and writes three files: a variance workbook, a forecast model, and the dashboard.
Operating income bridge (drivers, Shapley)
Budget $1.19M
Software −$90.0K $303,200 vs $213,200
Price −$79.4K average price at actual mix: $447.51 vs $454.94
Headcount −$33.2K 124 vs 122 FTE-months (Engineering +2)
Volume +$22.0K 10,622 units vs 10,561
Mix +$16.0K unit share: Enterprise 4.8% vs 4.9%; Pro 40.5% vs 39.2%; ...
...
Actual $1.00M reconciles exactly
OpenVariance runs as a local MCP server. Your agent app starts it when it needs it. There's nothing to host, and your files stay on your computer. Numbers the tools return become part of your conversation with the AI provider, the same as pasting them into a chat.
Claude Code
claude mcp add openvariance -- uvx --from git+https://github.com/wavebyrd/openvariance openvariance mcpClaude Desktop, Cursor and other MCP clients
{
"mcpServers": {
"openvariance": {
"command": "uvx",
"args": ["--from", "git+https://github.com/wavebyrd/openvariance", "openvariance", "mcp"]
}
}
}Then ask something like "Load the demo and tell me why operating income missed budget in September," or "Here's our P&L export and budget. How did we do last month?" See docs/agents.md for the tool list and the rules the server gives agents.
# 1. See how a file will be read, and save suggested account mappings to review
openvariance inspect examples/demo_budget_2026.xlsx --write-mapping budget_map.json
# 2. Compare actuals with the budget, and write Excel and a dashboard
openvariance variance \
--actual examples/demo_pl_quickbooks_2026.csv \
--budget examples/demo_budget_2026.xlsx --baseline-mapping budget_map.json \
--period 2026-09 --excel september.xlsx --dashboard september.html --openOnly high-confidence mappings are applied automatically. Every other account is listed for you to confirm, and nothing is used until it maps and ties out. See docs/importing.md.
Add --actual-drivers and --baseline-drivers (units, prices, headcount and pay rates) to get a
driver bridge instead of a line-item bridge. Add --ytd for year to date.
SEC asks automated clients to identify themselves, so set a name and email once:
export OPENVARIANCE_SEC_USER_AGENT="Jane Doe jane@example.com"
openvariance sec CRWV # quarterly statements, $M
openvariance forecast --ticker CRWV --excel crwv_model.xlsxShort version below. Full detail and worked examples are in docs/methodology.md.
- Sign convention. Variance = (actual − baseline) × direction. Positive is always favorable. Revenue above budget is +, and costs above budget are −.
- Percent variance is variance ÷ |baseline|, so a shrinking loss reads as favorable. It shows
n/mwhen the baseline is zero. - Stocks vs. flows. Revenue and cash flows add up across periods. Balance sheet lines take the last period. Totals are always derived from their parts, never stored.
- Attribution. Shapley values are computed in exact rational arithmetic, then rounded to cents with the largest-remainder method, so the rounded bridge still ties to the cent.
- Missing data stays missing. A line with no data shows "—", not zero, and the reason is noted.
- No plugs. The forecast's cash comes from the cash flow statement. If an opening balance sheet doesn't balance, the gap is reported, not hidden.
from openvariance import compare, explain, demo
from openvariance.forecast import infer_assumptions, default_scenarios, run_scenarios
d = demo.load()
report = compare(d.actual, d.budget, ["2026-09"])
bridge = explain(d.budget_drivers["2026-09"], d.actual_drivers["2026-09"])
print(report.headline.impact, bridge.reconciles)
base = infer_assumptions(d.history).assumptions
results = run_scenarios(d.history, default_scenarios(base, 12), periods=12)src/openvariance/
accounts.py standard chart of accounts, sign conventions
dataset.py FinancialData: amounts by period, line, department
variance.py line-by-line comparison
attribution.py Shapley attribution and reconciling bridges
drivers.py volume/mix/price and headcount/rate driver model
forecast.py linked three-statement forecast and scenarios
sec.py SEC EDGAR loader and XBRL normalization
importers/ file inspection, account mapping, tie-outs
excel.py formula-driven workbooks
dashboard.py self-contained HTML dashboard
mcp_server.py tools for AI agents
cli.py the openvariance command
- No seasonality yet. Forecasts grow smoothly from the latest period, so a company with a big holiday quarter (Apple, retailers) gets a reasonable annual total but not the quarter-by-quarter shape.
- The importer has been tested on the formats in
examples/and the tests. Unusual exports (multi-row headers, merged department columns) may need converting to the standard format. - SEC tag coverage is broad but not universal. Banks and insurers report differently and aren't a good fit yet.
- Rolling forecasts with saved versions, and forecast accuracy tracking over time
- A GitHub Action that grades a public-company forecast against each new 10-Q
- Headcount planning (hires, start dates, raises) feeding payroll drivers
- Multi-level headers and more accounting-system presets
- A browser app on top of the same engine
Issues and pull requests are welcome. Start with CONTRIBUTING.md. The one rule that matters most: every number has to tie, and every new calculation needs a test that proves it.
MIT. See LICENSE. Demo Co. is fictional. OpenVariance is a tool for analysis, not financial or investment advice.
