diff --git a/CLAUDE.md b/CLAUDE.md index 3bf4fb0..14dcc75 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This file covers what the code assumes and why. cmd/money/main.go subcommands; the TUI is the default internal/config rules.toml, account.toml, XDG config, data-root resolution internal/model Account, Transaction, amount formatting, description normalisation -internal/glob the `*` / `?` matcher used by rules (linear time, no backtracking) +internal/glob the `*` / `?` matcher used by rules (two-pointer, no exponential blowup) internal/parser Parser interface + registry; nlb, revolut, traderepublic internal/store SQLite index (modernc.org/sqlite, no cgo) internal/importer directory walk, dedupe, balance checks diff --git a/README.md b/README.md index ee5889a..2c4c994 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ tagged by glob rules you write. rules.toml # tag rules, in order index.db # SQLite index (rebuildable; safe to delete*) checking/ - account.toml # currency + how to parse this bank's exports + account.toml # currency + which parser reads this bank's exports 2026-01.csv 2026-02.csv savings/ @@ -63,7 +63,7 @@ money # open the TUI (default) money import # extract new transactions from every statement money import --force # re-parse statements even if unchanged money retag # re-apply rules.toml to everything already imported -money ls --untagged # what still needs a tag +money ls --untagged # what no rule has claimed yet money ls --wide # also show type and reported balance money ls --account checking --month 2026-01 money report --month 2026-01 # spending by tag @@ -82,12 +82,15 @@ imported — creating an `account.toml` is not enough on its own. Run | --- | --- | | `1` `2` `3` `4` `5` / `tab` | accounts · transactions · report · rule builder · rules | | `enter` | open the selected account (accounts view) | -| `4` | write a rule for what you are looking at — the only way to tag | | `/` | filter by description | | `u` | show only untagged transactions | | `a` | clear the account filter | | `i` | import · `r` re-apply rules · `q` quit | +There is no key that tags a transaction. Tags come from `rules.toml` and +nowhere else, so tagging what you are looking at means writing a rule for it on +`4` — which is why that screen shows you what a glob catches before you save. + ### Rule builder (`4`) Writing rules by hand means guessing what a glob will catch. This screen shows @@ -103,6 +106,12 @@ a `▸` against each one the glob currently matches and a running ╰────────────────────────────╯ ▸ LIDL SOFIA 4412 2 vs. the description ▸ LIDL VARNA 9911 1 ZARA MLADOST 1 + account +╭────────────────────────────╮ +│ blank = every account │ +╰────────────────────────────╯ + blank = all accounts + ▸ tag ╭────────────────────────────╮ │ groceries │ @@ -148,12 +157,12 @@ Rules that claim none are marked `✗`. ``` money · rules · 5 rules · 2 match nothing -# Pattern Account Tag T Txns Note -1 *LIDL* (all) groceries 3 the weekly shop -2 ✗ *LIDL SOFIA* (all) shadowed 0 -3 ✗ *OLD BANK NAME* (all) dead 0 closed in 2025 -4 *ZARA* (all) clothes 1 -5 *КАУФЛАНД* checking groceries 1 4412 is the branch +# Pattern Account Tag Txns Note +1 *LIDL* (all) groceries 3 the weekly shop +2 ✗ *LIDL SOFIA* (all) shadowed 0 +3 ✗ *OLD BANK NAME* (all) dead 0 closed in 2025 +4 *ZARA* (all) clothes 1 +5 *КАУФЛАНД* checking groceries 1 4412 is the branch ``` The count is how many transactions the rule *wins*, not how many its glob could @@ -163,7 +172,10 @@ can therefore reach zero either by matching nothing or by being shadowed, and both are worth deleting. `d` deletes the selected rule, `p` deletes every rule marked `✗` at once, and -both ask for a `y` first. Deleting edits `rules.toml` textually, so your +both ask for a `y` first. `r` recounts against what is currently in the index, +which is what you want after an import has added rows; `rules.toml` itself is +read at startup and whenever you save a rule from the builder, so an edit made +in another window needs a restart. Deleting edits `rules.toml` textually, so your comments, ordering and formatting survive; a comment sitting directly above a deleted rule goes with it, while one separated by a blank line is treated as a section heading and left alone.