| name | policyengine-us |
| description | PolicyEngine-US tax and benefit microsimulation patterns, situation creation, and common workflows |
PolicyEngine-US
PolicyEngine-US models the US federal and state tax and benefit system.
For Users 👥
What is PolicyEngine-US?
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:
- Income tax (with standard/itemized deductions)
- Payroll tax (Social Security, Medicare)
- Capital gains tax
Federal benefits:
- Earned Income Tax Credit (EITC)
- Child Tax Credit (CTC)
- SNAP (food stamps)
- WIC, ACA premium tax credits
- Social Security, SSI, TANF
State programs (varies by state):
- State income tax (all 50 states + DC)
- State EITC, CTC
- State-specific benefits
See full list: https://policyengine.org/us/parameters
Understanding Variables
When you see results in PolicyEngine, these are variables:
Income variables:
employment_income - W-2 wages
self_employment_income - 1099 income
qualified_dividend_income - Dividends
capital_gains - Capital gains
Tax variables:
income_tax - Federal income tax
state_income_tax - State income tax
payroll_tax - FICA taxes
Benefit variables:
eitc - Earned Income Tax Credit
ctc - Child Tax Credit
snap - SNAP benefits
Summary variables:
household_net_income - Income after taxes and benefits
household_tax - Total taxes
household_benefits - Total benefits
For Analysts 📊
Installation and Setup
pip install policyengine-us
uv pip install policyengine-us
Quick Start
from policyengine_us import Simulation
situation = {
"people": {
"you": {
"age": {2024: 30},
"employment_income": {2024: 50000}
}
},
"families": {"family": {"members": ["you"]}},
"marital_units": {"marital_unit": {"members": ["you"]}},
"tax_units": {"tax_unit": {"members": ["you"]}},
"spm_units": {"spm_unit": {"members": ["you"]}},
"households": {
"household": {
"members": ["you"],
"state_name": {2024: "CA"}
}
}
}
sim = Simulation(situation=situation)
income_tax = sim.calculate("income_tax", 2024)[0]
eitc = sim.calculate("eitc", 2024)[0]
print(f"Income tax: ${income_tax:,.0f}")
print(f"EITC: ${eitc:,.0f}")
Web App to Python
Web app URL:
policyengine.org/us/household?household=12345
Equivalent Python (conceptually):
The household ID represents a situation dictionary. To replicate in Python, you'd create a similar situation.
When to Use This Skill
- Creating household situations for tax/benefit calculations
- Running microsimulations with PolicyEngine-US
- Analyzing policy reforms and their impacts
- Building tools that use PolicyEngine-US (calculators, analysis notebooks)
- Debugging PolicyEngine-US calculations
For Contributors 💻
Repository
Location: PolicyEngine/policyengine-us
To see current implementation:
git clone https://github.com/PolicyEngine/policyengine-us
cd policyengine-us
tree policyengine_us/
Key directories:
ls policyengine_us/
Core Concepts
1. Situation Dictionary Structure
PolicyEngine requires a nested dictionary defining household composition and characteristics:
situation = {
"people": {
"person_id": {
"age": {2024: 35},
"employment_income": {2024: 50000},
}
},
"families": {
"family_id": {"members": ["person_id", ...]}
},
"marital_units": {
"marital_unit_id": {"members": ["person_id", ...]}
},
"tax_units": {
"tax_unit_id": {"members": ["person_id", ...]}
},
"spm_units": {
"spm_unit_id": {"members": ["person_id", ...]}
},
"households": {
"household_id": {
"members": ["person_id", ...],
"state_name": {2024: "CA"}
}
}
}
Key Rules:
- All entities must have consistent member lists
- Use year keys for all values:
{2024: value}
- State must be two-letter code (e.g., "CA", "NY", "TX")
- All monetary values in dollars (not cents)
2. Creating Simulations
from policyengine_us import Simulation
simulation = Simulation(situation=situation)
income_tax = simulation.calculate("income_tax", 2024)
eitc = simulation.calculate("eitc", 2024)
household_net_income = simulation.calculate("household_net_income", 2024)
Common Variables:
Income:
employment_income - W-2 wages
self_employment_income - 1099/business income
qualified_dividend_income - Qualified dividends
capital_gains - Capital gains
interest_income - Interest income
social_security - Social Security benefits
pension_income - Pension/retirement income
Deductions:
charitable_cash_donations - Cash charitable giving
real_estate_taxes - State and local property taxes
mortgage_interest - Mortgage interest deduction
medical_expense - Medical and dental expenses
casualty_loss - Casualty and theft losses
Tax Outputs:
income_tax - Total federal income tax
payroll_tax - FICA taxes
state_income_tax - State income tax
household_tax - Total taxes (federal + state + local)
Benefits:
eitc - Earned Income Tax Credit
ctc - Child Tax Credit
snap - SNAP benefits
household_benefits - Total benefits
Summary:
household_net_income - Income minus taxes plus benefits
3. Using Axes for Parameter Sweeps
To vary a parameter across multiple values:
situation = {
"axes": [[{
"name": "employment_income",
"count": 1001,
"min": 0,
"max": 200000,
"period": 2024
}]]
}
simulation = Simulation(situation=situation)
incomes = simulation.calculate("employment_income", 2024)
taxes = simulation.calculate("income_tax", 2024)
Important: Remove axes before creating single-point simulations:
situation_single = situation.copy()
situation_single.pop("axes", None)
simulation = Simulation(situation=situation_single)
4. Policy Reforms
from policyengine_us import Simulation
reform = {
"gov.irs.credits.ctc.amount.base_amount": {
"2024-01-01.2100-12-31": 5000
}
}
simulation = Simulation(situation=situation, reform=reform)
Common Patterns
Pattern 1: Single Household Calculation
from policyengine_us import Simulation
situation = {
"people": {
"parent": {
"age": {2024: 35},
"employment_income": {2024: 60000}
},
"child": {
"age": {2024: 5}
}
},
"families": {"family": {"members": ["parent", "child"]}},
"marital_units": {"marital_unit": {"members": ["parent"]}},
"tax_units": {"tax_unit": {"members": ["parent", "child"]}},
"spm_units": {"spm_unit": {"members": ["parent", "child"]}},
"households": {
"household": {
"members": ["parent", "child"],
"state_name": {2024: "NY"}
}
}
}
sim = Simulation(situation=situation)
income_tax = sim.calculate("income_tax", 2024)[0]
ctc = sim.calculate("ctc", 2024)[0]
Pattern 2: Marginal Tax Rate Analysis
situation_with_axes = {
"axes": [[{
"name": "employment_income",
"count": 1001,
"min": 0,
"max": 200000,
"period": 2024
}]]
}
sim = Simulation(situation=situation_with_axes)
incomes = sim.calculate("employment_income", 2024)
taxes = sim.calculate("income_tax", 2024)
import numpy as np
mtr = np.gradient(taxes) / np.gradient(incomes)
Pattern 3: Charitable Donation Impact
situation_baseline = create_situation(income=100000, donation=0)
sim_baseline = Simulation(situation=situation_baseline)
tax_baseline = sim_baseline.calculate("income_tax", 2024)[0]
situation_donation = create_situation(income=100000, donation=5000)
sim_donation = Simulation(situation=situation_donation)
tax_donation = sim_donation.calculate("income_tax", 2024)[0]
tax_savings = tax_baseline - tax_donation
effective_discount = tax_savings / 5000
Pattern 4: State Comparison
states = ["CA", "NY", "TX", "FL"]
results = {}
for state in states:
situation = create_situation(state=state, income=75000)
sim = Simulation(situation=situation)
results[state] = {
"state_income_tax": sim.calculate("state_income_tax", 2024)[0],
"total_tax": sim.calculate("household_tax", 2024)[0]
}
Helper Scripts
This skill includes helper scripts in the scripts/ directory:
from policyengine_skills.situation_helpers import (
create_single_filer,
create_married_couple,
create_family_with_children,
add_itemized_deductions
)
situation = create_single_filer(
income=50000,
state="CA",
age=30
)
situation = add_itemized_deductions(
situation,
charitable_donations=5000,
mortgage_interest=10000,
real_estate_taxes=8000
)
Common Pitfalls and Solutions
Pitfall 1: Member Lists Out of Sync
Problem: Different entities have different members
"tax_units": {"tax_unit": {"members": ["parent"]}},
"households": {"household": {"members": ["parent", "child"]}}
Solution: Keep all entity member lists consistent:
all_members = ["parent", "child"]
"families": {"family": {"members": all_members}},
"tax_units": {"tax_unit": {"members": all_members}},
"households": {"household": {"members": all_members}}
Pitfall 2: Forgetting Year Keys
Problem: "age": 35 instead of "age": {2024: 35}
Solution: Always use year dictionary:
"age": {2024: 35},
"employment_income": {2024: 50000}
Pitfall 3: Net Taxes vs Gross Taxes
Problem: Forgetting to subtract benefits from taxes
Solution: Use proper calculation:
net_tax = sim.calculate("household_tax", 2024) - \
sim.calculate("household_benefits", 2024)
Pitfall 4: Axes Persistence
Problem: Axes remain in situation when creating single-point simulation
Solution: Remove axes before single-point simulation:
situation_single = situation.copy()
situation_single.pop("axes", None)
Pitfall 5: State-Specific Variables
Problem: Using NYC-specific variables without in_nyc: True
Solution: Set NYC flag for NY residents in NYC:
"households": {
"household": {
"state_name": {2024: "NY"},
"in_nyc": {2024: True}
}
}
NYC Handling
For New York City residents:
situation = {
"households": {
"household": {
"members": ["person"],
"state_name": {2024: "NY"},
"in_nyc": {2024: True}
}
}
}
Version Compatibility
- Always use
policyengine-us>=1.155.0 for 2024 calculations
- Check version:
import policyengine_us; print(policyengine_us.__version__)
- Different years may require different package versions
Debugging Tips
-
Enable tracing:
simulation.trace = True
result = simulation.calculate("variable_name", 2024)
-
Check intermediate calculations:
agi = simulation.calculate("adjusted_gross_income", 2024)
taxable_income = simulation.calculate("taxable_income", 2024)
-
Verify situation structure:
import json
print(json.dumps(situation, indent=2))
-
Test with PolicyEngine web app:
- Go to policyengine.org/us/household
- Enter same inputs
- Compare results
Additional Resources
Examples Directory
See examples/ for complete working examples:
single_filer.yaml - Single person household
married_couple.yaml - Married filing jointly
family_with_children.yaml - Family with dependents
itemized_deductions.yaml - Using itemized deductions
donation_sweep.yaml - Analyzing donation impacts with axes