Product engineering · 2026 · shipped
Mainspring
A local-first financial-independence planner with a deterministic Rust engine.

You wind it up — and it drives everything. A mainspring is wound once and releases that energy steadily to turn every hand on the face. This is a financial-independence planner built the same way — one deterministic engine, running on your machine, driving every number in the plan off a single tick. Accounts, balances, and assumptions stay on-device, with no account to create and nothing leaving by default. Built for planning that still has to be right years from now, not just today.
The instrument

A projection you can trust
Deterministic net-worth projections and a Monte Carlo success rate, computed on your machine in milliseconds — coast number, FI date, and what today's spending costs the plan.

Tune the instrument
Set return and volatility assumptions directly, or start from a preset — three-fund, all-weather, a glidepath that de-risks near the date. Every number recalculates as you change one.

Rebalance without selling
See how far each holding has drifted from target, and how long steering new contributions there takes to close the gap — no selling, no capital-gains tax. Modeled from your own lots and cached prices.

Every dollar, accounted for
Log spending against bills and goals and see whether you're in the black — how much of your take-home is working, and how much is spare.
Further views


The movement
The engineering underneath
A planner is only as good as its arithmetic. Most of the work lives below the dial — in spending precision where it matters, keeping the simulation honest, and leaving the whole of it yours.
Exact decimal where it counts, floats where they don't
Every balance, contribution, and rate is a Money value object over arbitrary-precision decimals — HALF_UP, forty digits, persisted as NUMERIC(18,4) so a figure round-trips through storage without ever touching a JS float. Its one constructor refuses floats outright; a lint rule enforces it across the codebase. The split is deliberate: exact decimal governs the ledger, where a drifted cent is a bug; the Monte Carlo kernel runs in f64, where you're sampling a distribution and decimal "exactness" would be a fiction.
export class Money {
private readonly d: Decimal;
private constructor(d: Decimal) { this.d = d; }
static of(value: string): Money {
if (typeof (value as unknown) !== "string") {
throw new TypeError("Money.of expects a decimal string, never a float.");
}
const d = new MoneyDecimal(value);
if (!d.isFinite()) {
throw new RangeError(`Money.of received a non-finite value: ${value}`);
}
return new Money(d);
}
add(other: Money): Money {
return new Money(this.d.plus(other.d));
}
toString(): string {
return this.d.toFixed(MONEY_SCALE, MoneyDecimal.ROUND_HALF_UP);
}
}A deterministic core, sealed off from the shell
The projection engine is one dependency-light Rust crate — serde and nothing else — that knows nothing about Svelte or Tauri: assumptions in, forecast out, no clock, no I/O, no global state. A seeded RNG makes every run reproducible, so the same inputs give the same numbers every time and the math can be unit-tested on its own — including a zero-volatility path checked against the closed-form compounding formula. One source, two targets: native today, WASM next.
The Monte Carlo models the risk averages hide
Thousands of paths run year by year, straight through the withdrawal phase, drawn from geometric Brownian motion — or bootstrapped from historical returns — rather than compounded from a single average. The ordering matters: a plan that clears on mean returns can still fail on a bad run of early years — sequence-of-returns risk — and only path-wise simulation surfaces it.
Local-first is the architecture, not a tagline
Your data lives on your machine — Postgres compiled into the webview (PGlite) over IndexedDB — so by default there is no server to be the source of truth; the client is the system of record. That removes a whole class of machinery: no accounts, no sync-conflict resolution, no network on the hot path. Market quotes and an optional AI copilot are the only things that reach out, both opt-in, with any API key kept in the OS keychain rather than the database.
- Core
- Deterministic Rust kernel — pure, serde-only
- Money
- Exact-decimal ledger (decimal.js) — never floats
- Simulation
- Monte Carlo — GBM or bootstrapped returns
- Storage
- Local Postgres (PGlite) over IndexedDB
- Privacy
- Nothing leaves the device by default
- Shell
- Tauri + Svelte over the kernel
- Verification
- Seeded RNG — zero-volatility path checked against the closed-form compounding formula