Get the FREE Ultimate OpenClaw Setup Guide →

categorization

npx machina-cli add skill peerjakobsen/smartspender/categorization --openclaw
Files (1)
SKILL.md
11.3 KB

Categorization

Purpose

Provides Claude with Danish merchant knowledge and categorization rules for classifying bank transactions into spending categories.

Categories

15 Danish spending categories with subcategories:

CategorySubcategoriesDescription
BoligHusleje, El, Vand, Varme, ForsikringHousing costs
DagligvarerSupermarked, SpecialbutikGroceries
TransportOffentlig, Bil, Taxi, CykelTransportation
AbonnementerStreaming, Fitness, Software, TelefonSubscriptions
RestauranterRestaurant, Café, TakeawayDining out
ShoppingTøj, Elektronik, Bolig, AndetShopping
SundhedApotek, Læge, TandlægeHealth
UnderholdningBiograf, Koncert, SpilEntertainment
RejserFly, Hotel, FerieTravel
BørnDaginstitution, Tøj, LegetøjChildren
Personlig plejeFrisør, KosmetikPersonal care
UddannelseKurser, Bøger, MaterialerEducation
OpsparingOverførsler til opsparingSavings transfers
IndkomstLøn, RefusionIncome
AndetUkategoriseretOther / fallback

Merchant Pattern Database

Map raw transaction text patterns to normalized merchant names and categories. Patterns use * as wildcard.

Dagligvarer (Groceries)

PatternMerchantSubcategory
*NETTO*NettoSupermarked
*FØTEX* or *FOETEX*FøtexSupermarked
*REMA*1000* or *REMA1000*Rema 1000Supermarked
*IRMA*IrmaSupermarked
*LIDL*LidlSupermarked
*ALDI*AldiSupermarked
*BILKA*BilkaSupermarked
*MENY*MenySupermarked
*SPAR*SparSupermarked
*FAKTA*FaktaSupermarked
*COOP*CoopSupermarked
*DAGLIG*BRUGSEN* or *DAGLI*BRUGSEN*Dagli'BrugsenSupermarked
*SUPER*BRUGSEN*SuperBrugsenSupermarked
*KVICKLY*KvicklySupermarked

Transport

PatternMerchantSubcategory
*DSB*DSBOffentlig
*REJSEKORT*RejsekortOffentlig
*MOVIA*MoviaOffentlig
*Q8*Q8Bil
*CIRCLE*K*Circle KBil
*SHELL*ShellBil
*OK BENZIN* or *OK PLUS*OKBil
*UBER*UberTaxi
*TAXA* or *DANTAXI*TaxaTaxi
*DONKEY*REPUBLIC*Donkey RepublicCykel

Abonnementer (Subscriptions)

PatternMerchantSubcategory
*NETFLIX*NetflixStreaming
*SPOTIFY*SpotifyStreaming
*DISNEY*PLUS* or *DISNEYPLUS*Disney+Streaming
*HBO* or *MAX*STREAMING*HBO MaxStreaming
*VIAPLAY*ViaplayStreaming
*TV2*PLAY* or *TV 2 PLAY*TV2 PlayStreaming
*YOUTUBE*PREMIUM* or *GOOGLE*YOUTUBE*YouTube PremiumStreaming
*APPLE*MUSIC*Apple MusicStreaming
*FITNESS*WORLD*Fitness WorldFitness
*FITNESS*DK*Fitness DKFitness
*SATS*SATSFitness
*TDC* or *YOUSEE*TDCTelefon
*TELENOR*TelenorTelefon
*TELIA*TeliaTelefon
*ADOBE*Adobe CCSoftware
*MICROSOFT*365* or *MICROSOFT*OFFICE*Microsoft 365Software
*ICLOUD* or *APPLE.COM/BILL*iCloudSoftware
*DROPBOX*DropboxSoftware

Restauranter (Dining)

PatternMerchantSubcategory
*WOLT*WoltTakeaway
*JUST*EAT*Just EatTakeaway
*TOO GOOD TO GO* or *TOOGOODTOGO*Too Good To GoTakeaway
*STARBUCKS*StarbucksCafé
*JOE*THE*JUICE* or *JOE & THE JUICE*Joe & The JuiceCafé
*LAGKAGEHUSET*LagkagehusetCafé
*MCDONALDS* or *MC DONALDS*McDonald'sRestaurant
*BURGER*KING*Burger KingRestaurant

Shopping

