Johannes Kaindl50 downloadsView and triage hledger journals: filterable transaction table, balance and category dashboards, and categorizer-rule management synced with an external importer.
🇬🇧 English · 🇩🇪 Deutsch
An Obsidian plugin that renders hledger journals as filterable tables with balance and category dashboards, transaction triage and categorizer-rule management — fed by a companion Python importer.
Plugin ID:
finance-ledger(until 2026-06-10:finance).
As of 2026-08-17 — importer port, stages E0–E3: the built-in import now writes
journal.ledger, accounts.ledger, opening_balances.ledger and the account and
contract notes — without Python. It only touches what it produced itself: anfangssaldo_eur,
created, foreign frontmatter fields and everything below the AUTO-GENERATED marker
survive every run. Verified by npm run smoke:gui against a running Obsidian (21/21;
control run with the patch path removed: 15/20). Reports and dimension notes (E4–E7) still
come from the Python importer, run from a terminal.
As of 2026-10-03 — the subprocess is gone entirely: the import dialog, its
anti-duplicate preview and the re-import button no longer start the Python importer. The
plugin loads no Node module at all (tests/bundle.test.ts guards the built main.js), which
is what the Obsidian store review flags as Shell Execution and Direct Filesystem Access.
Before that, as of 2026-08-04 — stages E0+E1: CSV import runs inside the plugin
itself (TypeScript, no Python subprocess). Verified byte-for-byte against the Python
importer on real data: journal.ledger identical (1,576 transactions, 12 CSVs).
Reproducible with npm run parity.
As of 2026-06-10 (post phase 1 of the publication track): slices 1–10 plus the F15
design system merged. Mobile readiness (Platform.isMobile guards) and the design system
(KSP palette + finance tokens + light mode) integrated.
Slice-10 detail-pages layer: the importer writes 7 additional wikilink axes, 2 new note classes (transaction types + mandates) and a life-area layer into the vault. Plugin code unchanged (tolerant of extended note schemas).
Tests: 684 green. Bundle size: ~165 kB (main.js).
journal.ledger,
with click-through navigation to category, account and payee notesopening balance (as-of date per account) + transactions after that date. Transactions before the as-of date are filtered out, so the
bootstrap workflow never double-counts. Accounts without anfangssaldo_eur: get a TBC marker.:tbc: transaction with a one-click action: assign account, save
categorizer rule, remove tagjournal.ledger and
accounts.ledger inside the plugin: no Python, no uv, no subprocess. Works on mobile too.
Account configuration comes from a konten.yaml in the vault (setting: accounts file).categorizer-rules/accounts.ledger plus a frontmatter crawl,
deduplicatedobsidian://finance?mode=ledger&filter=… to drive the filters from outside
The plugin does not compute from raw data — it reads the hledger journal the importer wrote and turns it into views. The one place where it does compute is the account balance:
The plugin parses opening_balances.ledger with a small dedicated parser
(src/aggregator/openingBalances.ts):
parseOpeningBalances(text: string): Map<account, {amount, standAm}>
computeSaldo(account) = opening.amount + Sum(tx where tx.date > opening.standAm).
Bootstrap workflow: you put the current bank balance and today's date into the account
note's frontmatter (anfangssaldo_eur + anfangssaldo_stand_am). The importer turns that
into opening_balances.ledger. The plugin then filters out transactions before the as-of date.
isDesktopOnly: false).journal.ledger, accounts.ledger and optionally
opening_balances.ledger. Without a journal the views show nothing.konten.yaml in the vault. No Python,
no uv — this path works on mobile as well.uv, and a checkout of the Python importer.This plugin is not distributed through the community store. It lives on its own forge, and there are two ways to get it.
Recommended — via AnySource Sideloader, which installs and updates plugins from any git forge. Subscribe to this catalog once:
https://git.jkaindl.de/jkaindl/obsidian-catalog/raw/branch/main/catalog.json
Finance Ledger then appears in the sideloader's plugin list and updates like any other plugin — no manual copying, and every download is checksum-verified.
By hand, if you would rather not add another plugin:
main.js, manifest.json and styles.css from the
latest release.<vault>/.obsidian/plugins/finance-ledger/.Updates then have to be repeated by hand — the sideloader route exists to avoid exactly that.
From source: npm install && npm run build produces the same files; npm run deploy puts
them straight into a configured vault (see Build and deploy).
The pie-chart icon in the ribbon opens the dashboard. Everything else lives in the command palette:
| Command | View |
|---|---|
Open finance dashboard |
five-card overview: balances, TBC backlog, recurring items, top spending, upcoming contracts |
Open ledger viewer |
the filterable transaction table |
Open balance overview |
balance per account, corrected for the as-of date |
Open category overview |
hierarchical category aggregate |
Open TBC triage |
the open :tbc: transactions with one-click assignment |
Rebuild journal from CSVs (built-in) |
rebuilds journal.ledger and accounts.ledger — no external process |
Finance: import CSV |
multi-file upload with deduplication (desktop only) |
The usual loop: rebuild or import the journal → work through TBC triage (each assignment also writes a categorizer rule, so the same transaction lands by itself next time) → read the dashboard.
From outside, the plugin can be driven through
obsidian://finance?mode=ledger&filter=….
Settings → Community plugins → Finance Ledger:
uv binary path, with auto-detect fallbackThe full documentation lives in docs/:
The plugin uses three layers:
--fl-* tokens for finance-specific semantics (credit/debit/TBC colours, account-type
accents, money display, typed card top borders)--fl-* tokens, with light-mode
corrections for AA contrastWired into five views — balance overview, finance dashboard, ledger view, TBC triage and
category overview. Money values carry .fl-money plus a sign colour, account chips a
data-type outline, cards a data-card top border, status dots .fl-txn-state. The
light-mode bridge dims the signal colours to keep AA contrast.
Detailed documentation: docs/design.md (high level plus wiring state)
and docs/design/README.md (canonical token files).
The Python CLI importer that produces the journal is a separate project and is not
published yet. Its output in the vault lives under <vault>/<financeRoot>/Ledger/ plus
the note folders (German names, as the code expects them) 10-Konten, 20-Verträge,
30-Sparziele, 40-Monatsberichte, 45-Kategorien, 55-Categorizer-Rules, 60-Empfänger,
70-Quartalsberichte, 80-Jahresberichte and 05-Bases.
Everything the plugin needs beyond that journal — the built-in rebuild from CSVs — it does on its own.
Every note the importer writes (account, report, category, payee, rule) uses a marker pattern that protects user edits:
---
frontmatter
---
<user-editable header>
<!-- BEGIN: AUTO-GENERATED -->
auto section (tables, mermaid charts, bases embeds, cross-references)
<!-- END: AUTO-GENERATED -->
## 📌 Notes
user edit zone — untouched on re-runs.
On top of that: mermaid charts (pie for top categories, bar and xy-line for trends) and
collapsible bases embeds inside [!quote] callouts.
Monthly reports carry a budget section: target (12-month average) / actual / forecast (linear extrapolation) / difference / traffic light (🟢 below 90 % of target, 🟡 90–110 %, 🔴 above 110 %). A caveat warning appears when the average rests on fewer than 12 months.
npm install # once
npm test # vitest run (684 green)
npm run build # esbuild → main.js (repo root)
npm run dev # esbuild --watch (inline sourcemap, no minify)
npm run deploy # build + copy manifest.json, main.js, styles.css into a vault
npm run deploy copies into the target set through an environment variable:
export OBSIDIAN_PLUGIN_DIR="<vault>/.obsidian/plugins/finance-ledger"
npm run deploy
Then in Obsidian: Settings → Community plugins → turn off safe mode → enable Finance
Ledger. On updates, run npm run deploy again and reload the plugin (toggle it off and
on, or Cmd+R).
| Path | Purpose |
|---|---|
src/ |
TypeScript sources (views, ui, parser, resolver, state, types, utils, aggregator, categorizer rules) |
src/aggregator/openingBalances.ts |
as-of-aware parser for opening_balances.ledger |
src/aggregator/saldo.ts |
as-of-aware computeSaldo |
tests/ |
vitest specs (684 tests green) |
docs/design/ |
canonical design-system source of truth |
docs/design.md |
high-level design-system explanation |
styles.css |
plugin styles with tokens and utilities |
manifest.json |
Obsidian plugin manifest (id: finance-ledger) |
main.js |
esbuild output (committed, as Obsidian plugins require) |
package.json |
npm scripts |
esbuild.config.mjs |
bundle config |
vitest.config.ts |
test config |
tsconfig.json |
TypeScript config |
AGENTS.md |
architecture conventions for coding agents |
CHANGELOG.md |
release notes |
LICENSE)LICENSE-DOCS)Copyright © 2026 Johannes Kaindl.