Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ jobs:
- name: Type check
run: uv run mypy src/

- name: Vendor backlinks in docs
run: uv run python scripts/backlinks.py --check

- name: Tests with coverage
run: |
uv run pytest \
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ scripts/google-sheets/portfolio-optimizer/
scripts/*
!scripts/onboarding/
!scripts/qa/
!scripts/backlinks.py
# Private PII data files (real values for git-filter-repo — tracked templates available instead)
scripts/qa/pii-replacements.txt
scripts/qa/author-mailmap.txt
Expand Down
16 changes: 8 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Finance Guru

Finance Guru is a self-hosted family office engine: typed Python calculators, a private SQLite ledger, and specialist agents that run inside Claude Code or Codex. It is the open-core engine behind Keepfolio. The README describes the product for people. This file is the canonical instruction set for any agent working in the repository or in an instance built from it. `CLAUDE.md` imports it and adds only what is specific to Claude Code.
Finance Guru is a self-hosted family office engine: typed Python calculators, a private [SQLite](https://www.sqlite.org/) ledger, and specialist agents that run inside [Claude Code](https://code.claude.com/) or [Codex](https://github.com/openai/codex). It is the open-core engine behind [Keepfolio](https://keepfolio.app/). The README describes the product for people. This file is the canonical instruction set for any agent working in the repository or in an instance built from it. `CLAUDE.md` imports it and adds only what is specific to Claude Code.

## The split

Expand All @@ -19,7 +19,7 @@ Agents propose. Typed code computes. Every number an agent quotes comes from a c
Private data lives in an instance directory outside the repository, resolved from `FIN_GURU_DATA_ROOT` or the current working directory. The instance holds `.env`, `user-profile.yaml`, `config.yaml`, `family_office.db`, broker CSV exports under `imports/`, and every artifact the engine writes. Tracked files in this repository never carry personal values. `uv run python -m src.cli.instance_init <root> --repo .` scaffolds an instance.

- Run engine commands from the instance as `uv run python -m src.<tool>` so private paths resolve from the current directory.
- `family_office.db` is the single source of truth for positions, balances, transactions, and bank transactions. `src.integrations.refresh_all` fills it from SnapTrade (brokerage) and SimpleFIN (bank and card) and raises on a partial provider response. CSV exports in `imports/` are an ingestion path into the database, not a second ledger.
- `family_office.db` is the single source of truth for positions, balances, transactions, and bank transactions. `src.integrations.refresh_all` fills it from [SnapTrade](https://snaptrade.com/) (brokerage) and [SimpleFIN](https://www.simplefin.org/) (bank and card) and raises on a partial provider response. CSV exports in `imports/` are an ingestion path into the database, not a second ledger.
- The Google Sheets DataHub is retired. Do not write to Sheets, reference a spreadsheet ID, or reintroduce a gdrive MCP dependency.
- Write analysis to `analysis/` as `{topic}-{YYYY-MM-DD}.md` and buy tickets to `tickets/` as `buy-ticket-{YYYY-MM-DD}-{descriptor}.md`. Markdown with YAML frontmatter, date stamp, disclaimer, and citations.
- The pre-push compliance scan blocks a push that carries secrets or PII. A fresh checkout installs it with `.claude/skills/compliance-scan/scripts/install-pre-push.sh`.
Expand All @@ -34,11 +34,11 @@ A scaffolded checkout-mode instance holds `.agents` and `.claude` symlinks to th

## Code

- Every calculator is three layers: a Pydantic input model in `src/models/`, a calculator class, and a `*_cli.py` wrapper in the same directory. A new tool ships all three plus a test under `tests/python/` that runs without a network. Conventions and gotchas for the Python code are in `src/CLAUDE.md`.
- Every calculator is three layers: a [Pydantic](https://docs.pydantic.dev/) input model in `src/models/`, a calculator class, and a `*_cli.py` wrapper in the same directory. A new tool ships all three plus a test under `tests/python/` that runs without a network. Conventions and gotchas for the Python code are in `src/CLAUDE.md`.
- The CLI reference is `docs/reference/api.md`. Every CLI answers `--help`.
- `apps/simplefin-sync/` is a Bun workspace. Use `bun`, never npm.
- `apps/simplefin-sync/` is a [Bun](https://bun.sh/) workspace. Use `bun`, never npm.
- Research skills may call the MCP servers named in their persona files. None are required to run the calculators or the sync.
- Markdown emphasis uses underscores, `_like this_`. markdownlint rule MD049 enforces it.
- Markdown emphasis uses underscores, `_like this_`. [markdownlint](https://github.com/DavidAnson/markdownlint) rule MD049 enforces it.

## Toolchain and gates

Expand All @@ -52,17 +52,17 @@ uv run mypy src/
uv run pytest -m "not integration"
```

- The pre-commit hook runs the full pytest suite with the 80% coverage gate on every commit, so a commit takes about ten seconds. Tests marked `integration` need real API keys.
- The pre-commit hook runs the full [pytest](https://docs.pytest.org/) suite with the 80% coverage gate on every commit, so a commit takes about ten seconds. Tests marked `integration` need real API keys.
- Tests assume no `.env` in the repository root. A scaffolded `.env` holds placeholder strings such as `your_monthly_dividend_income_here`, and `python-dotenv` loads them, which fails the margin-metrics tests with `could not convert string to float`. Delete the file or fill in real numbers.
- Pull requests get CodeRabbit and Claude reviews. Verify each finding against the source before acting on it and dismiss a false positive with a written reason.
- Pull requests get [CodeRabbit](https://www.coderabbit.ai/) and Claude reviews. Verify each finding against the source before acting on it and dismiss a false positive with a written reason.

## Session end

Work is not complete until `git push` succeeds. Before ending a session: file issues for follow-up work, run the gates if code changed, commit, `git pull --rebase`, push, and confirm `git status` reports the branch is up to date with origin. If the push fails, resolve the cause and push again.

## Cursor Cloud

The startup script already runs `uv sync --dev` and `bun install`. `uv` lives at `~/.local/bin/uv` and `bun` at `~/.bun/bin/bun`. Both are on `PATH` for interactive shells only, so a fresh non-interactive shell needs `export PATH="$HOME/.local/bin:$HOME/.bun/bin:$PATH"` first. There is no long-running server. Run an analysis with `uv run python -m src.analysis.risk_metrics_cli AAPL --days 252 --benchmark SPY`, which fetches live data through yfinance with no API key, or launch the dashboard with `uv run python -m src.cli.fin_guru` and quit with `q`.
The startup script already runs `uv sync --dev` and `bun install`. `uv` lives at `~/.local/bin/uv` and `bun` at `~/.bun/bin/bun`. Both are on `PATH` for interactive shells only, so a fresh non-interactive shell needs `export PATH="$HOME/.local/bin:$HOME/.bun/bin:$PATH"` first. There is no long-running server. Run an analysis with `uv run python -m src.analysis.risk_metrics_cli AAPL --days 252 --benchmark SPY`, which fetches live data through [yfinance](https://github.com/ranaroussi/yfinance) with no API key, or launch the dashboard with `uv run python -m src.cli.fin_guru` and quit with `q`.

## Documentation

Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Short version — before you open a pull request:
2. Fork, clone, run `./setup.sh`
3. Create a feature branch off `main`
4. Run `uv run ruff format .`, `uv run ruff check .`, `uv run mypy src/`, `uv run pytest`
5. Open a PR — CodeRabbit and the Claude review bot will comment automatically
5. Open a PR — [CodeRabbit](https://www.coderabbit.ai/) and the Claude review bot will comment automatically

## Filing issues

Expand All @@ -18,8 +18,8 @@ Short version — before you open a pull request:

## Style

- Python — ruff (format + lint) + mypy strict
- Python — [ruff](https://docs.astral.sh/ruff/) (format + lint) + [mypy](https://mypy-lang.org/) strict
- Markdown — MD049 enforced; use underscores `_text_` not asterisks for emphasis
- Commits — conventional commits (`feat:`, `fix:`, `docs:`, `chore:`, `security:`) so release-please can cut versions
- Commits — [conventional commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, `chore:`, `security:`) so [release-please](https://github.com/googleapis/release-please) can cut versions

See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for everything else.
6 changes: 3 additions & 3 deletions PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Finance Guru is a **private, single-user family-office system**. This document d
- All financial data stays on the owner's machine
- No telemetry, no remote analytics, no third-party data sharing
- Nothing personally identifying is committed to the public engine repository; the separate instance repository is local-only and has no remote
- When data _does_ leave the laptop (SnapTrade, SimpleFIN, Fidelity APIs, ITC Risk Models), it goes directly to the owner's own accounts — no intermediary
- When data _does_ leave the laptop ([SnapTrade](https://snaptrade.com/), [SimpleFIN](https://www.simplefin.org/), [Fidelity](https://www.fidelity.com/) APIs, ITC Risk Models), it goes directly to the owner's own accounts — no intermediary
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

## What data Finance Guru handles

Expand All @@ -21,13 +21,13 @@ Finance Guru is a **private, single-user family-office system**. This document d
| Bank / card spending | SimpleFIN | `family_office.db` (committed to local-only instance repository) | Local only; no remote |
| Dividend events | SnapTrade activities | `family_office.db` (committed to local-only instance repository) | Local only; no remote |
| User profile (risk tolerance, goals) | Interactive onboarding | `user-profile.yaml` under the instance root (committed to local-only instance repository) | Local only; no remote |
| Market data | yfinance / Finnhub / ITC | In-memory during analysis | Per-provider terms |
| Market data | [yfinance](https://github.com/ranaroussi/yfinance) / [Finnhub](https://finnhub.io/) / ITC | In-memory during analysis | Per-provider terms |

## What leaves your machine

1. _Broker and bank reads_ — SnapTrade and SimpleFIN are queried outbound to pull your own accounts. Both are read-only; nothing is written back to a broker.
2. _Market-data queries_ — yfinance, Finnhub, and ITC Risk Models APIs see which tickers you query, but not your position sizes.
3. _Claude Code session_ — the LLM provider (Anthropic) sees conversation content including any data you paste into the session. Treat Claude Code like a privileged assistant — don't paste data you wouldn't email your accountant.
3. _Claude Code session_ — the LLM provider ([Anthropic](https://www.anthropic.com/)) sees conversation content including any data you paste into the session. Treat [Claude Code](https://code.claude.com/) like a privileged assistant — don't paste data you wouldn't email your accountant.

> The Google Sheets DataHub was retired 2026-07-31. Portfolio data no longer leaves the machine for Google Drive, and no `gdrive` MCP server is configured.

Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ You paste a screenshot into a chat model and ask whether a position is too big.

</div>

Every number an agent quotes comes from a Pydantic-validated calculator with a CLI you can run yourself. Every irreversible action passes through a guardrail that blocks when its inputs are missing rather than guessing. The AI gets judgment. The math gets a test suite.
Every number an agent quotes comes from a [Pydantic](https://docs.pydantic.dev/)-validated calculator with a CLI you can run yourself. Every irreversible action passes through a guardrail that blocks when its inputs are missing rather than guessing. The AI gets judgment. The math gets a test suite.

<div align="center">

Expand All @@ -49,7 +49,7 @@ Every number an agent quotes comes from a Pydantic-validated calculator with a C

### Prerequisites

Python 3.12 or later, [uv](https://docs.astral.sh/uv/), and Git. Bun only if you work on the SimpleFIN sync app.
[Python](https://www.python.org/) 3.12 or later, [uv](https://docs.astral.sh/uv/), and [Git](https://git-scm.com/). [Bun](https://bun.sh/) only if you work on the [SimpleFIN](https://www.simplefin.org/) sync app.

### Install

Expand Down Expand Up @@ -82,13 +82,13 @@ Then run the `instance-onboarding` skill. It scaffolds the instance with `--plug

## What is in the box

Finance Guru is the open-core engine behind Keepfolio, a "claude-code for personal finance." This repo is the free, self-hosted, CLI-native experience: the whole engine, every skill, every agent, no withheld tier.
Finance Guru is the open-core engine behind [Keepfolio](https://keepfolio.app/), a "claude-code for personal finance." This repo is the free, self-hosted, CLI-native experience: the whole engine, every skill, every agent, no withheld tier.

| Component | What it does | Why it matters |
| :--- | :--- | :--- |
| **Typed calculators** (`src/`) | 20 CLIs for risk, momentum, volatility, correlation, optimization, backtesting, options, factors, hedging, total return, and margin metrics. Every one is Pydantic input, calculator class, CLI wrapper. | Calculations are testable outside any AI session. The suite is 1,100+ tests behind an 80% coverage gate. |
| **Private instance** | A directory outside the repo holding `family_office.db`, your `.env`, broker CSVs, and every artifact the engine writes. | No spreadsheet, no cloud sync, no vendor dashboard between you and your ledger. Tracked files never carry personal values. |
| **Sync layer** (`src/integrations/`) | `refresh_all` pulls SnapTrade (brokerage) and SimpleFIN (bank and card) into SQLite with your own read-only credentials. | Partial provider responses raise before any write. You get an error instead of a coverage ratio computed on half your accounts. |
| **Sync layer** (`src/integrations/`) | `refresh_all` pulls [SnapTrade](https://snaptrade.com/) (brokerage) and SimpleFIN (bank and card) into [SQLite](https://www.sqlite.org/) with your own read-only credentials. | Partial provider responses raise before any write. You get an error instead of a coverage ratio computed on half your accounts. |
| **Fail-closed guardrails** | Concentration cap, margin coverage, and ITC risk run against trusted inputs before a buy ticket persists. | A block on missing NAV, missing rate, or an unrun Layer 3 score. A bad ticket needs a number to pass, not a prompt to agree. |
| **Skills and specialists** (`.claude/`) | Skills and 11 specialist agents coordinated by a finance orchestrator. They read the DB, run the CLIs, and write Markdown into your instance. | Every output carries its data source, date stamp, and the educational-only disclaimer. You can trace any claim back to a CLI run. |
| **Compliance scan on push** | A pre-push hook scans history and the diff for secrets and PII. | The repo is public. Your data is not. The hook is what keeps that true. |
Expand Down Expand Up @@ -137,7 +137,7 @@ Local-first does not mean network-free. Market data, brokerage, and LLM integrat

You are the intended operator of this engine, not an afterthought. A few things that make you effective here:

- **Read `CLAUDE.md` first.** It is the single source of truth for the skills index, the agent roster, the path variables, and the output rules. `AGENTS.md` points Codex at the same tree through the instance's `.agents` symlink.
- **Read `CLAUDE.md` first.** It is the single source of truth for the skills index, the agent roster, the path variables, and the output rules. `AGENTS.md` points [Codex](https://github.com/openai/codex) at the same tree through the instance's `.agents` symlink.
- **Run `date` before any market work.** Every specialist here is expected to know the current date before it searches or analyzes.
- **Never do the arithmetic yourself.** Call the CLI with `--output json` and quote what it returned. That is the whole reason the calculators exist.
- **Private data lives in the instance, not the repo.** Resolve `FIN_GURU_DATA_ROOT` or the working directory, read from `family_office.db`, and write artifacts into `analysis/` or `tickets/`. Tracked files never carry personal values, and the pre-push scan will stop you if you try.
Expand Down Expand Up @@ -173,10 +173,10 @@ The repo is public because the pattern is more useful than the portfolio. The co
- [x] Three-layer calculators for risk, momentum, volatility, correlation, optimization, backtesting, options, factors, hedging, and margin
- [x] Local SQLite system of record fed by SnapTrade and SimpleFIN
- [x] Fail-closed buy-ticket guardrails with Layer 3 ITC authority
- [x] Diátaxis documentation site on GitHub Pages
- [ ] Claude Code plugin as the primary install path ([#131](https://github.com/AojdevStudio/Finance-Guru/issues/131))
- [x] [Diátaxis](https://diataxis.fr/) documentation site on [GitHub Pages](https://pages.github.com/)
- [ ] [Claude Code](https://code.claude.com/) plugin as the primary install path ([#131](https://github.com/AojdevStudio/Finance-Guru/issues/131))
- [ ] Retirement-account sync migration gate ([#74](https://github.com/AojdevStudio/Finance-Guru/issues/74))
- [ ] Automated releases through release-please ([#112](https://github.com/AojdevStudio/Finance-Guru/issues/112))
- [ ] Automated releases through [release-please](https://github.com/googleapis/release-please) ([#112](https://github.com/AojdevStudio/Finance-Guru/issues/112))

Open items carry the `roadmap` label. Defects carry `bug`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ The engine checkout is public code. Private data lives in a separate instance di

## The three layers

Every analysis tool follows one 3-layer pattern. Pydantic models validate inputs and outputs. Calculator classes hold the business logic. Thin CLI entry points handle input and output only. The pattern keeps calculations testable and keeps command surfaces consistent, so every tool takes a ticker, a window, and flags in the same shape.
Every analysis tool follows one 3-layer pattern. [Pydantic](https://docs.pydantic.dev/) models validate inputs and outputs. Calculator classes hold the business logic. Thin CLI entry points handle input and output only. The pattern keeps calculations testable and keeps command surfaces consistent, so every tool takes a ticker, a window, and flags in the same shape.

## Where data comes from

Two read-only integrations feed the local database. The SnapTrade modules sync brokerage positions, balances, and activities. The SimpleFIN workspace syncs bank and card transactions. Broker CSV exports remain a first-class source, dropped into the instance import directory, so the system works without any live credentials. The coordinating entry point is `src.integrations.refresh_all`, which runs every configured source and exits non-zero on a partial refresh.
Two read-only integrations feed the local database. The [SnapTrade](https://snaptrade.com/) modules sync brokerage positions, balances, and activities. The [SimpleFIN](https://www.simplefin.org/) workspace syncs bank and card transactions. Broker CSV exports remain a first-class source, dropped into the instance import directory, so the system works without any live credentials. The coordinating entry point is `src.integrations.refresh_all`, which runs every configured source and exits non-zero on a partial refresh.

## Verified implementation seams

- `src/integrations/refresh_all.py` coordinates the configured refreshes.
- `src/integrations/snaptrade/` contains account, position, balance, and activity synchronization surfaces.
- `src/integrations/simplefin/sync_expenses_db.py` imports configured bank and card transaction data into local SQLite.
- `src/integrations/simplefin/sync_expenses_db.py` imports configured bank and card transaction data into local [SQLite](https://www.sqlite.org/).
- `src/models/`, `src/analysis/`, and the CLI entry points form the checked-in validation, business-logic, and command layers.

## What sits outside the stable core
Expand Down
Loading