PatternMerchantSubcategory
*H&M* or *H M * or *HM *H&MTøj
*ZALANDO*ZalandoTøj
*IKEA*IKEABolig
*ELGIGANTEN*ElgigantenElektronik
*POWER*PowerElektronik
*NORMAL*NormalAndet
*FLYING*TIGER*Flying TigerAndet
*SØSTRENE*GRENE* or *SOSTRENE*GRENE*Søstrene GreneAndet
*AMAZON*AmazonAndet
*JYSK*JyskBolig

Bolig (Housing)

PatternMerchantSubcategory
*ØRSTED* or *OERSTED*ØrstedEl
*HOFOR*HOFORVand
*TRYG*TrygForsikring
*TOPDANMARK*TopdanmarkForsikring
*ALKA* or *CODAN*CodanForsikring
*HUSLEJE* or *FAST OVERFØRSEL*HUSLEJE*HuslejeHusleje
*NORLYS*NorlysEl
*EWII*EwiiEl

Sundhed (Health)

PatternMerchantSubcategory
*APOTEK*ApoteketApotek
*MATAS*MatasApotek
*TANDLÆGE* or *TANDLAEGE*TandlægeTandlæge
*LÆGE* or *LAEGE*LægeLæge

Underholdning (Entertainment)

PatternMerchantSubcategory
*NORDISK*FILM*Nordisk FilmBiograf
*CINEMAXX*CinemaxXBiograf
*TICKETMASTER*TicketmasterKoncert
*BILLETLUGEN*BilletlugenKoncert

Rejser (Travel)

PatternMerchantSubcategory
*SAS* or *SCANDINAVIAN*AIRLINES*SASFly
*NORWEGIAN*NorwegianFly
*RYANAIR*RyanairFly
*AIRBNB*AirbnbHotel
*HOTELS.COM* or *BOOKING.COM*Booking.comHotel

Personlig pleje

PatternMerchantSubcategory
*SEPHORA*SephoraKosmetik
*FRISØR* or *FRISOER* or *CUTTERS*FrisørFrisør

Uddannelse (Education)

PatternMerchantSubcategory
*SAXO*SaxoBøger
*AMAZON*KINDLE*Amazon KindleBøger

Normalization Rules

Before matching patterns, normalize the raw transaction text:

  1. Convert to uppercase for matching
  2. Replace Danish characters: ØOE, ÆAE, ÅAA (for pattern matching only — preserve originals in raw_text)
  3. Collapse multiple spaces into one
  4. Trim leading/trailing whitespace

Transaction Type Detection

Use the transaction description prefix to identify the payment method:

Prefix PatternTypeNotes
Dankort-købCard payment (physical)Danish debit card
Visa-købCard payment (physical)Visa card
OverførselBank transferInternal or external
Fast overførselStanding orderRecurring transfer
PBS or BetalingsserviceDirect debitSubscriptions and bills
MobilePayMobile paymentPerson-to-person or merchant
Løn fraSalaryIncome — categorize as Indkomst
HævningATM withdrawalCategorize as Andet

Matching Order

When categorizing a transaction, check these sources in order — stop at the first match:

  1. learnings/categorization.md — Check for user corrections learned from previous sessions (confidence 1.0). These take precedence over all other rules.
  2. learnings/merchants.md — Check for merchant name aliases to normalize the raw text before pattern matching.
  3. merchant-overrides.csv — Check for a matching raw_pattern (confidence 1.0). These are learned from previous user corrections within the same session.
  4. Static pattern database — Check the merchant pattern tables above (confidence 1.0 exact / 0.8 partial).
  5. Intelligent classification — No pattern match, but Claude can infer category from transaction context (confidence 0.5–0.7).
  6. Fallback — Cannot determine category — assign to "Andet" (confidence 0.0).

Confidence Scoring

Assign a confidence score to each categorization:

Match TypeConfidenceDescription
Merchant override match1.0Transaction text matches a learned override in merchant-overrides.csv
Exact pattern match1.0Transaction text matches a known merchant pattern
Partial pattern match0.8Part of the text matches a known pattern
Intelligent classification0.5–0.7No pattern match, but Claude can infer from context
Unknown0.0Cannot determine category — assign to Andet

When manual_override is TRUE for a transaction, always use the user's category regardless of what patterns suggest.

Learning from Corrections

When a user manually corrects a transaction's category, the correction should be saved to learnings/categorization.md so future sessions automatically apply the learned rule.

