From data-science
Provides Python code patterns for PolicyEngine-US household impact calculations and population microsimulations of US federal/state taxes/benefits like EITC, SNAP, CTC.
npx claudepluginhub policyengine/policyengine-claude --plugin data-scienceThis skill uses the workspace's default tool permissions.
> **IMPORTANT: Always use the current year (2026) in calculations, not 2024 or 2025.**
Runs PolicyEngine microsimulations for population-level policy analysis: costs, revenues, poverty rates, distributional impacts, winners/losers, Gini, state-level effects.
Advises on US taxes for W-2, 1099, S-Corp filers: identifies deductions, logs expenses to JSON, assesses audit risk, optimizes brackets, plans estimated payments, handles multi-state filing and life events.
Provides Japanese tax advice on deductions, filings, business expenses, and 2025 rules using reference files for accurate consultations.
Share bugs, ideas, or general feedback.
IMPORTANT: Always use the current year (2026) in calculations, not 2024 or 2025.
PolicyEngine-US models the US federal and state tax and benefit system.
PolicyEngine-US is the "calculator" for US taxes and benefits. When you use policyengine.org/us, PolicyEngine-US runs behind the scenes.
What it models:
Federal taxes:
Federal benefits:
State programs (varies by state):
See full list: https://policyengine.org/us/parameters
Income variables:
employment_income - W-2 wagesself_employment_income - 1099 incomequalified_dividend_income - Dividendscapital_gains - Capital gainsTax variables:
income_tax - Federal income taxstate_income_tax - State income taxpayroll_tax - FICA taxesBenefit variables:
eitc - Earned Income Tax Creditctc - Child Tax Creditsnap - SNAP benefitsSummary variables:
household_net_income - Income after taxes and benefitshousehold_tax - Total taxeshousehold_benefits - Total benefitsuv pip install policyengine
Use calculate_household_impact() with USHouseholdInput for quick calculations.
from policyengine.tax_benefit_models.us import (
USHouseholdInput,
calculate_household_impact,
)
household = USHouseholdInput(
people=[
{"age": 35, "employment_income": 50_000, "is_tax_unit_head": True},
],
household={"state_code_str": "CA"},
year=2026,
)
result = calculate_household_impact(household)
print(f"Income tax: ${result.tax_unit[0]['income_tax']:,.0f}")
print(f"Net income: ${result.household['household_net_income']:,.0f}")
The US has more entities than the UK due to different program structures:
person - Individual peoplemarital_unit - Married couplesfamily - Family unitspm_unit - SPM unit (for SNAP, TANF, poverty measures)tax_unit - Tax filing unit (for income tax, EITC, CTC)household - Physical householdhousehold = USHouseholdInput(
people=[
{"age": 30, "employment_income": 60_000, "is_tax_unit_head": True},
],
household={"state_code_str": "CA"},
year=2026,
)
result = calculate_household_impact(household)
household = USHouseholdInput(
people=[
{"age": 35, "employment_income": 80_000, "is_tax_unit_head": True},
{"age": 33, "employment_income": 40_000, "is_tax_unit_spouse": True},
{"age": 8, "is_tax_unit_dependent": True},
{"age": 5, "is_tax_unit_dependent": True},
],
tax_unit={"filing_status": "JOINT"},
household={"state_code_str": "NY"},
year=2026,
)
result = calculate_household_impact(household)
print(f"EITC: ${result.tax_unit[0]['eitc']:,.0f}")
print(f"CTC: ${result.tax_unit[0]['ctc']:,.0f}")
print(f"SNAP: ${result.spm_unit[0]['snap']:,.0f}")
# Person-level
employment_income = result.person[0]['employment_income']
# Tax unit level (income tax, credits)
income_tax = result.tax_unit[0]['income_tax']
eitc = result.tax_unit[0]['eitc']
ctc = result.tax_unit[0]['ctc']
# SPM unit level (means-tested benefits)
snap = result.spm_unit[0]['snap']
tanf = result.spm_unit[0]['tanf']
# Household level
net_income = result.household['household_net_income']
Use Simulation with datasets for population-level analysis.
from policyengine.tax_benefit_models.us import (
us_latest,
ensure_datasets,
)
datasets = ensure_datasets(
data_folder="./data",
years=[2026],
)
dataset = datasets["enhanced_cps_2024_2026"]
from policyengine.core import Simulation
simulation = Simulation(
dataset=dataset,
tax_benefit_model_version=us_latest,
)
simulation.ensure()
output = simulation.output_dataset.data
total_eitc = output.tax_unit['eitc'].sum()
total_snap = output.spm_unit['snap'].sum()
from policyengine.core import Policy, ParameterValue
from datetime import datetime
param = us_latest.get_parameter("gov.irs.credits.ctc.amount.base_amount")
policy = Policy(
name="CTC $5000",
parameter_values=[
ParameterValue(
parameter=param,
value=5000,
start_date=datetime(2026, 1, 1),
)
],
)
reform_sim = Simulation(
dataset=dataset,
tax_benefit_model_version=us_latest,
policy=policy,
)
reform_sim.ensure()
def expand_eitc(sim):
"""Expand EITC phase-out threshold."""
sim.tax_benefit_system.parameters.get_child(
"gov.irs.credits.eitc.phase_out.start"
).update(period="year:2026:10", value=25000)
sim.tax_benefit_system.reset_parameter_caches()
policy = Policy(
name="Expand EITC",
simulation_modifier=expand_eitc,
)
For quick parameter lookups:
from policyengine_us import CountryTaxBenefitSystem
params = CountryTaxBenefitSystem().parameters
# CTC amount
ctc = params.gov.irs.credits.ctc.amount.base_amount("2026-01-01")
# SNAP max (use .children["N"] for indexed params)
snap_max = params.gov.usda.snap.income.max_allotment.children["4"]("2026-01-01")
# State TANF
dc_tanf = params.gov.states.dc.dhs.tanf.standard_payment.amount.children["3"]("2026-01-01")
# WRONG
mean = output.tax_unit['eitc'].values.mean()
# CORRECT
mean = output.tax_unit['eitc'].mean()
# People need tax unit roles
{"age": 35, "is_tax_unit_head": True}
{"age": 33, "is_tax_unit_spouse": True}
{"age": 8, "is_tax_unit_dependent": True}
tax_unit={"filing_status": "JOINT"} # or "SEPARATE", "HEAD_OF_HOUSEHOLD"
State variables use {state_code}_{program} naming:
ca_tanf, ny_tanf, dc_tanf - State TANFca_eitc, ny_eitc - State EITCstate_income_tax - Aggregate state taxfrom policyengine_us import CountryTaxBenefitSystem
system = CountryTaxBenefitSystem()
# Find state variables
ca_vars = [v for v in system.variables if v.startswith("ca_")]
SNAP benefits are calculated monthly (definition_period = MONTH). When sweeping annual income, the annual SNAP value is the sum of 12 monthly calculations. This creates subtle cliff behavior.
The Federal Poverty Level updates in October (new fiscal year). This means:
$33,550/yr → $2,795.83/mo → Eligible all 12 months → $1,956/yr SNAP
$33,600/yr → $2,800.00/mo → 130% FPL = $2,797.17/mo (Jan-Sep)
→ Fails 9 months, passes Oct-Dec → $527/yr SNAP
$34,700/yr → $2,891.67/mo → Exceeds even Oct-Dec threshold → $0/yr SNAP
snap (annual sum of monthly allotments)
├── snap_normal_allotment = max(snap_min_allotment, snap_max_allotment - snap_expected_contribution)
│ ├── snap_max_allotment (household size and region)
│ ├── snap_expected_contribution = floor(snap_net_income) × 0.30
│ │ └── snap_net_income = max(0, snap_gross_income - snap_deductions)
│ │ ├── snap_gross_income = snap_earned_income + snap_unearned_income
│ │ └── snap_deductions = standard + earned_income(20%) + shelter + dependent_care + medical + child_support
│ └── snap_min_allotment (usually only for 1-2 person households)
├── is_snap_eligible
│ ├── meets_snap_gross_income_test (≤ 130% FPL, or categorical)
│ ├── meets_snap_net_income_test (≤ 100% FPL)
│ ├── meets_snap_asset_test
│ └── meets_snap_work_requirements
└── snap_emergency_allotment (COVID-era, now $0)
sim = Simulation(situation=situation)
sim.trace = True
result = sim.calculate('snap_normal_allotment', '2025-01') # Check specific month!
for node in sim.tracer.trees:
def print_tree(n, indent=0):
val = n.value
val_str = str(val[0]) if hasattr(val, '__len__') and len(val) == 1 else str(val)
print(' ' * indent + f'{n.name} <{n.period}> = {val_str}')
for child in n.children:
print_tree(child, indent + 1)
print_tree(node)
| Cliff | Cause | Typical magnitude |
|---|---|---|
| SNAP 130% FPL (partial year) | Gross income test fails 9 months, passes Oct-Dec | ~75% of SNAP lost |
| SNAP 130% FPL (full) | Exceeds even Oct-Dec threshold | 100% of SNAP lost |
| School meals (free → reduced) | Free school meals lost at ~130% FPL | ~$250/child/yr |
| School meals (reduced → none) | Reduced-price meals lost at ~185% FPL | ~$990/child/yr |
# ✅ CORRECT for custom situations
from policyengine_us import Simulation
sim = Simulation(situation=situation)
# ❌ WRONG - Microsimulation expects a dataset, not a situation
from policyengine_us import Microsimulation
sim = Microsimulation(situation=situation) # Raises ValueError