
Debt Management
- 417 installs
- 161 repo stars
- Updated July 18, 2026
- joellewis/finance_skills
debt-management is a Claude Code finance skill that structures debt payoff, refinancing, and DTI analysis for developers building personal-finance copilots, planner tools, or advisor workflows involving credit and loans.
About
debt-management is a wealth-management plugin skill inside joellewis/finance_skills, a collection of 84 skills across 7 domain plugins for financial services in Claude Code. The skill teaches agents to compare debt avalanche versus snowball payoff strategies with month-by-month simulations, calculate front-end and back-end debt-to-income ratios against mortgage guidelines, analyze refinancing breakeven months including closing costs, and evaluate debt consolidation and balance transfer offers. Six key formulas cover DTI ratios, refinance breakeven, amortization payoff months, total interest, and after-tax effective rates. Worked examples walk through three-debt comparisons saving roughly 158 dollars under avalanche versus snowball and a 51,000 dollar interest savings refinance scenario. A bundled debt_management.py script supports demo runs and --verify checks. Developers reach for debt-management when building budgeting apps, financial advisor copilots, or wealth-management chatbots that must recommend prioritized payoff plans with quantitative backing.
- Liability prioritization frameworks
- Refinance tradeoff analysis
- Cash-flow impact modeling
- Advice-boundary guardrails
- Household debt scenarios
Debt Management by the numbers
- 417 all-time installs (skills.sh)
- +17 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #233 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joellewis/finance_skills --skill debt-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 417 |
|---|---|
| repo stars | ★ 161 |
| Last updated | July 18, 2026 |
| Repository | joellewis/finance_skills ↗ |
How do you compare debt avalanche vs snowball?
Structure debt payoff, refinancing, and liability prioritization advice when scoping personal-finance copilots, planner tools, or advisor workflows touching credit and loans.
Who is it for?
Developers building personal-finance copilots or advisory tools who need quantitative debt payoff, DTI, and refinancing logic with worked examples and a Python reference script.
Skip if: Institutional fixed-income trading, corporate treasury management, or general investment portfolio allocation unrelated to personal liability payoff.
When should I use this skill?
A user asks about debt payoff strategies, avalanche vs snowball, refinancing breakeven, DTI for mortgages, or credit card prioritization in a finance agent.
What you get
Prioritized debt payoff plan, DTI ratio calculations, refinancing breakeven analysis, total interest projections, and verified outputs from debt_management.py simulations.
- debt payoff plan
- DTI ratio analysis
- refinancing breakeven report
By the numbers
- Part of finance_skills collection with 84 skills across 7 domain plugins
- Documents 6 key debt formulas including DTI and refinance breakeven
Files
Debt Management
Core Concepts
Debt Avalanche
Pay minimum payments on all debts, then direct all extra payment to the debt with the highest interest rate first:
- Mathematically optimal: Minimizes total interest paid over the life of all debts
- Once the highest-rate debt is paid off, the freed-up payment rolls to the next highest rate
- Requires discipline — the highest-rate debt may also be the largest balance, meaning slow visible progress initially
- Always saves money compared to snowball, though the difference varies by debt profile
Debt Snowball
Pay minimum payments on all debts, then direct all extra payment to the debt with the smallest balance first:
- Psychologically effective: Quick wins build momentum and motivation
- Research (Kellogg School) shows people are more likely to stick with snowball and actually become debt-free
- May cost more in total interest than avalanche, but adherence is higher
- Best for individuals who need motivational wins to stay committed
Debt-to-Income Ratio (DTI)
Total monthly debt payments expressed as a percentage of gross monthly income:
- Front-end DTI (housing ratio): Monthly housing costs (PITI: principal, interest, taxes, insurance) / gross monthly income
- Guideline: < 28%
- Back-end DTI (total debt ratio): All monthly debt payments (housing + car + student loans + credit cards + other) / gross monthly income
- Guideline: < 36% (conventional), up to 43% (FHA), some lenders allow up to 50% for qualified borrowers
- DTI is a key factor in mortgage qualification and overall financial health assessment
Refinancing Analysis
Compare the total cost of the existing loan vs the new loan, accounting for closing costs:
- Monthly savings: Old payment - new payment
- Breakeven months: Total closing costs / monthly savings
- Total cost comparison: Sum of all remaining payments (old) vs sum of all payments (new) + closing costs
- If you plan to keep the loan beyond the breakeven point, refinancing saves money
- Consider: remaining term, resetting the amortization clock, and cash-out implications
Debt Consolidation
Combine multiple debts into a single loan, ideally at a lower interest rate:
- Potential benefits: Lower rate, single payment, simplified management
- Risks: Longer term may increase total interest even at lower rate; freed-up credit lines may tempt new borrowing
- Evaluate: Compare total interest paid (all debts independently) vs total interest paid (consolidated loan)
- Balance transfer cards (0% intro rate) can be effective but require payoff before the rate expires
Good Debt vs Bad Debt
- Good debt: Low interest rate, potentially tax-deductible, finances an appreciating asset or increases earning power (mortgage, student loans, business loans)
- Bad debt: High interest rate, finances depreciating assets or consumption (credit cards, payday loans, auto loans on luxury vehicles)
- The line is not absolute — a low-rate auto loan for a reliable commuter car can be reasonable
Opportunity Cost Analysis
When debt carries a low interest rate, paying it off aggressively may not be optimal:
- Decision rule: If expected after-tax investment return > after-tax debt interest rate, investing the extra cash may build more wealth
- Example: 3.5% mortgage (2.5% after tax deduction) vs 7-10% expected equity returns — investing likely wins mathematically
- Caveats: Investment returns are uncertain, debt payoff is guaranteed; psychological benefit of being debt-free has real value
- Consider risk tolerance: guaranteed 3.5% return (debt payoff) vs variable 7-10% (investing)
Debt Payoff Timeline
Amortization calculation with extra payments:
- Standard amortization: n = -ln(1 - (P×r)/PMT) / ln(1+r)
- With extra payment: replace PMT with PMT + extra, recalculate n
- Total interest = (n × PMT) - P (adjusting for extra payments)
Key Formulas
| Formula | Expression | Use Case |
|---|---|---|
| Front-end DTI | Housing payments / gross monthly income | Mortgage qualification |
| Back-end DTI | All debt payments / gross monthly income | Overall debt health |
| Refinance breakeven | Closing costs / monthly savings | Months to recoup refi costs |
| Months to payoff | n = -ln(1 - Pr/PMT) / ln(1+r) | Debt payoff timeline |
| Total interest paid | (n × PMT) - Principal | Cost of borrowing |
| Effective rate (after tax) | r × (1 - marginal_tax_rate) | Tax-deductible debt comparison |
Worked Examples
Example 1: Avalanche vs snowball comparison
Given: Three debts with $500/month available for extra payments (above minimums):
- Credit card: $5,000 balance, 22% APR, $100 minimum
- Student loan: $12,000 balance, 6% APR, $200 minimum
- Personal loan: $3,000 balance, 15% APR, $75 minimum
Calculate: Order of payoff, total months, and total interest for each strategy (month-by-month simulation; see scripts/debt_management.py). Solution — Avalanche (highest rate first: 22% → 15% → 6%): 1. Pay minimums on all ($375/mo). Extra $500 goes to credit card ($600/mo total to CC). 2. Credit card ($5K at 22%, $600/mo): paid off in month 10, ~$476 interest. 3. Freed payment rolls to the personal loan ($75 + $600 = $675/mo to PL): paid off in month 14, ~$408 interest. 4. All payments roll to the student loan ($200 + $675 = $875/mo): paid off in month 26, ~$1,062 interest (the 6% loan accrues interest on its full $12K balance throughout the earlier phases, not just at the end). 5. Total: 26 months, ~$1,946 total interest.
Solution — Snowball (smallest balance first: $3K → $5K → $12K): 1. Extra $500 goes to personal loan ($575/mo total to PL). 2. Personal loan ($3K at 15%, $575/mo): paid off in month 6, ~$123 interest. 3. Freed payment rolls to the credit card ($100 + $575 = $675/mo): paid off in month 14, ~$911 interest. 4. All payments roll to the student loan: paid off in month 26, ~$1,071 interest. 5. Total: 26 months, ~$2,104 total interest.
Comparison: Avalanche saves ~$158 in interest; both finish in 26 months. The difference is modest because the highest-rate debt is not the largest. Snowball gives a quicker first win (month 6 vs month 10 to first payoff) — for many people that motivational difference is worth $158.
Example 2: Refinance breakeven
Given: Current mortgage: $300K remaining, 6.5%, 25 years left, payment $2,028/mo. New offer: 5.5%, 25 years, closing costs $6,000, payment $1,838/mo. Calculate: Breakeven period and total interest savings. Solution: 1. Monthly savings: $2,028 - $1,838 = $190/month. 2. Breakeven: $6,000 / $190 = 31.6 months ≈ 32 months (2 years 8 months). 3. If staying in the home beyond 32 months, refinancing saves money. 4. Total payments (old): 25 × 12 × $2,028 = $608,400 → total interest = $608,400 - $300,000 = $308,400. 5. Total payments (new): 25 × 12 × $1,838 + $6,000 = $557,400 → total interest = $557,400 - $300,000 = $257,400. 6. Total interest savings: $308,400 - $257,400 = $51,000.
Common Pitfalls
- Ignoring psychological factors — snowball works better for many people despite costing slightly more in interest
- Not including all closing costs in refinancing analysis (origination fees, appraisal, title insurance, points)
- Consolidation at a lower rate but longer term may cost more in total interest — always compare total cost
- Paying off low-rate debt instead of investing (opportunity cost) without considering risk tolerance and guaranteed vs uncertain returns
- Not considering tax deductibility of mortgage or student loan interest when comparing effective rates
- Making only minimum payments on high-interest debt while saving in low-yield accounts
- Consolidation freeing up credit lines that lead to new debt accumulation
- Ignoring the amortization reset: refinancing to a new 30-year term extends the payoff date
Cross-References
- lending: mortgage analysis, loan terms, and amortization calculations
- emergency-fund: adequate emergency fund prevents taking on new high-interest debt during crises
- savings-goals: debt payoff competes with savings goals for cash flow allocation
- tax-efficiency: tax deductibility of certain debt interest affects optimal payoff order
- liquidity-management: debt payments are fixed obligations in cash flow planning
- financial-planning-workflow (advisory-practice plugin): debt payoff strategies are evaluated during the cash flow and recommendation phases of financial planning
Running the Script
uv run scripts/debt_management.py # run the demo (uses PEP 723 inline deps)
uv run scripts/debt_management.py --verify # check demo outputs against the worked examples (exit 1 on mismatch)
python3 scripts/debt_management.py # alternative (requires: pip install numpy)The demo prints the calculations covered above; its values match the worked examples in this skill. Run --help for a list of the classes and functions. For programmatic use, import the module rather than running it — the demo only executes under python debt_management.py.
# /// script
# dependencies = ["numpy"]
# requires-python = ">=3.11"
# ///
"""
Debt Management
===============
Compute debt payoff strategies (avalanche vs snowball), amortization schedules,
refinancing breakeven, debt-to-income ratios, and opportunity cost analysis.
Part of Layer 6 (Personal Finance) in the finance skills framework.
"""
import argparse
import sys
import math
from dataclasses import dataclass
import numpy as np
@dataclass
class Debt:
"""Represents a single debt obligation.
Parameters
----------
name : str
Descriptive label for the debt.
balance : float
Current outstanding balance in dollars.
apr : float
Annual percentage rate as a decimal (e.g., 0.22 for 22%).
minimum_payment : float
Required minimum monthly payment in dollars.
"""
name: str
balance: float
apr: float
minimum_payment: float
class DebtManagement:
"""Debt management computations: payoff strategies, amortization,
refinancing, and DTI analysis.
Parameters
----------
debts : list[Debt]
List of Debt objects representing outstanding obligations.
extra_payment : float, optional
Additional monthly payment above all minimums. Default is 0.0.
"""
def __init__(self, debts: list[Debt], extra_payment: float = 0.0):
self.debts = [Debt(d.name, d.balance, d.apr, d.minimum_payment) for d in debts]
self.extra_payment = extra_payment
@staticmethod
def months_to_payoff(balance: float, apr: float, payment: float) -> float:
"""Compute months to pay off a debt with fixed payments.
Uses n = -ln(1 - P*r/PMT) / ln(1+r).
Parameters
----------
balance : float
Outstanding principal.
apr : float
Annual percentage rate as a decimal.
payment : float
Monthly payment amount.
Returns
-------
float
Number of months to payoff. Returns inf if payment does not
cover interest.
"""
if balance <= 0:
return 0.0
r = apr / 12.0
if r == 0:
return balance / payment if payment > 0 else float("inf")
if payment <= balance * r:
return float("inf")
n = -math.log(1.0 - (balance * r) / payment) / math.log(1.0 + r)
return n
@staticmethod
def total_interest(balance: float, apr: float, payment: float) -> float:
"""Compute total interest paid over the life of a debt.
Parameters
----------
balance : float
Outstanding principal.
apr : float
Annual percentage rate as a decimal.
payment : float
Monthly payment amount.
Returns
-------
float
Total interest paid in dollars.
"""
n = DebtManagement.months_to_payoff(balance, apr, payment)
if math.isinf(n):
return float("inf")
# Last payment may be partial, so simulate
r = apr / 12.0
total_interest_paid = 0.0
remaining = balance
while remaining > 0:
interest = remaining * r
total_interest_paid += interest
principal_portion = min(payment - interest, remaining)
remaining -= principal_portion
if payment <= interest:
return float("inf")
return total_interest_paid
@staticmethod
def amortization_schedule(
balance: float, apr: float, payment: float, extra: float = 0.0
) -> np.ndarray:
"""Generate a full amortization schedule.
Parameters
----------
balance : float
Loan principal.
apr : float
Annual percentage rate as a decimal.
payment : float
Base monthly payment.
extra : float, optional
Extra monthly principal payment. Default is 0.0.
Returns
-------
np.ndarray
Structured array with columns: month, payment, interest,
principal, extra_principal, remaining_balance.
"""
r = apr / 12.0
rows: list[tuple[int, float, float, float, float, float]] = []
remaining = balance
month = 0
while remaining > 0.005: # threshold for rounding
month += 1
interest = remaining * r
base_principal = min(payment - interest, remaining)
if base_principal < 0:
# Payment doesn't cover interest
break
remaining -= base_principal
extra_applied = min(extra, remaining)
remaining -= extra_applied
actual_payment = interest + base_principal + extra_applied
rows.append(
(month, actual_payment, interest, base_principal, extra_applied, max(remaining, 0.0))
)
dtype = np.dtype(
[
("month", np.int32),
("payment", np.float64),
("interest", np.float64),
("principal", np.float64),
("extra_principal", np.float64),
("remaining_balance", np.float64),
]
)
return np.array(rows, dtype=dtype)
@staticmethod
def apr_to_effective_rate(apr: float, compounding_periods: int = 12) -> float:
"""Convert APR to effective annual rate.
EAR = (1 + APR/m)^m - 1
Parameters
----------
apr : float
Nominal annual percentage rate as a decimal.
compounding_periods : int, optional
Number of compounding periods per year. Default is 12 (monthly).
Returns
-------
float
Effective annual rate as a decimal.
"""
return (1.0 + apr / compounding_periods) ** compounding_periods - 1.0
@staticmethod
def after_tax_rate(apr: float, marginal_tax_rate: float) -> float:
"""Compute the effective after-tax interest rate for tax-deductible debt.
effective_rate = apr * (1 - marginal_tax_rate)
Parameters
----------
apr : float
Annual interest rate as a decimal.
marginal_tax_rate : float
Marginal tax rate as a decimal.
Returns
-------
float
After-tax effective rate as a decimal.
"""
return apr * (1.0 - marginal_tax_rate)
@staticmethod
def debt_to_income(
monthly_debt_payments: float, gross_monthly_income: float
) -> float:
"""Compute the back-end debt-to-income ratio.
DTI = monthly debt payments / gross monthly income
Parameters
----------
monthly_debt_payments : float
Total monthly debt obligations.
gross_monthly_income : float
Gross monthly income before taxes.
Returns
-------
float
DTI ratio as a decimal (e.g., 0.36 = 36%).
"""
if gross_monthly_income <= 0:
return float("inf")
return monthly_debt_payments / gross_monthly_income
@staticmethod
def front_end_dti(
monthly_housing_cost: float, gross_monthly_income: float
) -> float:
"""Compute the front-end (housing) debt-to-income ratio.
Front-end DTI = housing costs / gross monthly income
Parameters
----------
monthly_housing_cost : float
Monthly housing payment (PITI: principal, interest, taxes, insurance).
gross_monthly_income : float
Gross monthly income before taxes.
Returns
-------
float
Front-end DTI ratio as a decimal.
"""
if gross_monthly_income <= 0:
return float("inf")
return monthly_housing_cost / gross_monthly_income
@staticmethod
def refinance_breakeven(
closing_costs: float, old_payment: float, new_payment: float
) -> float:
"""Compute the refinancing breakeven period in months.
Breakeven = closing costs / monthly savings
Parameters
----------
closing_costs : float
Total refinancing closing costs.
old_payment : float
Current monthly payment.
new_payment : float
New monthly payment after refinancing.
Returns
-------
float
Months to breakeven. Returns inf if new payment is not lower.
"""
savings = old_payment - new_payment
if savings <= 0:
return float("inf")
return closing_costs / savings
def payoff_avalanche(self) -> dict:
"""Simulate debt payoff using the avalanche strategy (highest rate first).
Returns
-------
dict
Keys: 'total_months', 'total_interest', 'total_paid',
'payoff_order' (list of dicts with name, month_paid_off, interest_paid).
"""
return self._simulate_payoff(strategy="avalanche")
def payoff_snowball(self) -> dict:
"""Simulate debt payoff using the snowball strategy (smallest balance first).
Returns
-------
dict
Keys: 'total_months', 'total_interest', 'total_paid',
'payoff_order' (list of dicts with name, month_paid_off, interest_paid).
"""
return self._simulate_payoff(strategy="snowball")
def _simulate_payoff(self, strategy: str) -> dict:
"""Simulate multi-debt payoff month by month.
Parameters
----------
strategy : str
'avalanche' (highest APR first) or 'snowball' (lowest balance first).
Returns
-------
dict
Payoff results including total months, interest, and order.
"""
# Deep copy balances
balances = {d.name: d.balance for d in self.debts}
rates = {d.name: d.apr / 12.0 for d in self.debts}
minimums = {d.name: d.minimum_payment for d in self.debts}
interest_paid = {d.name: 0.0 for d in self.debts}
paid_off: set[str] = set()
payoff_order: list[dict] = []
total_paid = 0.0
month = 0
max_months = 1200 # safety limit (100 years)
while any(b > 0.005 for b in balances.values()) and month < max_months:
month += 1
# Determine priority order for extra payment
active = [name for name in balances if balances[name] > 0.005]
if not active:
break
if strategy == "avalanche":
active.sort(key=lambda n: rates[n], reverse=True)
else: # snowball
active.sort(key=lambda n: balances[n])
# Apply interest to all active debts
for name in active:
interest = balances[name] * rates[name]
interest_paid[name] += interest
balances[name] += interest
# Freed minimums from already-paid-off debts snowball into the
# extra payment every month for the rest of the simulation.
extra_available = self.extra_payment + sum(
minimums[name] for name in paid_off
)
# Pay minimums on active debts
for name in list(active):
pay = min(minimums[name], balances[name])
balances[name] -= pay
total_paid += pay
if balances[name] <= 0.005:
# Unused portion of this debt's minimum is freed this month
extra_available += minimums[name] - pay
balances[name] = 0.0
paid_off.add(name)
payoff_order.append(
{
"name": name,
"month_paid_off": month,
"interest_paid": round(interest_paid[name], 2),
}
)
# Apply extra payment + freed minimums to priority debt(s)
# Recalculate active after minimum payments
active = [name for name in balances if balances[name] > 0.005]
if strategy == "avalanche":
active.sort(key=lambda n: rates[n], reverse=True)
else:
active.sort(key=lambda n: balances[n])
for name in active:
if extra_available <= 0:
break
apply = min(extra_available, balances[name])
balances[name] -= apply
total_paid += apply
extra_available -= apply
if balances[name] <= 0.005:
balances[name] = 0.0
paid_off.add(name)
payoff_order.append(
{
"name": name,
"month_paid_off": month,
"interest_paid": round(interest_paid[name], 2),
}
)
total_interest = sum(interest_paid.values())
return {
"total_months": month,
"total_interest": round(total_interest, 2),
"total_paid": round(total_paid, 2),
"payoff_order": payoff_order,
}
def compare_strategies(self) -> dict:
"""Compare avalanche and snowball strategies side by side.
Returns
-------
dict
Keys: 'avalanche', 'snowball', 'interest_difference',
'months_difference'.
"""
avalanche = self.payoff_avalanche()
snowball = self.payoff_snowball()
return {
"avalanche": avalanche,
"snowball": snowball,
"interest_difference": round(
snowball["total_interest"] - avalanche["total_interest"], 2
),
"months_difference": snowball["total_months"] - avalanche["total_months"],
}
def _demo() -> None:
# ----------------------------------------------------------------
# Demo: Debt management computations
# ----------------------------------------------------------------
print("=" * 60)
print("Debt Management - Demo")
print("=" * 60)
# --- Example 1: Avalanche vs Snowball ---
print("\n--- Example 1: Avalanche vs Snowball Comparison ---")
debts = [
Debt("Credit Card", 5000, 0.22, 100),
Debt("Student Loan", 12000, 0.06, 200),
Debt("Personal Loan", 3000, 0.15, 75),
]
dm = DebtManagement(debts, extra_payment=500)
comparison = dm.compare_strategies()
for strategy_name in ("avalanche", "snowball"):
result = comparison[strategy_name]
print(f"\n {strategy_name.upper()}:")
print(f" Total months: {result['total_months']}")
print(f" Total interest: ${result['total_interest']:,.2f}")
for entry in result["payoff_order"]:
print(
f" {entry['name']:20s} paid off month {entry['month_paid_off']:3d}"
f" (interest: ${entry['interest_paid']:,.2f})"
)
print(f"\n Avalanche saves ${comparison['interest_difference']:,.2f} in interest")
print(f" Avalanche saves {comparison['months_difference']} month(s)")
# --- Example 2: Amortization Schedule ---
print("\n--- Example 2: Amortization Schedule (first 6 months) ---")
schedule = DebtManagement.amortization_schedule(
balance=300_000, apr=0.065, payment=1896, extra=200
)
print(f" {'Month':>5} {'Payment':>10} {'Interest':>10} {'Principal':>10} {'Extra':>8} {'Balance':>12}")
for row in schedule[:6]:
print(
f" {row['month']:5d} ${row['payment']:9,.2f} ${row['interest']:9,.2f}"
f" ${row['principal']:9,.2f} ${row['extra_principal']:7,.2f} ${row['remaining_balance']:11,.2f}"
)
print(f" ... total months: {len(schedule)}")
total_int = float(np.sum(schedule["interest"]))
print(f" Total interest paid: ${total_int:,.2f}")
# --- Example 3: Refinance Breakeven ---
print("\n--- Example 3: Refinance Breakeven ---")
old_pmt = 2028
new_pmt = 1838
costs = 6000
be_months = DebtManagement.refinance_breakeven(costs, old_pmt, new_pmt)
print(f" Old payment: ${old_pmt:,.2f}/mo")
print(f" New payment: ${new_pmt:,.2f}/mo")
print(f" Closing costs: ${costs:,.2f}")
print(f" Breakeven: {be_months:.1f} months ({be_months/12:.1f} years)")
# --- Example 4: DTI Ratios ---
print("\n--- Example 4: Debt-to-Income Ratios ---")
gross_income = 8500
housing = 1800
total_debt = 1800 + 500 + 200 + 100 # housing + car + student + cc
fe_dti = DebtManagement.front_end_dti(housing, gross_income)
be_dti = DebtManagement.debt_to_income(total_debt, gross_income)
print(f" Gross monthly income: ${gross_income:,.2f}")
print(f" Front-end DTI: {fe_dti:.2%} (guideline: <28%)")
print(f" Back-end DTI: {be_dti:.2%} (guideline: <36%)")
# --- Example 5: APR to Effective Rate ---
print("\n--- Example 5: APR to Effective Rate ---")
apr_val = 0.22
ear = DebtManagement.apr_to_effective_rate(apr_val)
after_tax = DebtManagement.after_tax_rate(0.065, 0.24)
print(f" 22% APR (monthly compounding) -> EAR = {ear:.4%}")
print(f" 6.5% mortgage (24% tax bracket) -> after-tax rate = {after_tax:.4%}")
print("\n" + "=" * 60)
print("Demo complete.")
print("=" * 60)
def _check(failures: list, name: str, actual: float, expected: float, tol: float) -> None:
"""Record a verification check result."""
ok = abs(actual - expected) <= tol
status = "PASS" if ok else "FAIL"
print(f" [{status}] {name}: actual={actual:.6g}, expected={expected:.6g}, tol={tol:.2g}")
if not ok:
failures.append(name)
def _verify() -> None:
"""Verify key outputs against the SKILL.md worked examples."""
failures: list = []
# SKILL.md Example 1: avalanche vs snowball
debts = [
Debt("Credit Card", 5000, 0.22, 100),
Debt("Student Loan", 12000, 0.06, 200),
Debt("Personal Loan", 3000, 0.15, 75),
]
dm = DebtManagement(debts, extra_payment=500)
av = dm.payoff_avalanche()
sb = dm.payoff_snowball()
_check(failures, "Ex1 avalanche months", av["total_months"], 26, 0)
_check(failures, "Ex1 avalanche interest", av["total_interest"], 1945.92, 1.0)
_check(failures, "Ex1 avalanche total paid = principal + interest",
av["total_paid"], 20000 + av["total_interest"], 0.5)
_check(failures, "Ex1 avalanche first payoff (CC) month",
av["payoff_order"][0]["month_paid_off"], 10, 0)
_check(failures, "Ex1 snowball months", sb["total_months"], 26, 0)
_check(failures, "Ex1 snowball interest", sb["total_interest"], 2104.35, 1.0)
_check(failures, "Ex1 snowball first payoff (PL) month",
sb["payoff_order"][0]["month_paid_off"], 6, 0)
# SKILL.md Example 2: refinance breakeven
_check(failures, "Ex2 refinance breakeven months",
DebtManagement.refinance_breakeven(6000, 2028, 1838), 31.58, 0.01)
if failures:
print(f"\n{len(failures)} check(s) FAILED: {', '.join(failures)}")
sys.exit(1)
print("\nAll checks passed.")
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__.strip().splitlines()[2] if __doc__ else "",
epilog=(
"Provides: Debt, DebtManagement. "
"For programmatic use, import this module (debt_management) instead of running it. "
"Bare run executes a demo whose printed values match the SKILL.md worked examples; "
"--verify asserts those values and exits nonzero on mismatch."
),
)
parser.add_argument(
"--verify",
action="store_true",
help="run the verification checks against the SKILL.md worked-example values",
)
args = parser.parse_args()
if args.verify:
_verify()
else:
_demo()
if __name__ == "__main__":
main()
Related skills
How it compares
Pick debt-management over generic budgeting skills when you need quantified avalanche versus snowball simulations, DTI mortgage guidelines, and refinancing breakeven math with a verified Python reference script.
FAQ
What strategies does debt-management compare?
debt-management compares debt avalanche (highest interest rate first, mathematically optimal) and debt snowball (smallest balance first, psychologically motivating). Worked examples simulate three debts over 26 months showing avalanche saves roughly 158 dollars in total interest.
What DTI guidelines does debt-management use?
debt-management calculates front-end DTI with a under 28% housing guideline and back-end DTI with a under 36% total debt guideline for conventional mortgages, noting FHA allows up to 43% and some lenders accept 50% for qualified borrowers.
Does debt-management include a reference script?
debt-management bundles debt_management.py runnable via uv run scripts/debt_management.py for demo simulations. The --verify flag checks demo outputs against the skill's worked examples and exits with code 1 on any mismatch.