agentleFS
KameronKalesKameronKales/planfi-skills/skills/fire-tracker/SKILL.md

fire-tracker

Skill0 starsChanged 4 months agoMITView on GitHub

Track FIRE progress by orchestrating the public planfi MCP. Use whenever someone wants to know whether they're already financially independent or can coast, how their savings/net worth benchmark against peers, which net-worth milestones they've hit, or whether they can retire by a target age and which levers get them there — e.g. "am I already financially independent?", "can I coast to retirement?", "how do I compare to other people my age?", "what milestones have I hit?", "can I retire by 50?".

The file

We split this skill into the rules it gives an agent

9 rules. About 0 are common, 4 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    All the math — the already-won surplus/cushion test, peer benchmarking, milestone thresholds, and the goal solver's lever ranking — lives …

    line 10
  2. Distinctive:

    If they're NOT available, tell the user to connect the MCP, then continue:

    line 21
  3. Very specific:

    If the user has (or wants) a full household model, call generate_financial_plan once and

    line 36
  4. Very specific:

    When the Barista bridge looks feasible (barista_fire_pct ≥ 100 or close, barista_spending_gap comfortably covered), chain …

    line 118
  5. Very specific:

    Read back the headline + the tool's assumed_defaults[].

    line 189
  6. Very specific:

    Follow any next_actions[] the tool returns (solve_goal suggests generate_action_plan).

    line 190
  7. Distinctive:

    All rates/decimals are fractions.

    line 220
  8. Very specific:

    All five tools return a structured assumed_defaults[] ({ field, assumed_value, note }) — read it back to the user.

    line 230
  9. Distinctive:

    Not financial advice. Planning estimates only.

    line 235

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

FIRE Tracker

