← Skills

finance-skill

Parse bank statements, track transactions, reconcile accounts

Finance Skill

Personal finance memory layer. Parse statements, store transactions, query spending.

Data Location

  • Transactions: ~/.openclaw/workspace/finance/transactions.json
  • Raw statements: ~/.openclaw/workspace/finance/statements/

Storage convention: OpenClaw workspace (~/.openclaw/workspace/) is the standard location for persistent user data. This matches where session-memory and other hooks store agent data. Credentials/config would go in ~/.config/finance/ if needed.

Tools

1. Parse Statement

When user shares a statement (image or PDF):

⚠️ IMPORTANT: Telegram/channel previews truncate PDFs! Always extract with pypdf first to get ALL pages:

python3 -c " import pypdf reader = pypdf.PdfReader('/path/to/statement.pdf') for i, page in enumerate(reader.pages): print(f'=== PAGE {i+1} ===') print(page.extract_text()) "

Then parse the full text output:

  1. Extract transactions from ALL pages
  2. Return JSON array: [{date, merchant, amount, category}, ...]
  3. Run scripts/add-transactions.sh to append to store
  4. Verify total matches statement (sum of expenses should equal "Total purchases")

Extraction format:

Each transaction: {"date": "YYYY-MM-DD", "merchant": "name", "amount": -XX.XX, "category": "food|transport|shopping|bills|entertainment|health|travel|other"} Negative = expense, positive = income/refund.

Categories:

  • food: restaurants, groceries, coffee, fast food
  • transport: Waymo, Uber, gas, public transit
  • shopping: retail, online purchases
  • bills: utilities, subscriptions
  • entertainment: movies, concerts, theme parks
  • health: pharmacy, doctors
  • travel: hotels, flights

2. Query Transactions

User asks about spending → read transactions.json → filter/aggregate → answer

Example queries:

  • "How much did I spend last month?" → sum all negative amounts in date range
  • "What did I spend on food?" → filter by category
  • "Show my biggest expenses" → sort by amount

3. Add Manual Transaction

User says "I spent $X at Y" → append to transactions.json

File Format

{ "transactions": [ { "id": "uuid", "date": "2026-02-01", "merchant": "Whole Foods", "amount": -87.32, "category": "food", "source": "statement-2026-01.pdf", "added": "2026-02-09T19:48:00Z" } ], "accounts": [ { "id": "uuid", "name": "Coinbase Card", "type": "credit", "lastUpdated": "2026-02-09T19:48:00Z" } ] }

Usage Flow

  1. User: shares statement image
  2. Agent: extracts transactions via vision, confirms count
  3. Agent: runs add script to store
  4. User: "how much did I spend on food?"
  5. Agent: reads store, filters, answers

Dependencies

  • jq — for JSON transaction storage and querying (apt install jq / brew install jq)
  • pypdf — for full PDF text extraction (pip3 install pypdf)

Lessons Learned

  • Telegram truncates PDF previews — always use pypdf to get all pages
  • Verify totals — sum extracted expenses and compare to statement total before importing
  • Coinbase Card — no Plaid support, statement upload only

Future: Plaid Integration

  • Add finance_connect tool for Plaid OAuth flow
  • Auto-sync transactions from connected banks
  • Same query interface, different data source
View raw SKILL.md
# Finance Skill

Personal finance memory layer. Parse statements, store transactions, query spending.

## Data Location
- Transactions: `~/.openclaw/workspace/finance/transactions.json`
- Raw statements: `~/.openclaw/workspace/finance/statements/`

*Storage convention: OpenClaw workspace (`~/.openclaw/workspace/`) is the standard location for persistent user data. This matches where session-memory and other hooks store agent data. Credentials/config would go in `~/.config/finance/` if needed.*

## Tools

### 1. Parse Statement
When user shares a statement (image or PDF):

**⚠️ IMPORTANT: Telegram/channel previews truncate PDFs!**
Always extract with pypdf first to get ALL pages:

```bash
python3 -c "
import pypdf
reader = pypdf.PdfReader('/path/to/statement.pdf')
for i, page in enumerate(reader.pages):
    print(f'=== PAGE {i+1} ===')
    print(page.extract_text())
"
```

Then parse the full text output:
1. Extract transactions from ALL pages
2. Return JSON array: `[{date, merchant, amount, category}, ...]`
3. Run `scripts/add-transactions.sh` to append to store
4. **Verify total matches statement** (sum of expenses should equal "Total purchases")

**Extraction format:**
```
Each transaction: {"date": "YYYY-MM-DD", "merchant": "name", "amount": -XX.XX, "category": "food|transport|shopping|bills|entertainment|health|travel|other"}
Negative = expense, positive = income/refund.
```

**Categories:**
- food: restaurants, groceries, coffee, fast food
- transport: Waymo, Uber, gas, public transit
- shopping: retail, online purchases
- bills: utilities, subscriptions
- entertainment: movies, concerts, theme parks
- health: pharmacy, doctors
- travel: hotels, flights

### 2. Query Transactions
User asks about spending → read transactions.json → filter/aggregate → answer

**Example queries:**
- "How much did I spend last month?" → sum all negative amounts in date range
- "What did I spend on food?" → filter by category
- "Show my biggest expenses" → sort by amount

### 3. Add Manual Transaction
User says "I spent $X at Y" → append to transactions.json

## File Format

```json
{
  "transactions": [
    {
      "id": "uuid",
      "date": "2026-02-01",
      "merchant": "Whole Foods",
      "amount": -87.32,
      "category": "food",
      "source": "statement-2026-01.pdf",
      "added": "2026-02-09T19:48:00Z"
    }
  ],
  "accounts": [
    {
      "id": "uuid",
      "name": "Coinbase Card",
      "type": "credit",
      "lastUpdated": "2026-02-09T19:48:00Z"
    }
  ]
}
```

## Usage Flow

1. User: *shares statement image*
2. Agent: extracts transactions via vision, confirms count
3. Agent: runs add script to store
4. User: "how much did I spend on food?"
5. Agent: reads store, filters, answers

## Dependencies
- `jq` — for JSON transaction storage and querying (`apt install jq` / `brew install jq`)
- `pypdf` — for full PDF text extraction (`pip3 install pypdf`)

## Lessons Learned
- **Telegram truncates PDF previews** — always use pypdf to get all pages
- **Verify totals** — sum extracted expenses and compare to statement total before importing
- **Coinbase Card** — no Plaid support, statement upload only

## Future: Plaid Integration
- Add `finance_connect` tool for Plaid OAuth flow
- Auto-sync transactions from connected banks
- Same query interface, different data source