What they do and how
Wes Eklund keeps his personal finances in a local system he calls fiduciary. The official Plaid CLI pulls balances, transactions, liabilities and investment holdings from his banks; older history comes from bank CSV exports. A Python script merges everything into a single SQLite file on his machine, removing duplicates. Claude Code, opened in the project folder, reads a CLAUDE.md that encodes a financial-planning method (a fiduciary test, a five-layer priority pyramid, an order of operations for the next dollar, target ratios and a review calendar) and eight skills that query the database with sqlite3: intake interview, questions, next-dollar allocation, quarterly health check, card and account tactics, spending audit, weekly report and sync.
Reported result
Stated by the author on X: the system covers more than 3,300 transactions across 18 months, and “it told me I was bleeding $200/mo in fees I didn't know about”. The repository's CLAUDE.md is consistent with that volume (about 3,312 transactions, December 2024 to June 2026). There is no breakdown of the fees and no other figure; we have not audited them. The project has one maintainer and about ten stars on GitHub.
Stated figures. An identified person or organization states that they have used it. The results are stated by the source; we have not audited them.
What has really been tested
On 22 October 2026 we read the two X posts and their replies, the README, CLAUDE.md, the eight SKILL.md files, docs/PRIVACY.md, the scripts and the tests at commit 2ed1505. Its 66 unit tests pass with pytest on Python 3.13. With fictional CSVs we ran ingest.py and the spending-audit and monthly-total queries: the recurring-charges query found the three subscriptions we had planted. We also found three behaviours you need to know: two identical purchases on the same day are kept only once, an amount written with a decimal comma (12,50) is read as 1,250, and Chase-format files keep Chase's sign (spending negative), the opposite of the ledger's convention. We did not link a real bank through Plaid or run the skills inside Claude Code.
How to replicate it
On macOS or Linux, clone the repository, install the Plaid CLI with Homebrew, create a free Plaid account and apply for the Trial plan (US and Canadian institutions only), link your banks and run scripts/sync.sh. Outside the US and Canada, skip Plaid and drop bank CSVs into data/statements/ after converting them to Date,Description,Amount with positive spending. Open Claude Code in the folder, run /onboard to write your profile to local memory, then ask questions or run /spending-audit and /weekly-report. Use an API key with commercial terms, keep the folder out of cloud sync and adapt the US-specific rules in CLAUDE.md to your country.
In two sentences
Wes Eklund, a software engineer who builds AI agents, turned his household money into a local, queryable ledger: the Plaid CLI syncs his bank accounts into SQLite and Claude Code, steered by a CLAUDE.md full of financial-planning rules and eight skills, acts as an advisor that has to show the maths from his own data. He says it covers more than 3,300 transactions over 18 months and that the first thing it found was about $200 a month in fees he did not know he was paying; the whole system is published under the MIT licence.
Who does it and why it matters
Eklund announced the project on X on 8 July 2026: “Just open sourced my personal finance system. Plaid CLI pulls live data into SQLite, Claude Code skills query it as a fiduciary advisor. 3,300+ transactions across 18 months. It told me I was bleeding $200/mo in fees I didn’t know about.” A day later he posted it again as a “privacy-first financial advisor”. His X profile says he builds AI agents and previously worked at AWS. The repository’s history starts in early June 2026 with a Plaid CLI toolkit and, a few days later, a commit titled “Encode financial advisor mental models into CLAUDE.md”; version 1.0.0 is dated 1 July.
The case is useful for three reasons. First, it is a person using an agent on his own finances, not a vendor demo: the README’s motivation is that “most financial apps sell you products or harvest your data”, generic advice ignores your situation and a human advisor costs “$200-400/hour”. Second, it shows a clean split of responsibilities that keeps appearing in the best personal-finance cases with agents: deterministic code fetches and stores the data, and the model only reads it and reasons over it. Third, everything that makes the advisor behave is in plain files you can read, copy and change: the planning method, the skills, the permissions and the privacy rules.
The thread also gives an honest dose of reality. Replies joked that the $200 a month was the Claude subscription, and one user said he had it running with a different agent (pi) after it built itself support for .claude/skills. Eklund answered that he supports Claude Code and Hermes explicitly but that “any agent runtime should work”. There is no further community feedback: the repository has a single maintainer and about ten stars.
Tools and architecture
Data in. The Plaid CLI is Plaid’s own command-line tool, released in April 2026 with JSON output designed to be read by agents. On the free Trial plan, Plaid’s help centre says you get production access for up to 10 connected institutions, but only if you are a developer in the United States or Canada and only for US and Canadian institutions. scripts/sync.sh calls plaid balance, plaid transactions list, plaid liabilities and plaid investments holdings, saves dated JSON snapshots and then rebuilds the database. Because Plaid returns roughly the last 30 days, the author backfilled older months with CSV exports from his banks.
The ledger. scripts/ingest.py parses the Plaid snapshots and every CSV in data/statements/, detects the bank format from the headers and writes two tables to data/finance.db: transactions (date, description, amount, merchant, Plaid category, account, institution, source) and accounts (balances and limits). The convention is that positive amounts are money spent and negative amounts money received, which is also Plaid’s convention. Each transaction gets an ID that is a hash of date, description, amount and the last four digits of the account, and INSERT OR IGNORE drops anything already there. The database file is set to chmod 600, and the data folder gets a marker so macOS Spotlight does not index it.
The advisor. CLAUDE.md is the brain. It defines a fiduciary test for every recommendation (loyalty, care, evidence from the ledger, no conflicts), a five-layer pyramid (protection, safety, accumulation, freedom, legacy) that must be worked bottom-up, a ten-step order of operations for the next dollar, decision rules such as “debt APR > 7%: always pay debt first”, a table of target ratios (debt-to-income, savings rate, credit utilisation, dining-to-grocery, fees as a share of income) and a review calendar. It also documents the schema so that the agent writes correct SQL.
The skills. Eight Agent Skills live in .claude/skills/: /onboard (an intake interview), /finance-query, /next-dollar, /health-check, /tactics, /spending-audit, /weekly-report and /sync-data. Each is a SKILL.md with a description that tells the agent when to use it, the allowed tools (mostly Bash and Read) and ready-made SQL. Your personal profile (income, debts, goals) is written by /onboard to Claude Code’s memory files under ~/.claude/projects/, never to the repository.
The guard rails. .claude/settings.json pre-approves only reading files, running the sync script and a handful of read-only Plaid commands. A pre-commit hook and a CI workflow block commits that include the data folder, database files or dollar amounts in the public part of CLAUDE.md. docs/PRIVACY.md and a 462-line threat model explain what leaves the machine.
Step by step to replicate it
- Check the prerequisites: macOS or Linux (Windows through WSL), Python 3.8 or later, SQLite and Homebrew, plus Claude Code or another Agent Skills runtime.
- Clone the repository and enable its hooks (
git config core.hooksPath .githooks) so that you cannot commit your data by accident. - Decide how data will come in. In the US or Canada: install the Plaid CLI, register, apply for the Trial plan, log in, fetch keys and run
plaid linkfor each bank. Anywhere else: export CSVs from your bank and convert them (template below). - Build the ledger with
bash scripts/sync.sh(Plaid) orpython3 scripts/ingest.py(CSV only). Check the summary it prints: total transactions and date range. - Sanity-check the data before asking for advice: signs, duplicates and transfers between your own accounts (queries below).
- Run
/onboardin Claude Code. It asks about goals, situation and risk tolerance and writes your profile to local memory. - Ask and audit. Start with factual questions (
/finance-query), then/spending-auditto look for subscriptions and fees, and/weekly-reportonce a week. Use/next-dollarand/health-checkonly once the data is clean. - Keep a review routine: sync weekly, review subscriptions monthly, and rerun
/health-checkquarterly, as the CLAUDE.md calendar suggests.
Copy and adapt
Subsections 1 to 4 are reproduced from the fiduciary repository, Copyright (c) 2026 Wes Eklund, under the MIT licence, at commit 2ed1505; keep that notice if you copy them. Subsections 5 to 7 are Agents Finance templates based on fiduciary, not files published by the author.
1. Install, connect and sync (README, literal)
Source: README.md (MIT).
git clone https://github.com/weklund/fiduciary.git && cd fiduciary
git config core.hooksPath .githooks
brew install plaid/plaid-cli/plaid
plaid register # opens browser — create a free Plaid developer account
plaid trial # apply for the free Trial plan (auto-approved in ~60 seconds)
plaid login # authenticate the CLI (opens browser for OAuth)
plaid keys fetch # download your API keys
plaid link --products transactions,liabilities,investments # connect your bank (opens browser)
bash scripts/sync.sh # pull data + build local DB
Then open Claude Code in the folder (the skills are discovered automatically) and run /onboard.
2. The advisor’s rules (CLAUDE.md, extract)
Source: CLAUDE.md (MIT). The full file also has target ratios, behavioural principles, the review calendar and the schema. The account types and thresholds are US-specific.
### Fiduciary Standard
Every recommendation must pass the fiduciary test:
- **Duty of Loyalty:** Prioritize the client's financial wellbeing above all else
- **Duty of Care:** Provide competent, situation-specific advice — not generic platitudes
- **Evidence-based:** Use data from the ledger, not assumptions. Show the math.
- **No conflicts:** This system doesn't sell products. It exists solely to optimize the client's outcomes.
### The Financial Planning Pyramid (Priority Hierarchy)
Work bottom-up. Never optimize a higher layer while a lower one is unstable.
Layer 5: LEGACY — Estate planning, wealth transfer, charitable giving
Layer 4: FREEDOM — Aspirational goals, lifestyle choices, early retirement
Layer 3: ACCUMULATION — Investing, retirement savings, goal funding
Layer 2: SAFETY — Full emergency fund, adequate insurance, stable cash flow
Layer 1: PROTECTION — Basic expenses covered, high-interest debt managed, no fees bleeding
### Key Decision Rules
**Invest vs. Pay Debt:**
- Debt APR > 7%: Always pay debt first (guaranteed return beats market uncertainty)
- Debt APR 5-7%: Gray zone — split approach or match to risk tolerance
- Debt APR < 5%: Invest the difference (historically favored by market returns)
- Exception: ALWAYS capture employer match regardless of debt level
**Emergency Fund Sizing:**
- Dual stable income: 3 months essential expenses
- Single income: 6 months
- Variable/self-employed: 6-12 months
3. What the agent may run without asking (.claude/settings.json, literal)
Source: .claude/settings.json (MIT). Anything else, such as writing files or other shell commands, still triggers Claude Code’s permission prompt.
{
"permissions": {
"allow": [
"Read",
"Bash(bash scripts/sync.sh)",
"Bash(plaid balance --all *)",
"Bash(plaid transactions list --all *)",
"Bash(plaid transactions sync --all *)",
"Bash(plaid liabilities --all *)",
"Bash(plaid investments --all *)"
]
}
}
4. A skill and the subscription finder (extracts)
Sources: finance-query/SKILL.md and spending-audit/SKILL.md (MIT).
---
name: finance-query
description: >
Answer questions about personal finances — balances, transactions, spending
patterns, account status, recent purchases, merchant history, income tracking.
Use when the user asks anything about their money, accounts, or transactions.
allowed-tools: Bash, Read
---
## Instructions
Answer the user's financial question using the unified SQLite ledger.
### Steps
1. Check if `data/finance.db` exists. If not, suggest running `python3 scripts/ingest.py` first.
2. Query the database using sqlite3 to answer the user's question.
3. Present results clearly with specific numbers, dates, and merchant names.
-- Find merchants that appear monthly with consistent amounts
SELECT description,
ROUND(AVG(amount),2) as avg_amount,
COUNT(*) as occurrences,
MIN(date) as first_seen,
MAX(date) as last_seen
FROM transactions
WHERE amount > 0 AND amount < 500
GROUP BY description
HAVING COUNT(*) >= 2
AND (MAX(date) > date('now', '-60 days'))
ORDER BY avg_amount * 12 DESC;
5. Agents Finance template: convert a European bank CSV
Agents Finance template based on fiduciary’s generic CSV format. It fixes the three problems we hit in testing: decimal commas, spending shown as negative, and identical same-day purchases that the dedup hash would merge. Save it as eu_csv_to_fiduciary.py, outside data/.
#!/usr/bin/env python3
"""Convert a European bank CSV export into fiduciary's generic format.
Output columns: Date,Description,Amount (ISO dates, dot decimals,
POSITIVE = money spent, NEGATIVE = money received).
Identical lines on the same day get a " #2", " #3"... suffix so that
fiduciary's dedup hash does not drop real repeated purchases.
"""
import argparse
import csv
from collections import Counter
from datetime import datetime
def eu_amount(raw: str) -> float:
s = raw.strip().replace("€", "").replace("\u00a0", "").replace(" ", "")
if "," in s: # 1.234,56 -> 1234.56
s = s.replace(".", "").replace(",", ".")
return float(s)
def main() -> None:
p = argparse.ArgumentParser()
p.add_argument("input")
p.add_argument("output")
p.add_argument("--date", default="Fecha")
p.add_argument("--desc", default="Concepto")
p.add_argument("--amount", default="Importe")
p.add_argument("--date-format", default="%d/%m/%Y")
p.add_argument("--delimiter", default=";")
p.add_argument("--encoding", default="utf-8-sig")
p.add_argument("--keep-sign", action="store_true",
help="the bank already shows spending as positive; do not flip")
a = p.parse_args()
seen = Counter()
rows = 0
with open(a.input, newline="", encoding=a.encoding) as f_in, \
open(a.output, "w", newline="", encoding="utf-8") as f_out:
reader = csv.DictReader(f_in, delimiter=a.delimiter)
writer = csv.writer(f_out)
writer.writerow(["Date", "Description", "Amount"])
for row in reader:
if not (row.get(a.date) or "").strip():
continue # blank or footer line
day = datetime.strptime(row[a.date].strip(), a.date_format).strftime("%Y-%m-%d")
desc = " ".join(row[a.desc].split())
amount = eu_amount(row[a.amount])
if not a.keep_sign: # most EU banks show spending as negative
amount = -amount
key = (day, desc.lower(), f"{amount:.2f}")
seen[key] += 1
if seen[key] > 1:
desc = f"{desc} #{seen[key]}"
writer.writerow([day, desc, f"{amount:.2f}"])
rows += 1
print(f"{rows} rows written to {a.output}")
if __name__ == "__main__":
main()
python3 eu_csv_to_fiduciary.py extracto.csv data/statements/bank-2026-10.csv \
--date Fecha --desc Concepto --amount Importe
python3 scripts/ingest.py
6. Agents Finance template: checks before trusting any advice
Agents Finance template based on fiduciary’s schema. Run these with sqlite3 -header -column data/finance.db (or ask the agent to run them) after each import.
-- 1. Sign check by file: spending files should be mostly positive.
SELECT source_file,
SUM(amount > 0) AS positive_rows,
SUM(amount < 0) AS negative_rows,
ROUND(SUM(amount), 2) AS net
FROM transactions
GROUP BY source_file
ORDER BY source_file;
-- 2. Months covered by more than one source (possible double counting).
SELECT substr(date, 1, 7) AS month,
GROUP_CONCAT(DISTINCT source) AS sources,
COUNT(*) AS rows
FROM transactions
GROUP BY month
HAVING COUNT(DISTINCT source) > 1;
-- 3. Large inflows that may be transfers or card payments, not income.
SELECT date, description, amount, account_type, source_file
FROM transactions
WHERE amount < -100
ORDER BY date DESC
LIMIT 30;
7. Agents Finance template: the fee finder
Agents Finance template based on fiduciary’s spending-audit queries, aimed at the kind of finding the author reports. Adjust the patterns to the words your banks use.
-- Fees and interest by month and by description, last 12 months.
SELECT substr(date, 1, 7) AS month,
description,
COUNT(*) AS times,
ROUND(SUM(amount), 2) AS total
FROM transactions
WHERE amount > 0
AND date >= date('now', '-12 months')
AND ( (' ' || LOWER(description) || ' ') LIKE '% fee %' -- not COFFEE
OR (' ' || LOWER(description) || ' ') LIKE '% fees %'
OR LOWER(description) LIKE '%interest charge%'
OR LOWER(description) LIKE '%overdraft%'
OR LOWER(description) LIKE '%late payment%'
OR LOWER(description) LIKE '%foreign transaction%'
OR LOWER(description) LIKE '%comision%'
OR LOWER(description) LIKE '%intereses%'
OR LOWER(category) = 'bank_fees') -- Plaid's primary category
GROUP BY month, description
ORDER BY month DESC, total DESC;
A prompt to pair with it in Claude Code (Agents Finance template):
Use the finance-query conventions in this project. Run the fee finder query in
fees.sql against data/finance.db. Then list every fee or interest charge with
its account, monthly and annual cost, and the date of the last charge. For each
one say, in one line, what usually causes it and one concrete way to avoid it.
Do not recommend any financial product by brand. Show the SQL you ran and the
totals, and flag any line you are not sure is a fee.
Prerequisites
- A computer where you can use a terminal, Python and SQLite. It is a developer’s tool: there is no app or installer.
- For live bank sync, a Plaid account on the Trial plan, which Plaid limits to developers in the US and Canada and to US and Canadian institutions, with up to 10 connected institutions. Everyone else can use CSV exports only.
- Claude Code (not included in Claude’s free plan; prices are on the tool page linked from this entry) or another Agent Skills runtime. The privacy guide recommends an API key under commercial terms rather than a consumer subscription.
- Enough financial literacy to challenge the advice: the frameworks are general rules of thumb, and the US account types (401(k), HSA, Roth IRA) need translating to your country’s equivalents.
A concrete example: a fictional month with a hidden fee
We built a fictional statement in the generic format with ten lines over September and October 2026: two months of a streaming subscription and a gym, a monthly account service fee, a foreign transaction fee, groceries, a pizza and a salary. ingest.py loaded the ten lines and printed the date range. The subscription query from the spending-audit skill returned the gym ($39.00, twice), the streaming service ($15.49, twice) and the monthly service fee ($12.00, twice); the fee finder above added the $3.10 foreign transaction fee. The monthly-totals query showed $66.49 spent in September and $181.79 spent against $3,100.00 received in October.
Then we tried what a European user would do with a raw export. A line for 12,50 euros was loaded as 1,250.00, two identical €4.50 coffees on the same day became a single row, and the sample Chase file in the project’s own test fixtures came in with the coffee and Amazon purchases as negative and the payroll deposit as positive +3,200, which the skills would count as spending. We then wrote a fictional Spanish-style export (semicolons, day/month/year dates, decimal commas, spending as negative) and ran it through the conversion template: it loaded with both coffees, a €12.00 account fee that the fee finder picks up, and the salary as a negative amount, as the ledger expects. None of this is a criticism of the author’s own use, which is US banks through Plaid, but it is exactly where an agent will confidently give advice on wrong numbers.
Results stated by the source
Two statements, both from the author on X and neither audited: the system holds “3,300+ transactions across 18 months”, and “it told me I was bleeding $200/mo in fees I didn’t know about”. The data-coverage note in CLAUDE.md is consistent with the first (about 3,312 transactions between December 2024 and June 2026, from Plaid since March 2026 and Chase and Amex exports before that). There is no breakdown of the $200, no before-and-after and no measure of time saved. Our checks are limited to the tests and the fictional run described above.
Limitations and risks
- Data sent to the model. Query results from your ledger go to your AI provider. The project’s privacy guide recommends a commercial API key, notes that consumer plans with training opt-in should not be used for this, and suggests a local model as the zero-trust option at the cost of quality.
- Local logs. Agent runtimes keep conversation history, including query results, in plain text on disk; the guide recommends shorter retention and excluding those folders from backups and cloud sync.
- US-only bank sync and US-centric advice. Plaid’s Trial plan does not cover other countries, and the order of operations, account types and thresholds are American.
- Ingestion quirks that we observed: decimal commas, Chase-style negative spending, Capital One payments recorded as positive, and same-day duplicates merged by the dedup hash. Overlapping Plaid and CSV periods are not deduplicated against each other, because descriptions and account digits differ.
- Advice, not a licensed adviser. The name refers to the method encoded in CLAUDE.md; no regulated professional reviews the output.
- Single-maintainer project. Pin a commit and keep your own copy of the rules you rely on.
Common mistakes
- Asking
/next-dollarbefore cleaning the data: one sign error turns a salary into spending and every ratio after it is wrong. - Counting transfers and credit card payments as income or spending; check large inflows first.
- Writing personal figures into the public CLAUDE.md instead of letting
/onboardkeep them in local memory. - Keeping the project in a synced folder (iCloud, Dropbox, OneDrive) where the database and logs leave your machine.
- Copying the US rules unchanged to another tax system.
Conclusions
fiduciary is a small project with a big idea: you do not need a finance app to get an agent that knows your money, just your own data in a file, a written method the model must follow and a few skills that turn questions into SQL. Its best parts to copy are the CLAUDE.md that makes the agent show its maths against a priority pyramid, the allow-list of read-only commands and the discipline of keeping the profile and the data out of git. Before you let it advise you, though, make sure the numbers are right: convert your bank files, check signs and duplicates, and treat the output as a well-argued draft that you still decide on.
Sources
- GitHub — weklund/fiduciary (MIT), commit 2ed1505 (opens in a new tab) (primary)
- X — Wes Eklund: “Just open sourced my personal finance system…” (8 July 2026) (opens in a new tab)
- X — Wes Eklund: “shipped it… privacy-first financial advisor” (9 July 2026) (opens in a new tab)
- fiduciary — CLAUDE.md (advisory frameworks, schema, conventions) (opens in a new tab)
- fiduciary — docs/PRIVACY.md (what stays local and what leaves the machine) (opens in a new tab)
- Plaid Docs — Plaid CLI (opens in a new tab)
- Plaid Help Center — What is the Plaid Trial plan? (opens in a new tab)
We wrote this entry in our own words from the sources above and checked that the links worked on October 22, 2026. Is anything incorrect? Tell us.