Agent skill
policyengine-code-style
PolicyEngine code writing style guide - formula optimization, direct returns, eliminating unnecessary variables
Install this agent skill to your Project
npx add-skill https://github.com/PolicyEngine/policyengine-claude/tree/main/skills/technical-patterns/policyengine-code-style-skill
SKILL.md
PolicyEngine Code Writing Style Guide
Essential patterns for writing clean, efficient PolicyEngine formulas.
Core Principles
- Eliminate unnecessary intermediate variables
- Use direct parameter/variable access
- Return directly when possible
- Combine boolean logic
- Use correct period access (period vs period.this_year)
- NO hardcoded values - use parameters or constants
Pattern 1: Direct Parameter Access
❌ Bad - Unnecessary intermediate variable
def formula(spm_unit, period, parameters):
countable = spm_unit("tn_tanf_countable_resources", period)
p = parameters(period).gov.states.tn.dhs.tanf.resource_limit
resource_limit = p.amount # ❌ Unnecessary
return countable <= resource_limit
✅ Good - Direct access
def formula(spm_unit, period, parameters):
countable = spm_unit("tn_tanf_countable_resources", period)
p = parameters(period).gov.states.tn.dhs.tanf.resource_limit
return countable <= p.amount
Pattern 2: Direct Return
❌ Bad - Unnecessary result variable
def formula(spm_unit, period, parameters):
assets = spm_unit("spm_unit_assets", period.this_year)
p = parameters(period).gov.states.tn.dhs.tanf.resource_limit
vehicle_exemption = p.vehicle_exemption # ❌ Unnecessary
countable = max_(assets - vehicle_exemption, 0) # ❌ Unnecessary
return countable
✅ Good - Direct return
def formula(spm_unit, period, parameters):
assets = spm_unit("spm_unit_assets", period.this_year)
p = parameters(period).gov.states.tn.dhs.tanf.resource_limit
return max_(assets - p.vehicle_exemption, 0)
Pattern 3: Combined Boolean Logic
❌ Bad - Too many intermediate booleans
def formula(spm_unit, period, parameters):
person = spm_unit.members
age = person("age", period.this_year)
is_disabled = person("is_disabled", period.this_year)
caretaker_is_60_or_older = spm_unit.any(age >= 60) # ❌ Unnecessary
caretaker_is_disabled = spm_unit.any(is_disabled) # ❌ Unnecessary
eligible = caretaker_is_60_or_older | caretaker_is_disabled # ❌ Unnecessary
return eligible
✅ Good - Combined logic
def formula(spm_unit, period, parameters):
person = spm_unit.members
age = person("age", period.this_year)
is_disabled = person("is_disabled", period.this_year)
return spm_unit.any((age >= 60) | is_disabled)
Pattern 4: Period Access - period vs period.this_year
# ❌ Bad
age = person("age", period) # Gives age/12
monthly_income = person("employment_income", period.this_year) / MONTHS_IN_YEAR # Redundant
# ✅ Good
age = person("age", period.this_year) # Gets actual age
monthly_income = person("employment_income", period) # Auto-converts to monthly
- Income/flows → Use
period(want monthly from annual) - Age/assets/counts/booleans → Use
period.this_year(don't divide by 12)
See policyengine-period-patterns skill for the full decision tree and more examples.
Pattern 5: No Hardcoded Values
❌ Bad - Hardcoded numbers
def formula(spm_unit, period, parameters):
size = spm_unit.nb_persons()
capped_size = min_(size, 10) # ❌ Hardcoded
age = person("age", period.this_year)
income = person("income", period) / 12 # ❌ Use MONTHS_IN_YEAR
# ❌ Hardcoded thresholds
if age >= 18 and age <= 65 and income < 2000:
return True
✅ Good - Parameterized
def formula(spm_unit, period, parameters):
p = parameters(period).gov.program
capped_size = min_(spm_unit.nb_persons(), p.max_unit_size) # ✅
age = person("age", period.this_year)
monthly_income = person("income", period) # ✅ Auto-converts (no manual /12)
age_eligible = (age >= p.age_min) & (age <= p.age_max) # ✅
income_eligible = monthly_income < p.income_threshold # ✅
return age_eligible & income_eligible
Use Framework Constants, Not Custom Parameters
PolicyEngine provides constants for universal conversion factors. Don't create parameters for these:
# ❌ BAD — created a weeks_per_month.yaml parameter:
weekly_subsidy * p.weeks_per_month
# ✅ GOOD — use framework constants:
weekly_subsidy * (WEEKS_IN_YEAR / MONTHS_IN_YEAR)
Available constants: MONTHS_IN_YEAR (12), WEEKS_IN_YEAR (52). Derive others from these.
CRITICAL: WEEKS_IN_YEAR is the integer 52, not 52.1429. Never use WEEKS_IN_YEAR * 7 for days per year — that gives 364, not 365. Use the literal 365 for days-per-year calculations.
Regulatory conversion factors take precedence. When a regulation cites a specific factor (e.g., "multiply by 4.3"), use that exact value even if a framework constant is close (WEEKS_IN_YEAR / MONTHS_IN_YEAR ≈ 4.333). The discrepancy may affect benefit amounts at boundary conditions.
Pattern 6: Streamline Variable Access
❌ Bad - Redundant steps
def formula(spm_unit, period, parameters):
unit_size = spm_unit.nb_persons() # ❌ Unnecessary
max_size = 10 # ❌ Hardcoded
capped_size = min_(unit_size, max_size)
p = parameters(period).gov.states.tn.dhs.tanf.benefit
spa = p.standard_payment_amount[capped_size] # ❌ Unnecessary
dgpa = p.differential_grant_payment_amount[capped_size] # ❌ Unnecessary
eligible = spm_unit("eligible_for_dgpa", period)
return where(eligible, dgpa, spa)
✅ Good - Streamlined
def formula(spm_unit, period, parameters):
p = parameters(period).gov.states.tn.dhs.tanf.benefit
capped_size = min_(spm_unit.nb_persons(), p.max_unit_size)
eligible = spm_unit("eligible_for_dgpa", period)
return where(
eligible,
p.differential_grant_payment_amount[capped_size],
p.standard_payment_amount[capped_size]
)
When to Keep Intermediate Variables
✅ Keep when value is used multiple times
def formula(tax_unit, period, parameters):
p = parameters(period).gov.irs.credits
filing_status = tax_unit("filing_status", period)
# ✅ Used multiple times - keep as variable
threshold = p.phase_out.start[filing_status]
income = tax_unit("adjusted_gross_income", period)
excess = max_(0, income - threshold)
reduction = (excess / p.phase_out.width) * threshold
return max_(0, threshold - reduction)
✅ Keep when calculation is complex
def formula(spm_unit, period, parameters):
p = parameters(period).gov.program
gross_earned = spm_unit("gross_earned_income", period)
# ✅ Complex multi-step calculation - break it down
work_expense_deduction = min_(gross_earned * p.work_expense_rate, p.work_expense_max)
after_work_expense = gross_earned - work_expense_deduction
earned_disregard = after_work_expense * p.earned_disregard_rate
countable_earned = after_work_expense - earned_disregard
dependent_care = spm_unit("dependent_care_expenses", period)
return max_(0, countable_earned - dependent_care)
✅ Break out complex expressions inside function calls
Don't inline complex calculations inside where(), max_(), or other function calls - give them descriptive names.
# ❌ BAD - Complex expression inlined in where()
return where(
above_trigger,
reduced_payment,
max_(maximum_benefit - countable_income, 0), # Hard to read
)
# ✅ GOOD - Break out into named variable
standard_payment = max_(maximum_benefit - countable_income, 0)
return where(
above_trigger,
reduced_payment,
standard_payment, # Clear what this represents
)
Another example:
# ❌ BAD - Multiple complex inlined expressions
return where(
income > add(spm_unit, period, ["earned", "unearned"]) * p.rate,
max_(benefit - (income * p.reduction_rate), 0),
benefit,
)
# ✅ GOOD - Named variables explain the logic
gross_income = add(spm_unit, period, ["earned", "unearned"])
income_threshold = gross_income * p.rate
reduced_benefit = max_(benefit - (income * p.reduction_rate), 0)
return where(
income > income_threshold,
reduced_benefit,
benefit,
)
Rule: If it's more than a simple variable or parameter access, give it a name.
Pattern 8: Use add() > 0 Instead of spm_unit.any()
When checking if ANY member has a boolean property, use add() > 0 instead of spm_unit.members + spm_unit.any().
# ❌ LESS PREFERRED - verbose pattern:
person = spm_unit.members
has_citizen = spm_unit.any(
person("is_citizen_or_legal_immigrant", period)
)
# ✅ BETTER - cleaner add() > 0 pattern:
immigration_eligible = add(spm_unit, period, ["is_citizen_or_legal_immigrant"]) > 0
Why this is better:
- Avoids intermediate
person = spm_unit.membersvariable - Consistent with
add()patterns used elsewhere - More descriptive variable name (
immigration_eligiblevshas_citizen) - Single line instead of multiple
More examples:
# Check if any member is disabled
has_disabled_member = add(spm_unit, period, ["is_disabled"]) > 0
# Check if any member is elderly
has_elderly_member = add(spm_unit, period, ["is_elderly"]) > 0
# Check if any child is present
has_child = add(spm_unit, period, ["is_child"]) > 0
Pattern 9: Use Existing SPMUnit-Level Variables Directly
If an spm_unit-level variable exists, use it directly. Don't access through person level.
# ❌ BAD - Unnecessary person-level access when spm_unit variable exists:
person = spm_unit.members
demographic = person("is_person_demographic_tanf_eligible", period)
# Then aggregating back to spm_unit...
# ✅ GOOD - Use the spm_unit-level variable directly:
demographic_eligible = spm_unit("is_demographic_tanf_eligible", period)
Before writing code, check:
- Does an spm_unit-level variable already exist?
- If yes, use
spm_unit("variable_name", period)directly - Only use
spm_unit.memberswhen you need person-level data that must be aggregated
# ✅ GOOD - Using existing spm_unit variables:
income_eligible = spm_unit("ar_tea_income_eligible", period)
resource_eligible = spm_unit("ar_tea_resource_eligible", period)
demographic_eligible = spm_unit("is_demographic_tanf_eligible", period)
return income_eligible & resource_eligible & demographic_eligible
Complete Example: Before vs After
❌ Before - Multiple Issues
def formula(person, period, parameters):
# Wrong period access
age = person("age", period) # ❌ age/12
assets = person("assets", period) # ❌ assets/12
annual_income = person("employment_income", period.this_year)
monthly_income = annual_income / 12 # ❌ Use MONTHS_IN_YEAR
# Hardcoded values
min_age = 18 # ❌
max_age = 64 # ❌
asset_limit = 10000 # ❌
income_limit = 2000 # ❌
# Unnecessary intermediate variables
age_check = (age >= min_age) & (age <= max_age)
asset_check = assets <= asset_limit
income_check = monthly_income <= income_limit
eligible = age_check & asset_check & income_check
return eligible
✅ After - Clean and Correct
def formula(person, period, parameters):
p = parameters(period).gov.program.eligibility
# Correct period access
age = person("age", period.this_year)
assets = person("assets", period.this_year)
monthly_income = person("employment_income", period)
# Direct return with combined logic
return (
(age >= p.age_min) & (age <= p.age_max) &
(assets <= p.asset_limit) &
(monthly_income <= p.income_threshold)
)
Pattern 7: Minimal Comments
Code Should Be Self-Documenting
Variable names and structure should explain the code - not comments.
❌ Bad - Verbose explanatory comments
def formula(spm_unit, period, parameters):
# Wisconsin disregards all earned income of dependent children (< 18)
# Calculate earned income for adults only
is_adult = spm_unit.members("age", period.this_year) >= 18 # Hard-coded!
adult_earned = spm_unit.sum(
spm_unit.members("tanf_gross_earned_income", period) * is_adult
)
# All unearned income is counted (including children's)
gross_unearned = add(spm_unit, period, ["tanf_gross_unearned_income"])
# NOTE: Wisconsin disregards many additional income sources that
# are not separately tracked in PolicyEngine (educational aid, etc.)
return max_(total_income - disregards, 0)
✅ Good - Clean self-documenting code
def formula(spm_unit, period, parameters):
p = parameters(period).gov.states.wi.dcf.tanf.income
is_adult = spm_unit.members("age", period.this_year) >= p.adult_age_threshold
adult_earned = spm_unit.sum(
spm_unit.members("tanf_gross_earned_income", period) * is_adult
)
gross_unearned = add(spm_unit, period, ["tanf_gross_unearned_income"])
child_support = add(spm_unit, period, ["child_support_received"])
return max_(adult_earned + gross_unearned - child_support, 0)
Comment Rules
- NO comments explaining what code does - variable names should be clear
- OK: Brief NOTE about implementation decisions (one line):
python
# NOTE: Disregard rate varies by calendar month - NO multi-line explanations of what the code calculates
Pattern 10: Remove Redundant Operations
Don't cap what's already capped
When a formula algebraically guarantees result <= upper_bound, remove the redundant min_():
# ❌ BAD — redundant (payment_standard - positive_income ≤ payment_standard always):
benefit = min_(max_(payment_standard - countable_income, 0), payment_standard)
# ✅ GOOD — max_(x, 0) already ensures result ≤ payment_standard:
benefit = max_(payment_standard - countable_income, 0)
Only use min_() when the bound can actually bind (e.g., capping subsidy at actual expenses or provider charges).
Quick Checklist
Before finalizing code:
- No hardcoded numbers (use parameters or constants like MONTHS_IN_YEAR)
- Correct period access:
- Income/flows use
period - Age/assets/counts/booleans use
period.this_year
- Income/flows use
- No single-use intermediate variables FOR SIMPLE VALUES
- BUT: Break out complex expressions inside
where(),max_()into named variables - Direct parameter access (
p.amountnotamount = p.amount) - Direct returns when possible
- Combined boolean logic when possible
- Minimal comments (code should be self-documenting)
- No redundant
min_()/max_()when algebraically guaranteed - Framework constants used correctly (
WEEKS_IN_YEAR= 52, not 52.14) - Regulatory conversion factors used when regulation specifies an exact value
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
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".
policyengine-us
ALWAYS LOAD THIS SKILL FIRST before writing any PolicyEngine-US code. Contains the correct API patterns for household calculations and population simulations using the new policyengine package. Covers US federal and state taxes/benefits. Triggers: "what would", "how much would a", "benefit be", "eligible for", "qualify for", "single parent", "married couple", "family of", "household of", "if they earn", "earning $", "making $", "calculate benefits", "calculate taxes", "benefit for a", "what would I get", "what is the maximum", "what is the rate", "poverty line", "income limit", "benefit amount", "maximum benefit", "compare states", "TANF", "SNAP", "EITC", "CTC", "SSI", "WIC", "Section 8", "Medicaid", "ACA", "child tax credit", "earned income", "supplemental security", "housing voucher", "microsimulation", "population", "reform", "policy impact", "budgetary", "decile".
policyengine-uk
ALWAYS LOAD THIS SKILL FIRST before writing any PolicyEngine-UK code. Contains the correct API patterns for household calculations and population simulations using the new policyengine package (not policyengine_uk directly). Triggers: "what would", "how much would a", "benefit be", "eligible for", "qualify for", "single parent", "married couple", "family of", "household of", "if they earn", "with income of", "earning £", "making £", "calculate benefits", "calculate taxes", "benefit for a", "tax for a", "what would I get", "what would they get", "what is the rate", "what is the threshold", "personal allowance", "maximum benefit", "income limit", "benefit amount", "how much is", "Universal Credit", "child benefit", "pension credit", "housing benefit", "council tax", "income tax", "national insurance", "JSA", "ESA", "PIP", "disability living allowance", "working tax credit", "child tax credit", "Scotland", "Wales", "UK", "microsimulation", "population", "reform", "policy impact", "budgetary", "decile".
policyengine-canada
ALWAYS LOAD THIS SKILL FIRST before writing any PolicyEngine-Canada code. Contains Canadian federal and provincial tax/benefit rules for household calculations. IMPORTANT: PolicyEngine-Canada does NOT have representative population microdata. Do NOT attempt microsimulation or population-level estimates for Canada. Only provide household-level analysis (single-family impacts, eligibility, benefit amounts). Triggers: "what would", "how much would a", "benefit be", "eligible for", "qualify for", "single parent", "married couple", "family of", "household of", "if they earn", "earning $", "making $", "calculate benefits", "calculate taxes", "benefit for a", "what would I get", "what is the maximum", "what is the rate", "income limit", "benefit amount", "maximum benefit", "compare provinces", "CCB", "Canada Child Benefit", "GST credit", "HST credit", "GST/HST", "OAS", "Old Age Security", "GIS", "Guaranteed Income Supplement", "CWB", "Canada Workers Benefit", "EI", "Employment Insurance", "CPP", "Canada Pension Plan", "RRSP", "TFSA", "Ontario Child Benefit", "OCB", "Ontario Trillium Benefit", "OTB", "BC Climate Action", "Alberta Child Benefit", "Quebec", "CRA", "Canada Revenue Agency", "Canadian", "Canada", "Ontario", "British Columbia", "Alberta", "Saskatchewan", "Manitoba", "Nova Scotia", "New Brunswick", "PEI", "Newfoundland", "Yukon", "NWT", "Nunavut", "provincial tax", "federal tax Canada".
policyengine-ui-kit-consumer
This skill should be used when setting up a new project that uses @policyengine/ui-kit, debugging CSS or styling issues in a consumer app, or when Tailwind utility classes are not being generated. Also use when creating globals.css, configuring PostCSS, or troubleshooting "no styles", "no spacing", or "no layout" problems. Triggers: "ui-kit import", "globals.css setup", "Tailwind not working", "styles not applying", "utility classes missing", "setup ui-kit", "PostCSS config", "no styling", "CSS broken", "import ui-kit", "theme.css", "no layout", "no spacing", "@tailwindcss/postcss"
policyengine-tailwind-shadcn
Tailwind CSS v4 + shadcn/ui integration patterns for PolicyEngine frontend projects. Covers @theme namespaces, CSS variable conventions, SVG var() usage, and common mistakes. Triggers: "Tailwind v4", "@theme", "shadcn", "CSS variables", "design tokens CSS", "theme.css", "@theme inline"
Didn't find tool you were looking for?