All work

myMeans

Double-entry accounting in Python, compatible with ledger-cli.

Source on GitLab Python · MPL-2.0 · v0.7.0
Bank data reaches the Ledger by two separate paths. A read-only Plaid sync enters a journal, becomes a plan, and only an explicit apply can replace the generated sidecar; apply refuses anything stale, unresolved, or ambiguous, so nothing writes back to the provider and no path moves money. A CSV import instead enters the manual Ledger workflow directly, skipping the plan and apply gate. Plaid journal plan apply CSV manual workflow refused Ledger

myMeans keeps my plain-text ledger-cli books in order. Bank data comes in through CSV imports or read-only Plaid sync, lands in a review queue, and only reaches the ledger after I've approved a plan.

The apply step is pure and offline: it refuses to write if anything is stale, ambiguous, or unresolved. There's also a planning command for cashflow and debt-payoff scenarios. It can read bank data but has no way to move money, by design.

A line chart of total_debt over twelve months from three real means-plan project runs on the README's published fictional-plan.yaml scenario: avalanche and snowball both reach zero debt, on 2027-04-20 and 2027-05-02, while minimum_only ends the year with 2,494.68 still owed. A table below gives each strategy's means-plan compare results: minimum_only keeps the highest final cash, 17,395.00, but pays the most interest, 574.68, and finishes with debt remaining; avalanche pays the least interest, 196.23, and is the rule-selected recommendation for lowest remaining debt, then lowest interest, then fewest shortfalls, not financial advice. 0 1,000 2,000 3,300 total debt ($) Aug 2026 Oct Dec Feb 2027 Apr Jun avalanche 0.00 snowball 0.00 minimum_only 2,494.68 means-plan compare strategy final cash remaining debt interest payoff / shortfalls minimum_only 17,395.00 2,494.68 574.68 — / 0 avalanche 15,278.77 0.00 196.23 2027-04-20 / 0 snowball 15,220.60 0.00 254.40 2027-05-02 / 0 recommended: avalanche — lowest remaining debt, then lowest interest, then fewest shortfalls, means-plan’s disclosed comparison rule — a rule-selected result, not financial advice
The eleven tables of the SQLite journal in means/bank_sync/store.py, each with its key columns in dark type and other columns in grey. The store declares no foreign keys, so dashed wires mark tables that share key columns. Cyan is the connection identity: connections, checkpoints and sync_status. Indigo is the account identity of provider, connection_id and account_id: accounts, balances, source_transactions, source_changes and bindings, which points at a Ledger account outside the database. Amber is the plan identity: plans and apply_runs. Violet is meta, which holds the revision counters that source_changes follow. A dashed frame groups the seven tables that one commit_revision call writes inside a single BEGIN IMMEDIATE transaction. commit_revision() one BEGIN IMMEDIATE Ledger outside the database checkpoints provider, connection_uid checkpoint revision sync_status provider, connection_uid fetched_at update_status connections uid provider provider_connection_id accounts provider, connection_id account_id last_revision balances provider, connection_id account_id last_revision source_transactions provider, connection_id account_id, transaction_id removed, last_revision source_changes revision, sequence provider, connection_id account_id, transaction_id meta source_revision transaction_revision decision_revision bindings provider, connection_id account_id ledger_account plans plan_id digest data_json apply_runs run_id plan_id phase