policyengine-healthcare
Healthcare program modeling in PolicyEngine-US — Medicaid, ACA marketplace, CHIP, and Medicare. Covers encoding rules, running analyses, and navigating the unique complexity of US healthcare programs. Triggers: "healthcare", "health insurance", "Medicaid", "ACA", "CHIP", "Medicare", "marketplace", "premium tax credit", "APTC", "PTC", "SLCSP", "benchmark plan", "rating area", "age curve", "family tier", "coverage gap", "Medicaid expansion", "MAGI", "medicaid_magi", "aca_magi", "medicaid_income_level", "medicaid_category", "enrollment", "takeup", "take-up", "per capita", "CSR", "cost sharing", "insurance premium", "second lowest silver", "required contribution percentage", "42 CFR", "IRC 36B", "categorical eligibility", "expansion adult", "healthcare reform", "healthcare analysis", "health policy".
What this skill does
# PolicyEngine healthcare programs
> **Scope:** This skill covers the healthcare domain — Medicaid, ACA marketplace, CHIP, and Medicare as modeled in PolicyEngine-US. For general PolicyEngine-US patterns, see the `policyengine-us` skill. For variable/parameter implementation patterns, see the `policyengine-variable-patterns` and `policyengine-parameter-patterns` skills.
## For users
### What healthcare programs does PolicyEngine model?
PolicyEngine-US models four interconnected healthcare programs:
| Program | What it does | Key variable |
|---------|-------------|--------------|
| **Medicaid** | Free/low-cost coverage for low-income individuals | `medicaid` |
| **ACA marketplace** | Subsidized private insurance via premium tax credits | `aca_ptc` |
| **CHIP** | Children's health coverage above Medicaid thresholds | `per_capita_chip` |
| **Medicare** | Coverage for seniors and disabled individuals | `medicare` |
These programs are **mutually exclusive by design** — Medicaid eligibility disqualifies you from ACA subsidies, and CHIP covers children who don't qualify for Medicaid. This interconnection is a key modeling challenge.
### Why healthcare is different from other benefits
Most benefit programs (SNAP, TANF, EITC) have a single income test and a single benefit amount. Healthcare programs are different:
- **9 eligibility categories** for Medicaid alone (infant, young child, older child, young adult, adult expansion, parent, pregnant, SSI recipient, senior/disabled)
- **51 different Medicaid programs** — every state sets its own income limits and rules
- **~500 ACA rating areas** — premiums vary by geographic zone, not just by state
- **Actuarial calculations** — ACA subsidies depend on the second-lowest silver plan premium in your area, adjusted by age
- **Program interactions** — losing Medicaid doesn't automatically mean gaining ACA access (the "coverage gap")
## For analysts
### Healthcare variables reference
#### Medicaid
| Variable | Entity | Description |
|----------|--------|-------------|
| `medicaid` | person | Annual Medicaid benefit amount |
| `is_medicaid_eligible` | person | Overall eligibility (combines all checks) |
| `medicaid_enrolled` | person | Actually enrolled (eligibility x take-up) |
| `medicaid_category` | person | Enum: SSI_RECIPIENT, INFANT, YOUNG_CHILD, OLDER_CHILD, PREGNANT, PARENT, YOUNG_ADULT, ADULT, SENIOR_OR_DISABLED, NONE |
| `medicaid_income_level` | person | Person's tax unit MAGI as fraction of FPL |
| `medicaid_magi` | tax_unit | Modified AGI for Medicaid (= AGI + state additions) |
| `takes_up_medicaid_if_eligible` | person | Pseudo-random take-up flag (default rate: 93%) |
| `medicaid_cost` | person | Per-capita cost by eligibility group and state |
#### ACA marketplace
| Variable | Entity | Description |
|----------|--------|-------------|
| `aca_ptc` | tax_unit | Annual premium tax credit amount |
| `is_aca_ptc_eligible` | person | PTC eligibility (income 100-400%+ FPL, no other coverage) |
| `aca_magi` | tax_unit | Delegates to `medicaid_magi` via `adds = ["medicaid_magi"]` |
| `aca_magi_fraction` | tax_unit | Income as percentage of FPL |
| `aca_required_contribution_percentage` | tax_unit | Household's required premium contribution rate |
| `slcsp` | tax_unit | Second-lowest silver plan premium (monthly, definition_period=MONTH). **Returns $0 for ineligible people** — the model skips the calculation when someone doesn't qualify for ACA. To get the unsubsidized benchmark premium regardless of eligibility, look at the underlying rating area cost parameters directly. |
| `takes_up_aca_if_eligible` | tax_unit | Take-up flag (default rate varies) |
#### CHIP
| Variable | Entity | Description |
|----------|--------|-------------|
| `per_capita_chip` | person | CHIP benefit per capita |
| `is_chip_eligible` | person | CHIP eligibility |
| `chip_category` | person | Enum: CHILD, PREGNANT_STANDARD, PREGNANT_FCEP, NONE |
### Household setup for healthcare analysis
Healthcare calculations require the state to be specified (unlike some federal-only programs):
```python
from policyengine_us import Simulation
situation = {
"people": {
"person1": {
"age": {"2026": 35},
"employment_income": {"2026": 25_000},
"is_tax_unit_head": {"2026": True},
},
"person2": {
"age": {"2026": 8},
"is_tax_unit_dependent": {"2026": True},
},
},
"tax_units": {"tax_unit": {"members": ["person1", "person2"]}},
"families": {"family": {"members": ["person1", "person2"]}},
"spm_units": {"spm_unit": {"members": ["person1", "person2"]}},
"marital_units": {"marital_unit": {"members": ["person1"]}},
"households": {
"household": {
"members": ["person1", "person2"],
"state_name": {"2026": "NY"},
}
},
}
sim = Simulation(situation=situation)
# Check Medicaid eligibility at person level
medicaid_eligible = sim.calculate("is_medicaid_eligible", 2026)
# Check ACA PTC at tax unit level
aca_ptc = sim.calculate("aca_ptc", 2026)
```
### Healthcare reform modeling
#### Medicaid expansion repeal (parameter modification)
```python
from policyengine_core.reforms import Reform
from policyengine_core.periods import instant
YEAR = 2026
def create_medicaid_expansion_repeal(state="UT"):
"""Remove adult Medicaid expansion by setting income limit to -inf."""
def modify_parameters(parameters):
parameters.gov.hhs.medicaid.eligibility.categories.adult.income_limit[state].update(
start=instant(f"{YEAR}-01-01"),
stop=instant("2100-12-31"),
value=float("-inf"),
)
return parameters
class reform(Reform):
def apply(self):
self.modify_parameters(modify_parameters)
return reform
```
#### IRA subsidy extension (variable-override reform)
The most common ACA policy question: extending the IRA-enhanced subsidies beyond their 2025 sunset. **`Reform.from_dict()` does not work** for ACA contribution rate parameters because they are list-valued (threshold + initial + final arrays). Use a variable-override reform instead:
```python
from policyengine_us import Microsimulation
from policyengine_core.reforms import Reform
ANALYSIS_YEAR = 2026 # Don't use "YEAR" — it shadows model_api.YEAR
# Look up actual parameter values to build the reform
from policyengine_us import CountryTaxBenefitSystem
p = CountryTaxBenefitSystem().parameters
contrib = p.gov.aca.required_contribution_percentage
# Check what values look like pre/post sunset
print("2025 initial rates:", contrib.initial("2025-01-01")) # IRA-enhanced
print("2026 initial rates:", contrib.initial("2026-01-01")) # Post-sunset (higher)
# Option A: Use Reform.from_dict for the scalar parameters that DO work
reform = Reform.from_dict({
# The 400% FPL cap removal (IRA made subsidies available above 400%)
'gov.aca.ptc_income_eligibility[2].amount': {
f'{ANALYSIS_YEAR}-01-01.2100-12-31': True
},
}, 'policyengine_us')
# Option B: For contribution rates (list-valued), use modify_parameters
from policyengine_core.periods import instant
def create_ira_extension():
def modify_parameters(parameters):
# Restore IRA-era contribution percentages
# You need to set each bracket's initial and final rates
for bracket_param in ['initial', 'final']:
getattr(
parameters.gov.aca.required_contribution_percentage,
bracket_param,
).update(
start=instant(f"{ANALYSIS_YEAR}-01-01"),
stop=instant("2100-12-31"),
value=getattr(contrib, bracket_param)("2025-01-01"),
)
return parameters
class reform(Reform):
def apply(self):
self.modify_parameters(modify_parameters)
return reform
```
Also see existing reforms in `policyengine_us/reforms/aca/` for production examples of variable-ovRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.