{
  "markdown": "<p align=\"center\">\n  <img src=\"public/assets/icon-512.png\" width=\"96\" alt=\"nestegg.money logo\">\n</p>\n\n<h1 align=\"center\">nestegg.money</h1>\n\n<p align=\"center\">\n  A private, zero-knowledge net worth &amp; salary tracker.<br>\n  Encrypted in your browser. No email, no password, just an account number.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://nestegg.money\"><b>Live app</b></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/VladimirWrites/nestegg.money/actions/workflows/ci.yml\"><img src=\"https://github.com/VladimirWrites/nestegg.money/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/License-Apache_2.0-blue.svg\" alt=\"License: Apache 2.0\"></a>\n</p>\n\n## Screenshots\n\n<p align=\"center\">\n  <img src=\"public/assets/screenshots/dashboard.png\" width=\"820\" alt=\"nestegg.money dashboard: net worth over time, allocation donut, and per-year breakdown\">\n</p>\n\n## Overview\n\nA deliberately simple, zero-knowledge personal ledger. Single Cloudflare Worker\nserving a static frontend (no framework, no bundler) plus three small API\nroutes, with D1 for storage. Login is a Mullvad-style account number; data is\nencrypted in your browser before it's sent, so the server only ever stores\nciphertext.\n\n## What it does\n\n- **Over time**: a stacked bar chart of net worth per year, one colour per\n  asset (or category), with a net-worth line when liabilities exist.\n- **Allocation**: a donut of your most recent year.\n- **Entry**: tap a year to open its editor; each row is one asset (name,\n  currency, value). Add/remove assets, copy the previous year, rename the year.\n- **Categories**: assets can be tagged into a category (e.g. several holdings\n  under \"Stocks\"). The editor shows each category as a section with a\n  subtotal; charts roll a category up into one segment.\n- **Long-term assets & loans**: a car or house can depreciate/appreciate\n  continuously and carry a loan with a real amortization schedule — extra\n  payments, rate-fixed periods, payment-or-term entry. Its net value is\n  injected into every year you own it.\n- **Multi-currency**: each row carries its own currency; everything is shown\n  in your chosen display currency at ECB rates (`/api/fx`). Past years use\n  that year's year-end rates.\n- **Ticker/crypto rows**: shares × live price via `/api/price` (Yahoo proxy).\n  Past years freeze to that year's closing price. Only the public symbol is\n  sent upstream — never an account or user identifier.\n- **Salary**: monthly pay per person (gross or net — your choice), with events (raises, job changes),\n  a dual-axis chart, and paste-from-spreadsheet import.\n- **Budget**: a rough monthly \"what's left\" — income from your latest salary\n  month, loan payments pulled from your assets, recurring expenses you enter,\n  grouped into categories with a breakdown donut.\n- **Forecast & retirement**: project net worth forward (contributions,\n  growth, scenario band, FIRE goal) and simulate drawdown with a state\n  pension (flat amount or German Rentenpunkte).\n- **Sync**: zero-knowledge. The account number derives an account hash (the\n  only thing the server sees) and an AES-GCM key (never leaves the browser).\n  Multi-device edits merge per record with tombstones, newest wins.\n  **No recovery** — keep the number safe; Export JSON is the real backup.\n- **Share links**: publish a frozen, read-only snapshot of chosen sections for\n  an advisor. Each share gets its own AES-GCM key, carried only in the URL\n  fragment; the server stores an unlinkable id + ciphertext. Expires in 30\n  days, revocable any time.\n- **Bilingual**: English and German throughout — the app (language picker in\n  the profile), the landing pages (`/` and `/de/`), and a public\n  [Brutto-Netto-Rechner](https://nestegg.money/brutto-netto-rechner)\n  ([English version](https://nestegg.money/en/german-net-salary-calculator))\n  that runs the exact salary engine entirely in the browser.\n\n## Layout\n\n```\nnestegg.money/\n├── src/                  # the Worker: /api/fx, /api/price, /api/vault, /api/share,\n│                         # /api/calc/*, /mcp, /.well-known/mcp.json + page routing\n├── public/\n│   ├── index.html        # marketing landing (generated; German at de/, see scripts/)\n│   ├── dashboard.html    # the app — loads one <script type=\"module\" src=\"js/main.js\">\n│   ├── brutto-netto-rechner.html  # public net-salary calculator (client-side, per-locale)\n│   ├── i18n/             # runtime dictionaries (en, de)\n│   ├── lib/              # finance-math: pure calculators incl. finance-math/de/\n│   │                     #   (generated BMF PAP Lohnsteuer engines + statutory tables)\n│   ├── css/              # base, landing, app styles\n│   └── js/               # native ES modules (no bundler); layers point ui → io → domain\n│       ├── domain/       #   pure logic, no DOM/network: money, dates, schema, ids,\n│       │                 #   loan, asset-value, model, forecast, retirement, merge, store\n│       ├── io/           #   effects: crypto (encrypt), storage (localStorage/sync/fetch)\n│       ├── ui/           #   DOM: dom, chart-kit, charts, networth, assets, salary, gate\n│       └── main.js       #   entry point: cross-cutting wiring + boot\n├── scripts/              # generators: per-locale pages, BMF PAP → JS, calculator docs\n├── tests/                # node --test: domain math, calculators, MCP, i18n page sync\n├── schema.sql            # D1: one row per account (hash → encrypted blob)\n└── wrangler.toml\n```\n\nThe Worker runs first (`run_worker_first`) so it can route the landing page vs\nthe app by hostname and handle `/api/*`; everything else falls through to the\nstatic assets binding. The frontend is a plain ES-module graph — the browser\nloads it directly, no build step.\n\n## Deploy\n\nRequires a Cloudflare account and `npm i -g wrangler` (then `wrangler login`).\n\n1. `wrangler d1 create networth-db` → copy the `database_id` into `wrangler.toml`.\n2. `wrangler d1 execute networth-db --remote --file=schema.sql`\n3. `wrangler deploy`\n4. Open the URL, create an account, save the number.\n\nLocal dev: `wrangler dev` (serves the app with live API + local D1).\n\nCut a release with `npm version patch|minor|major` — a `version` hook stamps the\nnew number into the service-worker cache name (`public/sw.js`) so clients pick up\nthe new build.\n\nTests (loan/asset/forecast/retirement math, `migrate`, multi-device merge, crypto):\n`npm test` (runs `node --test tests/*.mjs` — the pure domain modules import directly,\nno browser needed).\n\n## Calculators & MCP\n\nThe finance math is also exposed as **99 stateless calculators** any client — including AI\nagents — can call. They are pure functions of their inputs: no user data, no live prices, no\nFX lookups (you pass the rate in), no auth. This is a remote service, so your inputs are sent\nto the server — but it stores nothing and logs no request bodies: each call is computed in\nmemory and discarded.\n\nThe German set is the exception that carries data: `de-net-salary` computes exact Netto for\ntax years 2023–2026 via the official BMF Programmablaufplan (generated engines under\n`public/lib/finance-math/de/`, verified against all 1,008 published Prüftabellen values),\nwith `de-abgeltungsteuer`, `de-kindergeld`, `de-midijob`, and `de-rentenpunkte` sharing the\nsame verified statutory table. Everything else stays country-agnostic.\n\n- **JSON API:** `POST https://nestegg.money/api/calc/<name>` (JSON in, JSON out).\n  `GET /api/calc` lists them. See [`public/docs/calculators.md`](public/docs/calculators.md).\n- **MCP server (Streamable HTTP):** `https://nestegg.money/mcp` — the same calculators as MCP\n  tools, with typed `outputSchema`, read-only annotations, the docs as `resources/*`, and\n  canned workflows as `prompts/*` (`mortgage-plan`, `fire-check`, `brutto-netto`).\n\nInstall in an MCP client:\n\n```\nclaude mcp add --transport http nestegg https://nestegg.money/mcp\n```\n\nAlso published to the official MCP registry as `io.github.VladimirWrites/nestegg-calculators`\n(auto-republished when `server.json` changes on main), with the descriptor served at\n[`/.well-known/mcp.json`](https://nestegg.money/.well-known/mcp.json) and an\n[`llms.txt`](https://nestegg.money/llms.txt) for agent discovery.\n\nExample (an agent keeps responses small by default, then drills in):\n\n```\n> amortization { amount: 475000, rate: 3.75, mode: \"payment\", payment: 2869.8, startDate: \"2024-04-01\" }\n  → { monthlyPayment, payments, totalInterest, payoffDate, yearly: [ …per-year… ] }   // summary\n> amortization { …same…, detail: \"monthly\", offset: 0, limit: 12 }\n  → { schedule: [ …12 rows… ], scheduleTotal: 204, nextOffset: 12 }                    // paginated\n```\n\n## Notes\n\n- New accounts start empty with the current year. Tap the year to add asset\n  rows, use \"+ Year\" for more, or \"Reset\" to start over.\n- In a plain preview with no backend it runs local-only via localStorage with\n  fallback FX rates; sync, live FX and prices activate once deployed.\n- The server can't read your figures, but it can see the size of the\n  encrypted blob, sync times, and your IP — stated plainly in the app footer.\n\n## Contributing\n\nIssues and pull requests welcome. The domain logic (`public/js/domain/`) is pure\nand covered by tests — run `npm test` before sending a PR, and add tests for new\nbehaviour there. The `ui/` and `io/` layers are thin and browser-facing; keep DOM\nwork out of `domain/`. (`package.json` version and the service-worker cache name\nmust match — a test enforces it; run `npm run sync-version` if it complains.)\n\n## License\n\nLicensed under the [Apache License 2.0](LICENSE). © 2026 Vladimir Jovanovic.\n",
  "bytes": 9614,
  "sha": "486bdf47371dd81cd7de0e2e6c484700a6c8dcd9f62870c8214ded26354e036d",
  "repo_slug": "vladimirwrites/nestegg.money",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_vladimirwrites_nestegg_calcula_646b3f30/readme"
}