agentic-financial-planner-lab
An experimental framework for building auditable personal-finance planning agents: a typed case file, deterministic calculators, a Monte Carlo simulation adapter, cited research through the Model Context Protocol, and a critic gate that blocks any memo whose numbers cannot be traced to a recorded computation. No commercial product, account, or specific vendor is required anywhere; the LLM layer runs locally by default (Ollama) with Bedrock as the wired alternative.
The LLM never does the math. Every dollar figure in an output memo resolves to a recorded calculator run or a case-file field, and a critic rejects the memo otherwise. This is a research and education project: not a financial advisor, no trade execution, no stock picking, no required account anywhere. Examples use synthetic households only (see the disclaimer).
Keywords: financial planning, retirement readiness, Monte Carlo simulation, LLM agents, Model Context Protocol (MCP), funded ratio, safe withdrawal rate, personal finance, FIRE.
Architecture
The LLM appears at exactly two points (memo drafting and a tone review); everything else is deterministic, seeded, and testable.
flowchart TD
A[Case file: typed household facts] --> B[Assumptions gate:<br/>base / conservative / optimistic,<br/>confirmed by the user]
B --> C[Deterministic engines]
C --> C1[Calculators:<br/>funded ratio, FI timeline]
C --> C2[Monte Carlo simulation]
C --> C3[CEFR health metric]
C --> C4[Allocation diagnostics]
C1 --> D[(Computation ledger:<br/>every result gets a citable id)]
C2 --> D
C3 --> D
C4 --> D
E[MCP research source:<br/>search + fetch, recorded] --> D
D --> F[Memo writer LLM:<br/>drafts prose, cites only<br/>ids from the ledger menu]
F --> G{Critic gate:<br/>10 deterministic checks<br/>+ LLM tone review}
G -- approved --> H[Planning memo<br/>+ audit sidecar]
G -- rejected twice --> I[Hard failure:<br/>no memo emitted]
How it compares
| Spreadsheet / DIY | Web retirement simulators | Generic LLM chat | This project | |
|---|---|---|---|---|
| Deterministic, seeded math | yes | yes | no | yes |
| Explains trade-offs in prose | no | limited | yes | yes |
| Every number traceable to a computation | manual | no | no | enforced by a critic |
| Cited methodology sources | manual | some | fabrication risk | fetched and verified |
| Runs fully local | yes | no | rarely | yes (Ollama) |
| Refuses unverifiable output | n/a | n/a | no | yes |
Install
Requires Python 3.11+.
pip install "planner-lab[agent]" # from PyPI
Or work from a clone:
uv sync --extra agent --extra dev
Extras are optional by design. The core installs without any agent framework; agent adds the Strands SDK (with Ollama and OpenTelemetry support), mcp adds Model Context Protocol clients for research sources.
Try it
The core works offline with no LLM:
uv run planner-lab validate examples/cases/sample_household.yaml
uv run planner-lab calc funded-ratio --portfolio 900000 --spending 50000
uv run planner-lab calc fi-timeline --portfolio 250000 --savings 50000 --spending 60000
With a local Ollama server running and a tool-calling-capable model pulled (default qwen3; override with OLLAMA_MODEL):
# Full pipeline: assumptions -> calculators -> memo draft -> critic gate -> memo
uv run planner-lab memo examples/cases/sample_household.yaml -o memo.md --yes
# Add Monte Carlo simulation, the fundedness metric, and allocation diagnostics
uv sync --all-extras
uv run planner-lab analyze examples/cases/sample_household.yaml --simulate --health --allocation --yes
# Ground the memo's methodology in cited guides from an MCP research server
PLANNER_LAB_RESEARCH_MCP_URL=https://example.com/mcp \
uv run planner-lab memo examples/cases/sample_household.yaml -o memo.md --yes --research
# Derive annual cash flow from a budgeting-app CSV export (no LLM involved)
uv run planner-lab import-cashflow examples/data/sample_transactions_monarch.csv \
--format monarch --case my_case.yaml --write
# Interactive intake chat that builds a case file
uv run planner-lab intake -o my_case.yaml
# Minimal agent-plus-tool example
uv run python examples/hello_agent.py
The memo command writes the markdown memo plus a .audit.json sidecar holding the full computation ledger and critic report, so every number can be checked by hand. If the critic rejects the draft twice, no memo is written and the failing checks are printed.
Case studies
Full walkthroughs with real generated memos, checked in verbatim:
- An on-track couple, full analysis: simulation percentiles, the CEFR health metric, allocation diagnostics, and cited research in one run.
- Data gaps and CSV import: missing data is disclosed, then partially filled from a transactions export with no LLM involved.
- A rejected memo: what the critic gate catches, and why the worst case is no memo rather than a wrong one.
How a run works
- The case file is loaded and validated; material gaps are recorded.
- Base, conservative, and optimistic assumption sets are shown for confirmation (
--yesaccepts them non-interactively). Rates are real, after inflation. - Deterministic calculators run per assumption set: funded ratio (gross, and net of Social Security or pension income when the case has income streams), years to financial independence, sustainable spending. Each result lands in the computation ledger with an id.
- Optionally, a Monte Carlo engine simulates each set behind a generic
ScenarioSimulatorinterface: correlated stock/bond/cash assets at the case's portfolio weights, guaranteed-income streams, education and purchase goals as outflow events, crash and sequence-risk stress runs, a choice of spending policy (--spending-policyconstant-real, Guyton-Klinger-style guardrails, VPW, floor-ceiling, percent-of-portfolio), a five-policy comparison (--compare-spending-policies), parameter sensitivity (--sensitivity), and a Social Security claiming-age comparison at 62/67/70 (--ss-comparison). - The LLM drafts the memo, citing numbers only from the ledger menu it is given.
- The critic runs ten deterministic checks (structured-number traceability, prose dollar/percent traceability, no securities advice, disclaimer, assumption disclosure, missing-data disclosure, citation consistency, real/nominal labeling, certainty language, diagnostic framing) plus an LLM tone review. One revision is attempted; then the run fails.
Evals
evals/golden/ holds ten synthetic household cases with expected ledger values. uv run python evals/run_evals.py runs each through the full pipeline against a real local model and writes a report (latest) recording the approval rate: how often the model produced a memo that survived every check. Deterministic ledger mismatches always fail the run; critic rejections are the system working as designed and are scored, not hidden. A nightly GitHub Actions job runs the suite against a small cached Ollama model.
Configuration
Runtime configuration is environment-based: model provider, research server, and tracing are selected with environment variables. Modeling defaults (assumption sets, simulation seeds, stress durations) are code with documented rationale; override assumptions per case in the case file.
| Variable | Purpose | Default |
|---|---|---|
PLANNER_LAB_MODEL_PROVIDER |
ollama or bedrock |
ollama |
OLLAMA_HOST / OLLAMA_MODEL |
Local model server and model id | http://localhost:11434 / qwen3 |
PLANNER_LAB_BEDROCK_MODEL |
Bedrock model id (provider bedrock) |
provider default |
PLANNER_LAB_RESEARCH_MCP_URL |
Streamable-HTTP MCP server exposing search and fetch tools; enables --research |
unset |
OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_HEADERS |
OTLP tracing target for setup_telemetry("otlp"); --trace prints spans to stdout |
unset |
Small local models occasionally mis-copy a number or skip a citation; the critic then rejects the memo after one revision attempt rather than emitting it. A larger model (for example OLLAMA_MODEL=gpt-oss:20b) makes full runs with simulation, diagnostics, and research more reliable.
Optional extras: agent (LLM pipeline, Strands SDK), planning (Monte Carlo simulation, fundedness metric), portfolio (lifecycle allocation diagnostics), mcp (research sources), dev (tests, lint, types). The core installs with none of them.
Status
Working retirement-readiness pipeline: case-file schemas, deterministic calculators, critic gate, memo renderer, interactive intake, Monte Carlo simulation, certainty-equivalent funded ratio (CEFR) metric, lifecycle allocation diagnostics, MCP research citations, and CSV cash-flow import. See CLAUDE.md for architecture rules.
Citation
@software{hodge_agentic_financial_planner_lab,
author = {Hodge, John},
title = {agentic-financial-planner-lab: an auditable financial planning agent framework},
year = {2026},
url = {https://github.com/jman4162/agentic-financial-planner-lab},
doi = {10.5281/zenodo.21301713},
version = {0.2.0},
license = {MIT}
}
License
MIT. Educational use; nothing here is financial advice.
Metadata
Release files for planner-lab 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| planner_lab-0.2.0.tar.gz | 611.4 kB | With provenance | Details for planner_lab-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| planner_lab-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for planner_lab-0.2.0-py3-none-any.whl |
Total release size: 676.1 kB
Release files / planner_lab-0.2.0.tar.gz
| Download URL | planner_lab-0.2.0.tar.gz |
|---|---|
| Size | 611.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e334ac17ec57eb7cf17c19001402dcfd2567f324ed176af48c7a92a33854e421
|
|
BLAKE2b-256 checksum How to use checksums |
c8c0005841b28bdb93487c6ad8bd801c87384835ff59e896df2d49bc6676fd3b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency logRelease files / planner_lab-0.2.0-py3-none-any.whl
| Download URL | planner_lab-0.2.0-py3-none-any.whl |
|---|---|
| Size | 64.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7f75f3c34ea0acebec10d6558f429aad65609801c36775d268fa08b377e6e359
|
|
BLAKE2b-256 checksum How to use checksums |
bc4746344ef6311f814e7654dc70b4642e0359e355a9fdd5203b594dc3bd4061
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency logSecurity for planner-lab 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for planner_lab-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.