Automating Expense Reporting with OpenClaw, Raspberry Pi, and Claude
How I built Khalti, an OpenClaw-based personal finance agent that runs on a Raspberry Pi and turns transaction emails into expense reports.
Expense tracking is one of those problems that sounds simple until you try to keep it running every day. The hard part is not adding up numbers. The hard part is collecting transactions from different institutions, normalizing them, categorizing them, remembering to review them, and turning them into a report before the context disappears.
I built Khalti to handle that workflow for me. It is an OpenClaw-based personal finance agent that runs on a Raspberry Pi, uses Gmail transaction emails as its input stream, and keeps a lightweight markdown ledger that can be reviewed and corrected over time.
The goal was not to build a full finance app. I wanted a small, reliable system that could sit in the background, collect transactions, ask me for judgment only when needed, and produce daily, weekly, and monthly views of my spending.
Why OpenClaw
OpenClaw gave me the agent runtime I needed: long-running context, scheduled jobs, tool execution, and conversational follow-up. That mattered because the workflow is not a single script. It is a loop.
Every day, the agent needs to:
- scan new transaction emails
- decide whether each message is an actual transaction
- extract amount, date, payee, institution, and transaction type
- append the result to the current weekly file
- ask me to clean up categories and splits
- remind me if anything is still uncategorized
- generate weekly and monthly reports on schedule
Claude helped me shape that loop into concrete operating instructions, templates, and scripts. Instead of starting with a giant application, I used Claude to turn the desired behavior into agent documentation: AGENTS.md for runtime behavior, TOOLS.md for local tool mechanics, REQUIREMENTS.md for functional requirements, and report templates for weekly and monthly summaries.
That documentation became the contract for the agent.
Running It on a Raspberry Pi
The Raspberry Pi is a good fit for this kind of project because the workload is small but persistent. It does not need a large server. It needs to wake up on schedule, check email, update files, and post summaries.
Khalti uses a simple workspace layout:
data/
├── config.json
├── transactions/
├── reports/YYYY/
└── trend-chart.png
The config.json file is the source of truth. It stores the timezone, categories, default category, Gmail settings, transaction source mappings, delivery channel, cron schedules, retry policy, and optional report destinations.
The Pi also runs himalaya, a command-line email client, for Gmail access over IMAP. I used the aarch64 Linux build, which fits the Raspberry Pi environment well. OpenClaw calls himalaya to list new mail and read message bodies, then the agent decides which emails represent real transactions.
That distinction is important. A bank email is not always a transaction. Statement notices, security alerts, login notifications, payment reminders, and promotional messages should not become ledger entries. Khalti is instructed to log only emails that represent a charge, payment, purchase, refund, transfer, or withdrawal that changes a balance.
Normalizing Different Institutions
Each institution formats transaction emails differently. Some include the merchant in the subject. Some put the useful fields in the body. Some use the same sender for multiple cards or accounts.
To handle that, Khalti treats source mappings as a lookup table, not a filter. The agent scans all new Gmail messages. If the sender is known, it maps the message to the configured institution and can use hints to disambiguate sub-accounts. If the sender is unknown but the email is clearly a transaction, the agent still logs it and raises it during review.
A source entry looks like this:
{
"sender_email": "[email protected]",
"institution": "Example Bank",
"sub_accounts": [
{
"label": "Example Rewards Card",
"match_hint": "Rewards"
}
]
}
That made the system practical across different banks, cards, and wallets. I do not need a perfect parser for every institution on day one. I need the agent to collect what it can, preserve the data in a predictable format, and surface uncertainty when something new appears.
Markdown as the Ledger
I intentionally kept the storage layer boring. Transactions are written to weekly markdown files:
weekly-YYYY-MM-DD--YYYY-MM-DD.md
Inside the file, transactions are grouped by day:
## 2026-04-27
1 | $12.34 | Merchant Name | Institution | type: DEBIT | category = UNSET | split = 1
2 | $50.00 | Refund Source | Institution | type: CREDIT | category = Groceries | split = 1
This format is easy for an agent to edit, easy for me to inspect, and easy for scripts to parse. It also gives me an audit trail without introducing a database too early.
The category = UNSET field is the key. Khalti can guess categories when it is confident, but the system is designed around review. Every morning, the agent presents the previous day's transactions. I can reply with category and split corrections, and the agent updates the weekly file directly.
If I do nothing, OpenClaw applies the configured default category at the end of the day. That keeps the ledger from staying permanently half-finished.
Scheduling the Workflow
The useful part of Khalti is the schedule. OpenClaw cron jobs drive the routine:
- morning collection from Gmail
- morning review of the previous day's transactions
- evening reminders for uncategorized debit transactions
- weekly reports
- monthly reports
- monthly trend chart generation
Reports are rendered from markdown templates. The weekly report summarizes spending by category and calls out uncategorized items. The monthly report aggregates the previous calendar month, writes a markdown report, and generates charts with local Python scripts.
For charts, Khalti uses matplotlib:
python3 scripts/gen_monthly_pie_chart.py --month 2026-03
python3 scripts/gen_monthly_trend_chart.py --months 12
The monthly pie chart shows category distribution. The trend chart gives a longer view of spending over time. Both scripts read the same weekly markdown files, so the reports stay tied to the ledger rather than a separate export format.
Where Claude Helped
Claude was most useful as a systems design partner. The interesting work was not writing one parser. It was turning a fuzzy personal workflow into a set of rules the agent could follow repeatedly.
I used Claude to clarify questions like:
- What counts as a transaction?
- What should be skipped?
- Where should runtime configuration live?
- How should unknown institutions be handled?
- What should the weekly file format look like?
- Which steps need confirmation before posting externally?
- How should Discord messages be formatted differently from markdown reports?
Those answers became durable workspace files. OpenClaw provides the execution loop. Claude helped me compress the behavior into instructions that the agent can reload, follow, and improve.
What I Learned
The biggest lesson was that personal automation works better when the system is allowed to be partially uncertain. Khalti does not need to perfectly categorize every expense. It needs to collect the transaction, store it consistently, ask good review questions, and make correction cheap.
The second lesson was that markdown is enough for a surprising amount of automation. A weekly markdown ledger is transparent, portable, and agent-friendly. When the data model is simple, the agent can spend more effort on judgment and less effort fighting infrastructure.
The Raspberry Pi also changed the feel of the project. Instead of a cloud app I have to deploy and monitor, Khalti feels like a small household service. It runs quietly, checks in on schedule, and gives me a better view of spending across different institutions without making me open every banking app.
Khalti is still intentionally small, but that is the point. It is a practical OpenClaw workflow: email in, markdown ledger, agent review, scheduled reports out.