Spending Analysis
Purpose
Provides rules for analyzing categorized transaction data — aggregating spending by category, comparing month-over-month, detecting unusual transactions, and generating savings recommendations.
Category Aggregation
For a given month, aggregate all categorized transactions:
- •Group transactions by
category - •For each category, compute:
- •
total: Sum of all transaction amounts (absolute values for expenses) - •
transaction_count: Number of transactions - •
avg_transaction:total / transaction_count
- •
- •Calculate each category's percentage of total spending:
category_total / total_spending × 100 - •Sort categories by total (highest first)
Write results to monthly-summary.csv.
Receipt-Level Breakdown
For a given merchant, aggregate spending at the receipt-item level instead of the transaction level. Used when the user asks about spending at a specific merchant (e.g., "Hvad bruger jeg hos Bilka?").
Data Source
- •Read
receipts.csv, filter bymerchant(case-insensitive match against normalized merchant name perskills/categorization/SKILL.md) - •If
monthargument is provided, also filter bydatecolumn (YYYY-MM prefix match) - •Collect all matching
receipt_idvalues and theirdatevalues - •Determine which monthly files to read: extract unique YYYY-MM values from the receipt dates
- •For each monthly file
receipt-items-{YYYY-MM}.csv: read it if it exists, filter to rows wherereceipt_idis in the collected set. Skip missing files. - •Combine all matching rows
Aggregation Rules
Group matching receipt items by subcategory:
- •For each subcategory, compute:
- •
total: Sum oftotal_pricefor all items in that subcategory - •
item_count: Sum ofquantityfor all items in that subcategory - •
avg_price:total / item_count
- •
- •Calculate each subcategory's percentage of total merchant spending:
subcategory_total / merchant_total × 100 - •Sort subcategories by total (highest first)
Top Items per Subcategory
For each subcategory, identify the top 3 most purchased individual items:
- •Group items by
item_namewithin the subcategory - •For each item, compute:
- •
purchase_count: Sum ofquantityacross all receipts - •
item_total: Sum oftotal_priceacross all receipts
- •
- •Sort by
purchase_count(highest first), break ties byitem_total - •Return top 3
Overall Top Items
Across all subcategories, identify the top 3 most frequently purchased items using the same logic as above but without the subcategory grouping.
Multi-Month Handling
- •Month specified: Show totals for that month only. Header:
{Merchant} — Indkøbsoversigt {month_name} {year} - •No month specified: Show all-time totals plus a per-month average. Header:
{Merchant} — Indkøbsoversigt samlet- •Per-month average:
total / number_of_distinct_months(count distinct YYYY-MM values from matching receipts)
- •Per-month average:
Output Format: Merchant Breakdown
## {Merchant} — Indkøbsoversigt {month or "samlet"}
**Antal kvitteringer**: {count}
**Samlet forbrug**: {total} kr
### Fordeling pr. varekategori
| Kategori | Beløb | Andel | Antal varer |
|----------|-------|-------|-------------|
| {subcategory} | {amount} kr | {pct}% | {item_count} |
| ... | ... | ... | ... |
### Hyppigst købte varer
1. {item_name} — {count}x — {total} kr
2. {item_name} — {count}x — {total} kr
3. {item_name} — {count}x — {total} kr
If no month is specified, append a summary line after the table:
**Gennemsnit pr. måned**: {avg} kr ({month_count} måneder)
Month-Over-Month Comparison
Compare the current month's spending to the previous month:
- •For each category present in either month:
- •
vs_prev_month:current_total - previous_total(absolute difference in kr) - •
vs_prev_month_pct:(current_total - previous_total) / previous_total × 100
- •
- •Flag categories with significant changes:
- •Increase > 20%: highlight as notable increase
- •Decrease > 20%: highlight as notable decrease
- •New category (not in previous month): flag as new spending area
If there is no previous month data (first month of tracking), skip the comparison.
Unusual Transaction Detection
Flag individual transactions that stand out:
By Amount
- •Transaction amount > 3× the average for its category
- •Single transaction > 5.000 kr (unless the category is Bolig or Indkomst)
By Frequency
- •Multiple transactions to the same merchant on the same day (possible duplicate charges)
- •Weekend transactions to work-related merchants
By Category Mix
- •A merchant that usually falls in one category appearing in a different one
Savings Recommendations
Generate actionable suggestions based on analysis:
Subscription Savings
- •Unused subscriptions: Subscriptions where
status: activebut no other transactions to that merchant's category (e.g., Viaplay active but no streaming usage signals) - •Duplicate services: Multiple subscriptions in the same subcategory (e.g., Netflix + HBO Max + Viaplay = 3 streaming services)
- •Price increases: Subscription amount increased > 10% from the average
Category Savings
- •High dining spend: If Restauranter > 15% of total, suggest cooking more
- •Transport optimization: If Taxi subcategory > Transport total × 30%, suggest alternatives
- •Impulse shopping: If Shopping has many small transactions (> 10 in a month, avg < 200 kr), flag as potential impulse purchases
Formatting Suggestions
Present each suggestion as:
{action} — Spar {amount} kr/år
Example: "Opsig Viaplay — Spar 1.188 kr/år"
Danish Currency Formatting
All user-facing monetary values must use Danish formatting:
- •Thousands separator: period (
.) - •No decimal places for whole amounts in casual output
- •Suffix:
kr(with space before) - •Examples:
- •
1.847 kr(one thousand eight hundred forty-seven) - •
28.450 kr(twenty-eight thousand four hundred fifty) - •
149 kr(no thousands separator needed) - •
4.200 kr(four thousand two hundred)
- •
Output Format: Spending Overview
When presenting a spending overview, use this structure:
## {Month} {Year} — Overblik
**Samlet forbrug**: {total} kr
### Fordeling pr. kategori
| Kategori | Beløb | Andel | Ændr. |
|----------|-------|-------|-------|
| {category} | {amount} kr | {pct}% | {change} |
| ... | ... | ... | ... |
### Abonnementer ({count} aktive)
| Tjeneste | Månedlig | Årlig | Status |
|----------|----------|-------|--------|
| {service} | {amount} kr | {annual} kr | {status} |
| ... | ... | ... | ... |
**Total abonnementer**: {total} kr/måned ({annual_total} kr/år)
### Forslag til besparelser
1. {suggestion} — Spar {amount} kr/år
2. {suggestion} — Spar {amount} kr/år
Output Format: Monthly Report
When generating a detailed report, include additional sections:
## {Month} {Year} — Månedlig rapport
### Resumé
{2-3 sentence summary of the month's spending}
### Forbrug pr. kategori
{Category breakdown table as above}
### Sammenlignet med {previous_month}
{Highlight notable changes — increases, decreases, new categories}
### Usædvanlige transaktioner
{List any flagged transactions with amounts and reasons}
### Abonnementer
{Subscription table as above}
{Note any changes: new subscriptions, cancellations, price changes}
### Handlinger i denne måned
{List actions taken from the Action Log: syncs, cancellations, etc.}
### Anbefalinger
{Savings suggestions with estimated annual impact}
Examples
Category Aggregation Example
Given 5 transactions in January 2026:
Netto -347.50 Dagligvarer Føtex -289.00 Dagligvarer Netflix -149.00 Abonnementer DSB -72.00 Transport Wolt -198.00 Restauranter
Monthly Summary rows:
month: 2026-01, category: Dagligvarer, total: 636.50, count: 2, avg: 318.25 month: 2026-01, category: Restauranter, total: 198.00, count: 1, avg: 198.00 month: 2026-01, category: Abonnementer, total: 149.00, count: 1, avg: 149.00 month: 2026-01, category: Transport, total: 72.00, count: 1, avg: 72.00
Savings Recommendation Example
Detected 3 streaming subscriptions: - Netflix: 149 kr/måned (1.788 kr/år) - HBO Max: 149 kr/måned (1.788 kr/år) - Viaplay: 99 kr/måned (1.188 kr/år) Total: 397 kr/måned (4.764 kr/år) Suggestion: "Overvej at konsolidere streamingtjenester? Netflix + HBO Max + Viaplay = 397 kr/måned"