# Expense Categorizer

> Categorizes bank or credit-card statement transactions into Income, Saving, and Expenditure (with sub-categories like Food, Bills, Shopping, Travel, Rent, etc.), and reports totals plus a savings rate. Use this whenever the user shares a bank statement, credit card statement, or transaction export (CSV, Excel, or PDF) and wants it analyzed, categorized, or broken down — including requests like "categorize my expenses", "how much did I save this month", "split my spending vs savings", "analyze my bank statement", "what did I spend money on", or "give me a budget breakdown". Also use it if the user pastes/types a list of transactions directly instead of a file.

- Skill: `kayalkathir/expense-categorizer` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add kayalkathir/expense-categorizer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kayalkathir/expense-categorizer/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: kayalkathir (https://skillmd.com/u/kayalkathir)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/kayalkathir/expense-categorizer

---


# Expense Categorizer

Classify each transaction in a bank/credit-card statement as **Income**,
**Saving**, or **Expenditure** (with a sub-category), then report totals and a
savings rate. Categorization is keyword/merchant-based: it looks at the
transaction description and matches it against editable keyword lists — it
does not require an LLM call per transaction, so it's fast and deterministic
even on statements with hundreds of rows.

## When to use this

Trigger on requests to analyze, categorize, or summarize personal
transactions — whether from an uploaded file or pasted as text. Don't wait for
the user to say "use expense-categorizer"; if they hand you a statement and
ask what they spent or saved, this is the tool.

## Workflow

1. **Get the input.** If the user attached/named a file, use it directly. If
   they pasted transactions as text instead, save them to a temporary CSV
   first with columns `date,description,debit,credit` (or `date,description,amount`
   with signed values) before running the script — don't try to categorize by
   reading the pasted text yourself, the script's keyword matching is the
   source of truth and keeps results consistent.

2. **Run the script:**
   ```
   python scripts/categorize.py <input_file> --out <output_file>.csv
   ```
   It handles `.csv`, `.xlsx`/`.xls` directly via pandas, and `.pdf` by
   extracting tables with `pdfplumber` (install with `pip install pdfplumber`
   if missing). It auto-detects the description column and either a
   debit/credit pair or a single signed amount column — if it can't find
   them, it raises an error naming the columns it did find, so you can tell
   the user what to check or rename.

   Many bank-generated PDF statements are password-protected. If the user
   gives you a password, pass it with `--password <pw>` — don't write it to
   any file or log, just pass it as the CLI argument for that one run.

3. **Report the results.** The script prints a summary (total income, total
   expenditure, total saving, savings rate, and a per-category breakdown) and
   writes the full categorized transaction list to the output CSV. Present
   the summary to the user directly, and mention where the categorized CSV
   was saved. Highlight anything that looks off (e.g. a large chunk landed in
   "Other" — see step 4).

4. **Handle misses.** Any expenditure that doesn't match a keyword falls into
   "Other". If a meaningful share of transactions end up there, look at the
   actual descriptions and suggest specific keyword additions to the user
   rather than guessing — then add them to `SAVING_KEYWORDS`,
   `INCOME_KEYWORDS`, or `EXPENDITURE_CATEGORIES` in
   `scripts/categorize.py` (and mirror the change in
   `references/categories.md` for readability) so future runs pick them up.
   These lists are meant to evolve with the user's own bank's wording — don't
   hesitate to edit them.

5. **Categorization logic** (for reference — already implemented in the
   script, only relevant if you need to explain or adjust behavior):
   - A transaction matching a **saving** keyword (SIP, FD, RD, mutual fund,
     transfer to own savings/investment account, etc.) is **Saving**,
     regardless of whether it's a debit or credit.
   - Any other **credit** (money in) is **Income**.
   - Any other **debit** (money out) is **Expenditure**, sub-categorized by
     matching `EXPENDITURE_CATEGORIES` keywords, defaulting to "Other".

## Notes

- Statement formats vary a lot bank to bank. The column auto-detection covers
  common naming ("Narration", "Particulars", "Debit", "Withdrawal Amt", etc.)
  but if a statement uses unusual headers, rename the relevant columns in the
  source file (or tell the script author) rather than fighting the detector.
- PDF extraction quality depends on the statement's layout. If
  `pdfplumber` finds no tables, the PDF is likely scanned/image-based and
  needs OCR before this skill can help — tell the user that rather than
  guessing at numbers.
- This categorizes based on *description text*, not amount thresholds — a
  ₹50,000 transfer and a ₹50 one are classified the same way if the
  description matches the same keyword.