A thin orchestration layer over the planfi MCP (https://ai.planfi.app/mcp/free). All the math — the already-won surplus/cushion test, peer benchmarking, milestone thresholds, and the goal solver's lever ranking — lives server-side. This skill only gathers inputs and calls the tools — it does not compute anything locally and bakes in no defaults of its own. Read-only.

Step 0 — Make sure the planfi tools are connected

This skill uses these tools (may be namespaced, e.g. mcp__planfi__analyze_already_won): analyze_already_won, analyze_fire_benchmark, analyze_fire_variants, analyze_milestones, what_if_plan. solve_goal, plus optional generate_financial_plan (for plan_id chaining + a share_url). Use whichever name your environment exposes (bare or mcp__planfi__-prefixed); below they are written bare.

If they're NOT available, tell the user to connect the MCP, then continue:

claude mcp add --transport http planfi https://ai.planfi.app/mcp/free

Try free, then add your key. The command above adds the free connector — https://ai.planfi.app/mcp/free (no key needed). Once you create an API key, add a new connector with the MCP url — https://ai.planfi.app/mcp — and authorize it with your key.

(On claude.ai: add a custom connector pointing at https://ai.planfi.app/mcp/free.)

Access — free for personal use. The planfi MCP is free to try (a small monthly allowance, no key needed). Heavy automated abuse forced us to add limits — but it stays free for personal use: email kam@rateapi.dev and we'll send you a free API key, no charge. (Companies and commercial use have paid plans.) To use a key, pass it as an Authorization: Bearer pft_… header in your MCP client config.

Step 1 — (Optional but preferred) build a plan first to chain context + get a share link

If the user has (or wants) a full household model, call generate_financial_plan once and capture the returned plan_id. Four of the five tools — analyze_already_won, analyze_milestones, analyze_fire_variants, and solve_goal — accept { plan_id } (plus an overrides object), so they can resolve the household from the saved plan instead of you re-sending every figure. generate_financial_plan returns a share_url (planfi.app). analyze_already_won and analyze_fire_variants also return a share_url whenever you pass a plan_id that resolves, and solve_goal returns a share_url on every call (it always builds one from the resolved plan).

analyze_fire_benchmark is the exception: it takes raw inputs ONLY (NO plan_id). Pass its figures (annual_income, annual_savings, liquid_net_worth) directly — do not try to chain a plan_id into it.

This step is optional: every tool below runs from raw inputs too. Prefer the plan path when the session already has a model, when the user is asking more than one of these questions, or when they want a sharable artifact.

Engine facts to bake in: all rates/decimals are fractions (a 40% savings rate → 0.40); all dollars are today's (real) dollars; any bracket/threshold figures are approximate ~2026 values.

Step 2 — Route by intent

Pick the tool that matches what the user is asking. Pass { plan_id } when you have one (except for analyze_fire_benchmark); the raw fields below are still REQUIRED where noted.

"Am I already financially independent?" / "Have I already won?" / "Can I coast from here?" / "Is $1.6M enough to stop saving?" / "Do I even need to keep working?" → analyze_already_won

Always CALL analyze_already_won for these — do not answer from general knowledge or quote the 4% rule / "25x expenses" from memory. When the user gives (or the plan has) net worth and spending, run it and lead with its real output — the actual verdict, surplus, and cushion — THEN explain. Returns whether the portfolio already covers spending — is_over_funded, fire_pct, surplus, cushion_years, current_safe_spend, one_more_year_safe_spend, and marginal_safe_spend_per_extra_year. REQUIRED: liquid_net_worth, annual_spend. Optional: safe_withdrawal_rate (default 0.04), fire_target_net_worth (else derived from annual_spend / safe_withdrawal_rate), annual_contributions (default 0), real_growth_rate (default 0.05). Accepts plan_id (+ an overrides object, + name for the share link).

analyze_already_won({ liquid_net_worth: 1600000, annual_spend: 60000 })

"How do I compare to peers?" / "What percentile am I in?" / "Is my savings rate good for my income?" / "Am I ahead or behind for someone earning $140k?" / "How does my net worth stack up?" → analyze_fire_benchmark (raw inputs only — NO plan_id)

Always CALL analyze_fire_benchmark for these — do not answer from general knowledge, cite median-net-worth surveys from memory, or eyeball a percentile. When the user gives income, savings, and net worth, run it and lead with its real output — the actual percentile band and cohort framing — THEN explain. Returns a savings_percentile_band, cohort_framing, savings_rate, years_to_fi, and net_worth_to_income_multiple versus a peer cohort. REQUIRED: annual_income, annual_savings, liquid_net_worth. Optional: safe_withdrawal_rate (default 0.04), real_return (default 0.05). There is NO plan_id, savings_rate, net_worth, income, or age input — savings rate and the percentile band are computed server-side from the three required figures.

analyze_fire_benchmark({ annual_income: 140000, annual_savings: 49000, liquid_net_worth: 450000 })

"What's my Lean / Fat / Barista FIRE number?" / "How much do I need for lean FIRE?" / "Could I Barista-FIRE on a part-time job?" / "What if I only need $45k a year vs $95k?" / "How far am I from fat FIRE?" → analyze_fire_variants

Always CALL analyze_fire_variants for these — do not answer from general knowledge or multiply spend by 25 in your head. The tiers, the after-tax Barista bridge, and each tier's timeline are all computed server-side; when the user gives the numbers, run it and lead with its real output, THEN explain. Computes the Lean / Standard / Fat target tiers (target net worth = annual spend / SWR). For each tier the tool returns {lean,standard,fat}_fire_number, {…}_fire_pct, and the ENGINE-COMPUTED timeline {…}_years_to_fire and {…}_fire_age (age = current_age + years; null when the tier is out of reach at the current savings rate). Plus an optional Barista-FIRE bridge where part-time NET income (after federal tax) covers a spending gap so a SMALLER portfolio is needed before full drawdown (barista_fire_number, barista_reduction_vs_full, barista_fire_pct). Quote {…}_fire_age and {…}_years_to_fire VERBATIM — never compute a retirement age or a "years from now" yourself. The tool already did it; deriving age from years (or vice-versa) in prose is how the "age 41 (15 years)" inconsistency happens. Lean ≤ Standard ≤ Fat in both years and age. REQUIRED: current_age, liquid_net_worth, annual_savings, base_annual_spend. Optional: lean_annual_spend (default 70% of base), fat_annual_spend (default 160% of base), safe_withdrawal_rate (0.04), real_return (0.05), filing_status (single), and for the bridge barista_part_time_income + barista_end_age (+ barista_other_taxable_income). Accepts plan_id (+ overrides, + name for the share link).

analyze_fire_variants({ current_age: 40, liquid_net_worth: 600000, annual_savings: 30000, base_annual_spend: 60000, barista_part_time_income: 25000, barista_end_age: 55 })

When the Barista bridge looks feasible (barista_fire_pct ≥ 100 or close, barista_spending_gap comfortably covered), chain analyze_already_won to confirm the smaller Barista number is already funded; when a tier is still short, chain solve_goal to rank the easiest levers to reach it. This tool returns assumed_defaults[], a share_url when a plan_id resolves, and next_actions[] edges (→ solve_goal, → analyze_already_won).

"What milestones have I hit?" / "Is $480k a big deal?" / "When do I cross my first $500k / $1M?" / "What's the next net-worth milestone for me?" / "Have I hit Coast FIRE yet?" → analyze_milestones

Always CALL analyze_milestones for these — do not answer from general knowledge or improvise a milestone list from memory. The thresholds and headlines are defined server-side; when the user gives a net worth, run it and lead with its real newly_reached[] output, THEN explain. Returns the net-worth milestones crossed in newly_reached[] (each { type, label, headline, net_worth }). REQUIRED: net_worth. Optional: coast_pct (enables the Coast FIRE milestone), fire_pct (enables the FIRE milestone), age (stamped on headlines), date (ISO; defaults today), already_logged[] (milestone types not to re-detect). Accepts plan_id (+ overrides) for context.

analyze_milestones({ net_worth: 450000 })

"what if we drop our 401k to the employer match next year" / "what if I stop maxing my accounts starting at age X" / "scale back contributions and spend the difference — what happens to my FIRE and Coast dates" / "single-change scenario against my saved plan" → what_if_plan

Always CALL what_if_plan for a single-change scenario against a saved plan — never adjust the numbers yourself, never re-send the household, and never narrate a scenario outcome the tool did not compute. Pass plan_id plus a small changes array of typed ops (401k_employer_match_only, 401k_stop, 401k_set_annual, ira_set_annual, hsa_set_annual, taxable_monthly_contribution, retirement_age, annual_salary, desired_annual_spend; "starting next year" → start_age = that earner's age + 1). Every unchanged field is inherited from the saved plan; quote the returned scenario_summary comparison (baseline vs scenario net worth, delta, FIRE ages) verbatim. Cross-link: to SOLVE for a target age instead of testing one change, use solve_goal.

"Can I retire by 50?" / "What would it take to retire at 55?" / "What if I save $500 more a month — does that move my FIRE date?" / "What if I cut spending / retire later / change my allocation?" / "Which lever gets me there fastest?" → solve_goal

Always CALL solve_goal for these — do not answer from general knowledge, quote a rule of thumb from memory, or hand-wave a what-if by adjusting numbers yourself. Every "can I retire by X" and every what-if about savings rate, retire age, spending, or allocation is a solver run against the real plan: run it and lead with its real output — feasible / already_achieved and the ranked levers — THEN explain. Never narrate a scenario outcome the solver did not actually compute. Solves for a target FIRE age and ranks the levers (savings rate, retire age, spend, allocation) that close the gap, easiest-first. REQUIRED: target_fire_age (20–100), plus a plan — either a full inline plan (earners[], stocks, …) OR a plan_id. Optional: levers[] (savings_rate | retire_age | spend | allocation), overrides, max_iterations, max_engine_calls, time_budget_ms. Always returns a share_url.

solve_goal({ target_fire_age: 50, plan_id: 'pl_abc123' })

Step 3 — Surface results honestly

For whichever tool you called:

  • Lead with the headline — the already-won verdict (is_over_funded) + surplus / cushion_years / current_safe_spend; the savings_percentile_band + cohort_framing; the newly_reached[] milestones; or the ranked, easiest-first ranked_levers solve_goal returns to hit the target age (plus feasible / already_achieved — whether the target is reachable at all).
  • Read back assumed_defaults[] — every one of these tools returns a structured assumed_defaults[] array of { field, assumed_value, note } listing each input you omitted and the value the engine assumed (e.g. safe_withdrawal_rate 0.04, real_growth_rate/real_return 0.05, annual_contributions 0). Surface each so the user can correct any silent default. disclosures.key_assumptions is SEPARATE static prose (a short list of method notes), and disclosures.not_advice is a BOOLEAN, not a message — honor it by presenting results as planning estimates, not financial advice.
  • Follow next_actions[] — each is { tool, why, prefilled_args } (carrying { plan_id } when available). Only some tools emit edges: solve_goal → generate_action_plan; analyze_fire_variants → solve_goal / analyze_already_won; generate_financial_plan → generate_financial_insights, check_model_completeness, and commentary tools. analyze_already_won, analyze_milestones, and analyze_fire_benchmark currently return no next_actions edges, so chain by intent yourself there.
  • For a share link: solve_goal always returns a share_url; analyze_already_won returns one when given a resolving plan_id; analyze_fire_variants returns one when given a resolving plan_id; generate_financial_plan always returns one. analyze_milestones and analyze_fire_benchmark do not — run generate_financial_plan (Step 1) for a sharable plan.

Recommended call sequence (typical session)

  1. (preferred) generate_financial_plan → capture plan_id (+ share_url) — note analyze_fire_benchmark won't use the plan_id.
  2. Route by intent → one of the five tools (with { plan_id } where accepted, plus the REQUIRED raw fields).
  3. Read back the headline + the tool's assumed_defaults[].
  4. Follow any next_actions[] the tool returns (solve_goal suggests generate_action_plan); for tools that emit none, chain by intent yourself, or run generate_financial_plan for a share link.

Fictional examples

1. "I'm 45 with $1.6M invested and spend $60k a year — am I already financially independent?" → analyze_already_won({ liquid_net_worth: 1600000, annual_spend: 60000 }). Lead with the verdict (won / not yet via is_over_funded), the surplus, cushion_years, and current_safe_spend; if not yet there, chain solve_goal to show the smallest lever to close the gap. Read back assumed_defaults[] (the safe_withdrawal_rate / real_growth_rate assumptions that drive the verdict).

2. "Can I retire by 50 if I'm 38 with $400k invested and saving $3k/mo?" → build a quick plan with generate_financial_plan (capturing plan_id + share_url), then solve_goal({ target_fire_age: 50, plan_id }). Lead with whether age 50 is reachable (feasible) and the easiest-first ranked_levers (e.g. bump savings rate, trim spend, push retire age) it returns; surface the share_url solve_goal itself returns. Read back assumed_defaults[].

3. "I'm 40 with $600k invested, saving $30k/yr, spending $60k — what's my Lean vs Fat FIRE number, and could I Barista-FIRE on a $25k/yr part-time job until 55?" → analyze_fire_variants({ current_age: 40, liquid_net_worth: 600000, annual_savings: 30000, base_annual_spend: 60000, barista_part_time_income: 25000, barista_end_age: 55 }). Lead with the three tiers (Lean / Standard / Fat target_net_worth + fire_pct + years_to_target) and the Barista bridge — barista_fire_number (smaller than full_fire_number because part-time NET income covers barista_spending_gap), barista_reduction_vs_full, and barista_fire_pct. If the Barista number is already covered, chain analyze_already_won; if a tier is short, chain solve_goal for the easiest levers. Read back assumed_defaults[] (Lean 70% / Fat 160% of base, SWR, real return).

(All examples use fictional figures — never reuse a real user's numbers in documentation.)

Notes

  • All rates/decimals are fractions; all dollars are today's (real) dollars; any thresholds are ~2026.
  • REQUIRED raw inputs that can't be inferred: analyze_already_won needs liquid_net_worth + annual_spend; analyze_fire_benchmark needs annual_income + annual_savings + liquid_net_worth; analyze_fire_variants needs current_age + liquid_net_worth + annual_savings + base_annual_spend; analyze_milestones needs net_worth; solve_goal needs target_fire_age (20–100) plus a plan (inline or plan_id). Ask for them before calling.
  • Pass { plan_id } to reuse a saved household model on analyze_already_won, analyze_milestones, analyze_fire_variants, and solve_goal; pass an overrides object for inline changes on top of the resolved plan. analyze_fire_benchmark does NOT accept plan_id — pass its figures raw.
  • All five tools return a structured assumed_defaults[] ({ field, assumed_value, note }) — read it back to the user. disclosures.key_assumptions is separate static method prose; disclosures.not_advice is a boolean. solve_goal always returns a share_url, analyze_already_won returns one when given a resolving plan_id; for the other two, chain generate_financial_plan for a sharable link.
  • Not financial advice. Planning estimates only.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.