From 3d141513dbcc8a5d554b50d3928ac4da55bc9d57 Mon Sep 17 00:00:00 2001 From: Priyanka Punukollu Date: Thu, 26 Feb 2026 16:49:00 -0600 Subject: [PATCH] feat: add family financial planner with global childcare data Made-with: Cursor --- evals/test_family_planner.py | 67 +++++++++++ tools/family_planner.py | 217 +++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+) create mode 100644 evals/test_family_planner.py create mode 100644 tools/family_planner.py diff --git a/evals/test_family_planner.py b/evals/test_family_planner.py new file mode 100644 index 000000000..920bfc9e2 --- /dev/null +++ b/evals/test_family_planner.py @@ -0,0 +1,67 @@ +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools')) +from family_planner import plan_family_finances + + +def test_family_plan_austin_one_child(): + result = plan_family_finances( + current_city="Austin", + annual_income=120000, + portfolio_value=94000, + num_planned_children=1, + ) + assert result is not None + assert result["monthly_cost_breakdown"]["childcare_monthly"] > 0 + assert result["monthly_cost_breakdown"]["total_new_monthly_costs"] > 1000 + assert "honest_assessment" in result + assert "alternatives" in result + assert "is_feasible" in result["income_impact"] + + +def test_family_plan_two_children(): + result = plan_family_finances( + current_city="Austin", + annual_income=120000, + partner_income=80000, + num_planned_children=2, + ) + one_child = plan_family_finances("Austin", 120000, num_planned_children=1) + assert ( + result["monthly_cost_breakdown"]["childcare_monthly"] + > one_child["monthly_cost_breakdown"]["childcare_monthly"] + ) + + +def test_family_plan_partner_reduces_hours(): + result = plan_family_finances( + current_city="Austin", + annual_income=150000, + partner_income=80000, + partner_work_reduction=0.5, + num_planned_children=1, + ) + assert result["monthly_cost_breakdown"]["income_reduction_monthly"] > 0 + + +def test_family_plan_international_cheaper(): + result_berlin = plan_family_finances("Berlin", 120000, num_planned_children=1) + result_austin = plan_family_finances("Austin", 120000, num_planned_children=1) + assert ( + result_berlin["monthly_cost_breakdown"]["childcare_monthly"] + < result_austin["monthly_cost_breakdown"]["childcare_monthly"] + ) + + +def test_family_plan_shows_alternatives(): + result = plan_family_finances("Austin", 120000, num_planned_children=1) + assert "alternatives" in result + # Austin should suggest Williamson County as cheaper + assert len(result["alternatives"]) > 0 + + +def test_family_plan_what_helps(): + result = plan_family_finances("Austin", 80000, num_planned_children=1) + assert "what_helps" in result + assert len(result["what_helps"]) > 0 + assert "disclaimer" in result diff --git a/tools/family_planner.py b/tools/family_planner.py new file mode 100644 index 000000000..85752bdf1 --- /dev/null +++ b/tools/family_planner.py @@ -0,0 +1,217 @@ +""" +Family Financial Planner +Models the financial impact of having children for any city worldwide. +Source: US Dept of Labor + Care.com 2024 averages +""" + +CHILDCARE_ANNUAL = { + "san francisco": 31000, "san-francisco": 31000, + "seattle": 26000, + "new york": 29000, "new-york": 29000, "nyc": 29000, + "boston": 28000, + "washington dc": 27000, "dc": 27000, + "los angeles": 24000, "la": 24000, + "chicago": 22000, + "portland": 22000, + "denver": 20000, + "minneapolis": 20000, + "austin": 18000, + "travis county": 18000, + "atlanta": 18000, + "miami": 19000, + "nashville": 17000, + "raleigh": 17000, + "williamson county": 16000, + "round rock": 16000, + "cedar park": 16000, + "dallas": 16000, + "houston": 16000, + "hays county": 15000, + "san marcos": 15000, + "kyle": 15000, + "phoenix": 15000, + "bastrop county": 14000, + "caldwell county": 13000, + "lockhart": 13000, + "london": 22000, + "toronto": 18000, + "sydney": 16000, + "berlin": 4000, + "paris": 5000, + "tokyo": 8000, + "amsterdam": 6000, + "stockholm": 5000, + "default": 18000, +} + + +def _estimate_monthly_take_home(annual_salary: float, city: str = "") -> float: + if annual_salary <= 44725: + federal = 0.12 + elif annual_salary <= 95375: + federal = 0.22 + elif annual_salary <= 200000: + federal = 0.24 + else: + federal = 0.32 + fica = 0.0765 + no_tax = [ + "tx", "wa", "fl", "nv", "tn", "wy", "sd", "ak", + "texas", "washington", "florida", "austin", "seattle", + "dallas", "houston", "nashville", "miami", + ] + state = 0.0 if any(s in city.lower() for s in no_tax) else 0.05 + return (annual_salary * (1 - federal - fica - state)) / 12 + + +def plan_family_finances( + current_city: str, + annual_income: float, + partner_income: float = 0, + portfolio_value: float = 0, + num_planned_children: int = 1, + timeline_years: int = 5, + partner_work_reduction: float = 0.0, +) -> dict: + """Model the financial impact of having children.""" + + city_lower = current_city.lower() + + # Step 1: Get childcare cost + annual_childcare = CHILDCARE_ANNUAL.get("default", 18000) + for key in CHILDCARE_ANNUAL: + if key in city_lower or city_lower in key: + annual_childcare = CHILDCARE_ANNUAL[key] + break + monthly_childcare = (annual_childcare / 12) * num_planned_children + + # Step 2: Get median rent for city + RENT_LOOKUP = { + "austin": 2100, "travis": 2100, + "williamson": 1995, "round rock": 1995, + "hays": 1937, "san marcos": 1937, + "bastrop": 1860, "caldwell": 1750, + "seattle": 2400, "san francisco": 3200, + "new york": 3800, "boston": 3100, + "denver": 1900, "chicago": 1850, + "miami": 2800, "nashville": 1800, + "los angeles": 2900, "dallas": 1700, + "london": 2800, "tokyo": 1800, + "berlin": 1600, "paris": 2200, + } + rent = 2000 + for key, val in RENT_LOOKUP.items(): + if key in city_lower: + rent = val + break + + # Step 3: Calculate income + total_income = annual_income + partner_income + reduced_partner = partner_income * (1 - partner_work_reduction) + effective_income = annual_income + reduced_partner + income_reduction = partner_income - reduced_partner + + # Step 4: Monthly financials + take_home_before = _estimate_monthly_take_home(total_income, current_city) + take_home_after = _estimate_monthly_take_home(effective_income, current_city) + + food_clothing = 800 * num_planned_children + healthcare = 300 * num_planned_children + family_rent = rent * 1.3 + + total_new_costs = monthly_childcare + food_clothing + healthcare + + surplus_before = take_home_before - (rent * 1.8) + surplus_after = take_home_after - (family_rent * 1.6) - total_new_costs + + # Step 5: Income needed to maintain current surplus + current_surplus = take_home_before - (rent * 1.8) + income_needed = effective_income + test_income = effective_income + while True: + test_take_home = _estimate_monthly_take_home(test_income, current_city) + test_surplus = test_take_home - (family_rent * 1.6) - total_new_costs + if test_surplus >= current_surplus or test_income > 500000: + income_needed = test_income + break + test_income += 5000 + + # Step 6: Alternatives (cheaper nearby option for Austin users) + alternatives = [] + if "austin" in city_lower or "travis" in city_lower: + wilco_childcare = CHILDCARE_ANNUAL.get("williamson county", 16000) + wilco_rent = 1995 + savings = ( + (annual_childcare - wilco_childcare) / 12 + + (rent - wilco_rent) + ) + if savings > 0: + alternatives.append({ + "option": "Move to Williamson County", + "monthly_savings": round(savings), + "note": f"Saves ~${savings:,.0f}/mo vs Austin City", + }) + + # Step 7: International comparison + intl = { + "austin": annual_childcare, + "berlin": CHILDCARE_ANNUAL["berlin"], + "paris": CHILDCARE_ANNUAL["paris"], + "stockholm": CHILDCARE_ANNUAL.get("stockholm", 5000), + "note": "Western Europe has heavily subsidized childcare", + } + + # Honest assessment + if surplus_after > 0: + honest_assessment = ( + f"Having {num_planned_children} child(ren) in {current_city} adds " + f"~${round(total_new_costs):,}/mo in costs. " + f"You would have ${round(surplus_after):,}/mo surplus after family expenses — " + f"this is financially feasible." + ) + else: + shortfall = abs(round(surplus_after)) + honest_assessment = ( + f"Having {num_planned_children} child(ren) in {current_city} adds " + f"~${round(total_new_costs):,}/mo in costs. " + f"Your current income leaves a ${shortfall:,}/mo shortfall after family expenses. " + f"You'd need ~${income_needed:,}/yr combined income to maintain your current lifestyle." + ) + + return { + "family_plan": { + "city": current_city, + "num_children": num_planned_children, + "timeline_years": timeline_years, + }, + "monthly_cost_breakdown": { + "childcare_monthly": round(monthly_childcare), + "food_clothing_misc": round(food_clothing), + "healthcare_increase": round(healthcare), + "housing_increase_for_space": round(family_rent - rent), + "total_new_monthly_costs": round(total_new_costs), + "income_reduction_monthly": round(income_reduction / 12), + }, + "income_impact": { + "take_home_before_kids": round(take_home_before), + "take_home_after_kids": round(take_home_after), + "monthly_surplus_before": round(surplus_before), + "monthly_surplus_after": round(surplus_after), + "is_feasible": surplus_after > 0, + "income_needed_to_maintain_surplus": round(income_needed), + }, + "honest_assessment": honest_assessment, + "alternatives": alternatives, + "what_helps": [ + f"Family member childcare eliminates ${round(monthly_childcare):,}/mo in costs", + "Nanny share splits childcare cost ~50%", + "Employer childcare benefits (check your benefits package)", + "Dependent Care FSA saves taxes on up to $5,000/yr", + ], + "international_comparison": intl, + "disclaimer": ( + "Cost estimates vary significantly by provider. " + "Actual costs depend on childcare type and location." + ), + "data_source": "US Dept of Labor + Care.com 2024 averages", + }