{
  "markdown": "# opentax-engine\n\n**A US tax calculator that shows its work — and can prove it.**\n\nThree ideas, that's the whole project:\n\n1. **Ask** it a tax question with plain facts (`--wages 50000`).\n2. It answers with a **proof**: every rule it applied, with the law it came from (`26 U.S.C. § 63(c)` …), every assumption it made.\n3. Anyone can **verify** that proof offline. If it can't derive an answer from its encoded rules, it refuses — it never guesses.\n\nOpen source (AGPL-3.0, with commercial licenses available), exact to the cent (no floating point), built to be extended.\n\n## Try it\n\n```bash\npnpm install && pnpm build\npnpm opentax eval --status mfj --wages 120000 --kids 2\n```\n\n```\nMarried filing jointly · tax year 2026\n\n  Income                  $120,000.00\n  − Deductions             $32,200.00   (standard deduction)\n  = Taxable income         $87,800.00\n  Tax before credits       $10,043.00\n  − Credits                 $4,400.00   (child tax credit)\n  ─────────────────────────────────────\n  You owe                   $5,643.00   (4.7% of income)\n\nus.federal.net_tax  $5,643.00\n├─ us.federal.income_tax_after_credits  $5,643.00     [26 U.S.C. § 26(a)]\n│  ├─ us.federal.income_tax_before_credits.tax_table  $10,043.00   [26 U.S.C. § 3(a); 2026 Tax Table]\n│  │  └─ us.federal.taxable_income  $87,800.00        [26 U.S.C. § 63(b)]\n│  │     ├─ us.federal.agi  $120,000.00               [26 U.S.C. § 62(a)]\n│  │     │  ├─ fact wages = $120,000.00\n│  │     │  └─ assumed taxableInterest = $0.00 (default)\n│  │     └─ us.federal.standard_deduction  $32,200.00 [26 U.S.C. § 63(c); Rev. Proc. 2025-32]\n│  └─ us.federal.ctc  $4,400.00                       [26 U.S.C. § 24; Schedule 8812]\n⋮  (abridged: the full tree cites every node and logs every default)\n\nAssumptions (77): every default was $0/none — pass the real facts if your situation differs\ncorpus @invaro/opentax-corpus-us-federal@0.37.0  sha256:6c422520ead11760…\n```\n\nIt answers under **the law in force on the date you ask about** — `--as-of` defaults to today; pass `--as-of 2025-12-31` and the same facts derive under TY2025 rules instead: the same household owes $5,746.00 under TY2025's $31,500 standard deduction, cited to the other Rev. Proc.\n\nMoney is written in **dollars** (`50000`, `\"$50,000\"`, `\"1234.56\"`). Not sure what inputs exist? `pnpm opentax facts` lists them all. More facts than fit in flags? Use a JSON file: `--facts examples/mfj_120k_2kids.json`.\n\n**Or skip the terminal entirely** — the engine is pure TypeScript with zero platform\ndependencies (even SHA-256 is hand-written pure JS, so hashing is bit-identical in Node\nand the browser), so the whole thing runs in a browser:\n\n```bash\npnpm -F @invaro/opentax-playground build && open packages/playground/dist/index.html\n```\n\nOne ~500 KiB self-contained HTML file: engine + full rule corpus + verifier, no server,\nno network, works from `file://`. Compute, read the proof tree, download the proof —\nthen paste it into the **Verify** tab and watch your own browser re-derive every step\n(alter one byte and it says exactly what broke). Same corpus Merkle root the CLI prints.\n\nSave a proof, verify a proof:\n\n```bash\npnpm opentax eval --status single --wages 50000 --proof proof.json\npnpm opentax verify proof.json     # ✓ VERIFIED — re-derived independently, every step matches\n```\n\nChange one byte of the proof — or one rule — and `verify` fails and says exactly what broke: the file was altered, the corpus is a different version, or a step doesn't re-derive.\n\nDon't want to trust our verifier? The format is fully specified — canonical JSON, hashing, Merkle construction, node semantics, test vectors — in **[docs/PROOF-FORMAT.md](docs/PROOF-FORMAT.md)**, so you can write an independent checker in whatever language you trust.\n\n## When it can't answer\n\nIt tells you, in one consistent shape, and never makes something up:\n\n| exit code | error code | meaning | what to do |\n|---|---|---|---|\n| 2 | `NEEDS_FACTS` | you didn't give it enough | it lists every missing fact and the exact flag to add |\n| 3 | `UNHANDLED_ENUM_CASE`, `NO_APPLICABLE_RULE`, `NOT_MODELED` | the rules for this case/date aren't encoded yet, or the law is deliberately out of scope | see coverage below; add them (it's just data) |\n| 1 | anything else | bad input, failed verification | read the message |\n\nEvery error is `{ code, message, data, hint }` — same shape for humans, scripts, and AI agents.\n\n## The AI-agent use case: never let a model invent a tax number again\n\nLLMs *will* confidently produce wrong tax figures — most training data predates the OBBBA entirely. Two integration patterns fix that:\n\n**1. Oracle pattern (MCP)** — the model never computes; it calls the engine:\n\n```bash\nclaude mcp add opentax -- npx -y @invaro/opentax\n```\n\nNo install at all if you prefer hosted: the same server runs at `https://opentax.invaro.ai/mcp`, and it's on the official MCP registry as `io.github.Invaro/opentax`.\n\nFifteen tools. Full returns: `compute_return` (the Form 1040 line set), `calculate_tax`, `calculate_business_tax` (1120), `calculate_fiduciary_tax` (1041), `compute_state_return` (CA 540, IL-1040, NY IT-201, VA 760, PA-40, NJ-1040, OH IT 1040, NC D-400, GA 500). Determinations: `determine_dependent`, `is_tipped_occupation` (the full Treasury occupation list as data). The oracle surface: `verify_tax_claim`, `verify_fact` (fact-check any claimed dollar amount — \"CTC is $2,000/child\" → *refuted, it's $2,200, § 24(h)(2) as amended by OBBBA*), `lookup_tax_parameter`, `search_tax_rules`, `list_input_facts`, `explain_rule`, `find_tax_cliffs`, `compare_filing_statuses`. Every response carries its assumptions and the corpus hash, so the agent can quote the law and the user can re-verify.\n\nOn **TaxCalcBench** (50 full TY2025 returns, federal + state), a cold Claude Sonnet agent with this MCP server scores **48/50 exact under strict scoring (96%)** and 98.2% of all scored lines, one attempt per case, graded by the benchmark's own evaluator. The benchmark's paper puts the best frontier model on its own at ~33%. Details in [docs/METHODOLOGY.md](docs/METHODOLOGY.md).\n\n**2. Guardrail pattern (`opentax check`)** — the model answers, your harness gates it:\n\n```bash\n$ opentax check --status mfj --wages 120000 --kids 2 --expect 6600\n✗ REFUTED   claimed $6,600.00, but the law derives $5,643.00 (off by $957.00)\n$ echo $?\n1        # wire this into your eval suite / response pipeline\n```\n\nExit 0 = verified, 1 = refuted (with the correct value), 2 = the claim can't be checked without more facts. A one-line post-processing step turns any tax-adjacent agent from \"plausible\" to \"provable.\"\n\nPlus the general contract: add `--json` to **any** command — single JSON object, `ok: true|false`, stable error codes and exit codes, no ANSI. Full agent docs in **[AGENTS.md](AGENTS.md)**.\n\n## What's covered today (tax years 2025 & 2026, current law)\n\n**Every W-2 household, all five filing statuses, refunds included.** 276 rules, 295 documented input facts, 329 golden fixtures. The default answer is **net tax** — negative means the government owes you.\n\n- **Individual (Form 1040)** — brackets, standard & itemized deductions (Schedule A with the OBBBA SALT cap), capital gains & qualified dividends with full § 1222 Schedule D netting, AMT, Social Security taxation, retirement income incl. the § 72(d) pension Simplified Method, residential rental income with § 168 depreciation, SE tax, NIIT & Additional Medicare, kiddie tax, capital losses, HSA, student-loan interest, IRA deduction, foreign earned income exclusion.\n- **Credits** — CTC/ACTC + ODC, EITC (all child counts), education (AOTC/LLC), child & dependent care, saver's, adoption, premium tax credit (2025 no-cliff / 2026 cliff) — plus proof-backed dependent determination.\n- **OBBBA, both years** — tips & overtime deductions (with the 71-occupation eligibility list), senior deduction, car-loan interest, non-itemizer charitable, § 68 haircut, and the 2026 parameter shifts throughout.\n- **Business & corporate (Form 1120)** — QBI § 199A full mechanics, SEP/solo-401(k), § 179 + bonus + R&D expensing + § 163(j), K-1 pass-through, entity classification, flat 21% with charitable/DRD/NOL mechanics, BEAT, corporate FTC, § 250, penalty taxes, QSBS, buyback excise, corporate estimates.\n- **Estates & trusts (Form 1041)**, household employment (Schedule H), farmers & fishermen, estimated-tax safe harbors + annualized installments, withholding checkup.\n- **State (30 states, in the same corpus)** — deep rule packs for IL, VA, CA, NY, PA, NJ, OH, NC, and GA with printed-form composers (via the MCP server's `compute_state_return` and `opentax state`): CalEITC/YCTC/renter's credit and CA AMT, NYC resident tax + Yonkers surcharge + IT-214, VA age deduction and Spouse Tax Adjustment worksheets, IL EITC and use tax, PA's eight-class netting, Schedule SP Tax Forgiveness, and the Working Pennsylvanians Tax Credit, NJ's category netting with the printed Tax Table, pension-exclusion cliff, property-tax deduction-vs-credit worksheet, NJEITC (incl. the flat $260 age-decoupled credit), CTC and CDCC, OH's HB 96 brackets, MAGI-tiered exemptions, Business Income Deduction, and the joint filing / retirement / senior / EIC / child-care credits, NC's AGI-tiered child deduction, $20,000 mortgage+property itemized cap, and Bailey/military exclusions, and GA's per-spouse retirement exclusion, Low Income Credit table, and the HB 136 50% CDCC. Flat-rate rules for 10 more states; the nine no-income-tax states answer $0 with a citation.\n- **Out of scope refuses loudly** — consolidated returns, REIT/RIC, fiscal-year returns, CAMT: a named refusal, never a silent wrong answer.\n\nThe line-by-line inventory (every rule, its statute, its validity window) is queryable, not prose: `pnpm opentax corpus list`.\n\n**Is it correct?** Exact bigint-cents math — floats never enter · 279 golden fixtures asserting every intermediate to the cent · below $100,000 the engine reproduces the printed IRS Tax Table method exactly (verified against 41 sampled rows of the 2025 Publication 1040 table, all four statuses) · every rule and the fact catalog Merkle-pinned in `corpus.lock.json` · every fixture round-trips through `verify` · every dollar read from the primary source text.\n\n**Honest caveats.** Where the engine approximates, the rule's own citation says so; where a condition can't be verified, the default is conservative — $0 or a refusal, never a guess. The big ones: earned income ≈ wages and MAGI ≈ AGI in several phase-outs; EITC qualifying children approximated by the CTC child count; a handful of niche interactions refuse outright.\n\n## The solver layer — ask questions a calculator can't answer\n\nBecause the rules are pure functions, `opentax` can *reason* about the tax code, not just evaluate it — and every data point is a real, proof-backed evaluation:\n\n```\n$ opentax cliffs --status hoh --wages 30000 --kids 2 --vary taxableInterest --from 10000 --to 14000\n\n2 cliff(s) found:\n  ▮ at $12,199.99: one more cent of taxableInterest costs $16.00\n  ▮ at $12,200.00: one more cent of taxableInterest costs $3,455.00\n```\n\nThat second one is the § 32(i) EITC kill switch, located **to the exact cent** by bisection over real evaluations — one cent of interest income past the TY2026 investment-income limit destroys the family's entire earned income credit.\n\n```\nopentax compare --wages 50000            # net tax under every filing status\nopentax marginal --status single --at 50000    # your true marginal rate\nopentax sweep --vary wages --from 0 --to 200000 --step 5000 --csv   # the whole curve\n```\n\n`cliffs` also finds every $50 CTC phase-out step (§ 24(b)'s \"or fraction thereof\" makes one cent past $412,000 cost $50); `invert` answers \"what income first reaches tax X\" by bisection — and *refuses* with `not-monotone` when the EITC region makes the answer ambiguous, rather than returning a plausible root. This is \"policy simulation\" as an open-source CLI command.\n\nThe same layer powers `opentax search` and `opentax lookup`: full-text rule search with document-frequency scoring tuned so that **zero hits reliably means the topic is outside the corpus**: a refusal guarantee for search, matching the engine's refusal guarantee for evaluation. `lookup … --expect` is the fact-checker behind the MCP `verify_fact` tool.\n\n**This is a computation-and-citation tool, not tax advice.**\n\n## Extending it\n\nAll tax knowledge is **data** — you add coverage by writing a rule object with a citation and a hand-computed test, never by touching engine code:\n\n1. Write the rule (id, citation with statute + excerpt, validity dates, formula).\n2. Statutory exceptions are their own rules that `override` the base with a guard — the proof shows why they did or didn't fire.\n3. Add a golden fixture with expected cents you computed from the statute by hand.\n4. `pnpm test && pnpm -F @invaro/opentax-corpus-us-federal gen:lock`\n\nFull walkthrough: **[CONTRIBUTING.md](CONTRIBUTING.md)**.\n\n**Currency policy:** the corpus tracks current law — when the IRS or Congress changes the numbers, the change lands as a new rule *version* with its own validity window and citation, never an in-place edit. Old proofs stay verifiable against the corpus root they were computed under.\n\n## Commands\n\n| | |\n|---|---|\n| `opentax eval --status mfj --wages 120000 --kids 2` | answer + proof tree (negative = refund) |\n| `opentax eval … --withheld 7000` | **mid-year checkup**: balance due / refund expected next April |\n| `opentax eval … --brief` | plain-English 8-line summary only |\n| `opentax eval --facts f.json --proof out.json` | facts from a file, save the proof |\n| `opentax check … --expect 6600` | gate a claimed number: exit 0 verified, 1 refuted |\n| `opentax verify proof.json` | re-derive a proof, confirm or refute |\n| `opentax state --facts return.json` | printed-form state return lines (IL/VA/CA/NY/PA/NJ/OH/NC/GA) |\n| `opentax facts` / `opentax flags` | every input, its type, its default / every CLI flag, grouped |\n| `opentax lookup standard deduction` | the dollar amounts behind a question, with citations |\n| `opentax search kiddie tax` | full-text rule search; zero hits means it isn't encoded |\n| `opentax occupation DJ` | is this job on the Treasury tipped-occupation list? |\n| `opentax eval --target us.federal.eligible.tips_deduction --occupation DJ` | yes/no determinations with proof |\n| `opentax explain <rule-id>` | one rule: citation, excerpt, hash, dependencies |\n| `opentax corpus list` / `hash` / `export` | rule inventory / corpus fingerprint / the whole corpus as JSON |\n| `opentax sweep --from 0 --to 200000` | the tax curve, point by exact point |\n| `opentax marginal --at 50000` | true marginal rate at a point |\n| `opentax cliffs --from 400000 --to 450000` | exact cents where marginal > 100% |\n| `opentax invert --goal 10000 --lo 0 --hi 500000` | what income first reaches tax X (refuses if not monotone) |\n| `opentax compare --wages 50000` | net tax under every filing status |\n| `opentax eval --se-profit 80000 --wages 0` | freelancer: SE tax + QBI + income tax in one number |\n| `opentax eval --wages 190000 --gains 50000` | investor: capital-gains stacking + NIIT |\n| `opentax eval --wages 300000 --salt 50000 --mortgage-interest 30000 --mortgage-balance 900000 --medical 30000 --charity 10000` | homeowner: Schedule A vs standard, elected automatically |\n| `opentax eval --target us.federal.corp.entity_level_income_tax --entity llc --members 1` | \"how is my LLC taxed?\" — classification + entity-level tax, with the check-the-box citations |\n\nAll take `--json` (except `flags` and `corpus export`, whose output is already raw). In this repo, prefix with `pnpm`: `pnpm opentax …` — or run the published package directly: `npx -y @invaro/opentax eval …`\n\n## Repo layout\n\n```\npackages/\n  core/               the engine: domain-general, zero deps, browser-safe\n  corpus-us-federal/  the tax rules as cited data + golden tests (federal + 30 states)\n  solve/              the reasoning layer: sweep, marginal, cliffs, invert, compare,\n                      rule search, and the fact-checker (also domain-general)\n  compose/            printed-form state-return composers (IL/VA/CA/NY/PA/NJ/OH/NC/GA)\n  cli/                the `opentax` command\n  mcp/                @invaro/opentax, the published package:\n                      MCP server (stdio + HTTP) and the npx CLI\n  playground/         the browser playground (one self-contained HTML file)\nsite/                 opentax.invaro.ai, which also serves the hosted MCP endpoint\n```\n\n## License: AGPL-3.0 + commercial (dual-licensed)\n\nOpenTax is **free software under the [GNU AGPL-3.0](LICENSE)**: use it, study\nit, fork it, run it as a service. The one condition is the AGPL's share-alike\nrule: a product or service built on this engine must publish its own complete\nsource under the AGPL too.\n\n**Building something closed-source or proprietary?** You need a\n[commercial license from Invaro](COMMERCIAL-LICENSE.md). That is the deal:\nopen products use it free, closed products pay for it. It keeps the engine\nfunded and the corpus current.\n\nVersions through `0.2.1` were released under Apache-2.0 and remain so; all\nlater versions are AGPL-3.0-only. \"OpenTax\" is a trademark of Invaro Inc.\n",
  "bytes": 17240,
  "sha": "33b91e1a7fa14bcff853959b4e187c77a417e814256c2b26cfea7e68d9e79874",
  "repo_slug": "invaro/opentax-engine",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_invaro_opentax_f807286d/readme"
}