How to record a categorization learning:

  1. Open learnings/categorization.md
  2. Append a new row to the Learnings table with:
    • Date: Today's date (YYYY-MM-DD)
    • Pattern: The normalized raw text pattern to match (uppercase, wildcards allowed)
    • Merchant: The normalized merchant name
    • Category: The user-corrected category
    • Subcategory: The user-corrected subcategory
    • Context: Brief note about why this correction was made

Example learning entry:

| 2026-01-15 | *NETFLIX* | Netflix | Underholdning | Streaming | User: "Netflix er underholdning, ikke abonnement" |

Also update merchant-overrides.csv for the current session:

  1. Take the corrected transaction's raw_text from transactions.csv
  2. Normalize it: uppercase, trim whitespace, collapse multiple spaces
  3. Use this as the raw_pattern
  4. Use the user-corrected merchant, category, and subcategory from categorized.csv
  5. Set created_at to the current timestamp
  6. Only append if no row with the same raw_pattern already exists

Ambiguous Merchants

  • Netto: Always Dagligvarer, even though they sell non-grocery items
  • 7-Eleven: Dagligvarer (most purchases are food/drink)
  • Amazon: Default to Shopping unless description contains "Prime" or "Kindle" (then Abonnementer or Uddannelse)
  • Normal: ShoppingAndet (sells mixed categories)
  • Matas: SundhedApotek (primarily health/beauty)
  • Wolt: RestauranterTakeaway unless the Wolt+ subscription charge (then Abonnementer)

Examples

Example 1: Clear Match

raw_text: "NETTO FO 1234 KØBENHAVN"
normalized: "NETTO FO 1234 KOEBENHAVN"
pattern match: *NETTO* → Netto
result: category=Dagligvarer, subcategory=Supermarked, merchant=Netto, confidence=1.0

Example 2: PBS Subscription

raw_text: "PBS FITNESS WORLD"
normalized: "PBS FITNESS WORLD"
pattern match: *FITNESS*WORLD* → Fitness World
result: category=Abonnementer, subcategory=Fitness, merchant=Fitness World, confidence=1.0, is_recurring=TRUE

Example 3: Intelligent Classification

raw_text: "RESTAURANT COFOCO KBH"
normalized: "RESTAURANT COFOCO KBH"
no pattern match — but "RESTAURANT" prefix suggests dining
result: category=Restauranter, subcategory=Restaurant, merchant=Cofoco, confidence=0.6

Example 4: Income

raw_text: "Løn fra Arbejdsgiver ApS"
prefix match: "Løn fra" → salary
result: category=Indkomst, subcategory=Løn, merchant=Arbejdsgiver ApS, confidence=1.0

Source

git clone https://github.com/peerjakobsen/smartspender/blob/main/skills/categorization/SKILL.mdView on GitHub

Overview

Provides Claude with Danish merchant knowledge and categorization rules to classify bank transactions into spending categories. It maps raw transaction text to normalized merchant names and 15 main categories with subcategories, enabling consistent budgeting and reporting in Danish contexts.

How This Skill Works

The skill uses a Merchant Pattern Database to map raw transaction text to normalized merchant names and a Danish subcategory. Patterns use wildcards (*) to match merchant names (e.g., *NETTO*, *DSB*, *LAGKAGEHUSET*) and assign the appropriate 15-category + subcategory pairing such as Dagligvarer: Supermarked or Transport: Offentlig.

When to Use It

  • When organizing Danish bank transactions into spending categories for budgeting
  • When you need consistent merchant name normalization from raw text
  • When analyzing recurring payments in Abonnementer or attempting to classify subscriptions
  • When handling new or ambiguous merchants that should map to Andet
  • When auditing or exporting categorized data for Danish financial reports

Quick Start

  1. Step 1: Input the raw bank transaction text
  2. Step 2: Run it through the Merchant Pattern Database to find a match
  3. Step 3: Assign the corresponding normalized merchant and the Danish category/subcategory

Best Practices

  • Keep the 15 category definitions aligned with your chart of accounts
  • Regularly update merchant patterns to reflect new names and brands
  • Test wildcard patterns against common feeds to minimize misclassification
  • Prioritize exact matches before wildcard fallbacks
  • Maintain a fallback to Andet for unrecognized patterns

Example Use Cases

  • Pattern *NETTO* → Dagligvarer > Supermarked (Netto)
  • Pattern *DSB* → Transport > Offentlig
  • Pattern *NETFLIX* → Abonnementer > Streaming
  • Pattern *LAGKAGEHUSET* → Restauranter > Café
  • Pattern *WOLT* → Restauranter > Takeaway

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers