--- name: budget-import-from-csv risk_class: config_mutation inputs: [csv_file] references: [containers/129-house.md] --- # Runbook: Budget import from N26 CSV → Yuvomi Distil a bank-export CSV into Yuvomi's Budget and Subscriptions modules using the `yuvomi-mcp` tools. Run this whenever a new CSV period needs to be summarised into targets and fixed costs. --- ## Prerequisites - `yuvomi-mcp` is running on LXC 129 and connected as an MCP server in Claude. - The CSV is an N26 export (columns: Booking Date, Value Date, Partner Name, Partner Iban, Type, Payment Reference, Account Name, Amount (EUR), …). - API token: `homelab secret yuvomi-api-token` (decrypts on any enrolled client). - Direct API base: `https://house.hubris.network/api/v1` --- ## API quirks (Yuvomi ≤ 0.77.x) - **Subscriptions live under `/budget/subscriptions`**, NOT `/subscriptions/`. A top-level `/subscriptions` route returns 404. - `GET /budget/subscriptions` → `{ data: { subscriptions: [...], summary: {...} } }` - `GET /budget/subscriptions/meta` → `{ data: { categories: [...], payment_methods: [...] } }` - `POST /budget/subscriptions` → create a subscription (name, amount, billing_cycle, cycle_interval, next_payment_date, currency, category_id, payment_method_id required) - `GET /budget/` (no month) → returns only **non-recurring** base entries. Use `GET /budget/?month=YYYY-MM` to get all entries (recurring + one-time) for a month. - `GET /budget/categories` → expense category keys + income category names (German keys like `"Erwerbseinkommen"`, `"Sozialleistungen"`, `"Geschenke & Transfers"`). - Budget entries: `amount` positive = income, negative = expense. - Recurring entries: set `is_recurring: 1` + `recurrence_interval: "monthly"`. The `date` field sets the start month. - `recurrence_virtual: 1` smooths non-monthly amounts across all months in the summary (e.g. 55.08 € quarterly → shows as ~18.36 €/month). - Custom RRULE strings (`recurrence_rule`) are **not accepted** by the API — use `cycle_interval` on the subscription instead, or `recurrence_interval` on budget entries. --- ## Subscription category IDs (as of 2026-06-26) | id | name | budget_subcategory_key | |---|---|---| | 1 | Entertainment | subscription_entertainment | | 2 | Productivity | subscription_productivity | | 3 | Utilities | subscription_utilities | | 4 | Health | subscription_health | | 5 | Education | subscription_education | | 6 | Other | subscription_other | ## Payment method IDs | id | name | |---|---| | 1 | Credit Card | | 2 | Debit Card | | 3 | PayPal | | 6 | Bank Transfer / SEPA | | 7 | Other | --- ## Step 1 — Categorise the transactions Skip these as internal/already-covered: - Fixed costs you'll enter as **subscriptions** (Miete, SWM, SYNVIA, Hundefutter, Netflix, Grover, Rundfunk ARD, KuKita, Lillydoo) - Internal transfers (The Joy Pot ↔ Cookie, Hauptkonto, Tagesgeldkonto splits) - Identified income (Cookie Share, Kindergeld, Pocket Money credits, Distributor) - Fun Money pass-throughs (in and out same month → net zero) **Variable expense taxonomy:** | Category key | Subcategory key | Examples | |---|---|---| | `food` | `groceries` | E-Center, Knuspr, EDEKA, Tegut, VollCorner, Lidl, Netto, REWE, KoRo, Roast Market | | `food` | `restaurants_bars` | Restaurants, Lieferando, Cafes, Zeit für Brot, Baobab, Höflinger | | `personal_health` | `beauty_cosmetics` | DM, Rossmann | | `personal_health` | `pharmacy` | Apotheke, MVZ Dermatologie | | `transport` | `apps_taxi` | Uber, RYD GMBH, MVG, Handyparken | | `shopping_clothing` | `gifts` | Children products: Schlummersack, Catchy Kids, SP EVERY., Dukal, Berger-Lernwelt | | `shopping_clothing` | `clothes_shoes` | Zalando, Ernsting's, Schuhmair, Thalia, Vinted, Airbnb, Hotel at Booking.com | | `shopping_clothing` | `electronics` | Amazon, AMZN Mktp DE | | `housing` | `renovation_maintenance` | IKEA, Markus Festl, Granit, Sostrene Grene, Mol* tischdecken, Gaertnerei, Dehner | | `education` | `courses_college` | Kathrin Orlob (PEKiP), Nerina Aupperle | | `leisure` | `streaming` | WOW wowtv.de | | `financial_other` | `bank_fees` | Unidentified PayPal, Ratepay, N26 fees | | `Geschenke & Transfers` | *(income)* | One-off incoming transfers | --- ## Step 2 — Create subscriptions ``` get_subscriptions_meta() ← get category_id and payment_method_id ``` **Standard Cookie household subscriptions (as of 2026-07):** | Name | Amount | billing_cycle | cycle_interval | category_id | payment_method_id | |---|---|---|---|---|---| | Miete | 1080.00 | monthly | 1 | 6 (Other) | 6 (Bank Transfer) | | Strom (SWM) | 79.00 | monthly | 1 | 3 (Utilities) | 6 | | Internet / TV / Telefon | 29.99 | monthly | 1 | 3 (Utilities) | 6 | | Hundefutter | 75.00 | monthly | 1 | 6 (Other) | 6 | | Netflix | 8.00 | monthly | 1 | 1 (Entertainment) | 6 | | Grover | 16.90 | monthly | 1 | 6 (Other) | 2 (Debit Card) | | Rundfunk ARD / ZDF | 55.08 | monthly | 3 | 1 (Entertainment) | 6 | | KuKita Daycare (Leon) | 503.00 | monthly | 1 | 5 (Education) | 6 | | Lillydoo diapers | 56.70 | monthly | 2 | 4 (Health) | 3 (PayPal) | Monthly equivalent total: **1,838.60 €** (Yuvomi applies cycle_interval to prorate). --- ## Step 3 — Add recurring income entries ``` stage_add_budget_entry( title="Kindergeld", amount=55.00, category="Sozialleistungen", date="YYYY-MM-01", is_recurring=True, recurrence_interval="monthly", ) commit_pending(pending_id) ``` **Standard recurring income:** | Title | Amount | category | |---|---|---| | Kindergeld | +55.00 | Sozialleistungen | | Cookie Share | +2650.00 | Erwerbseinkommen *(see recommended amount below)* | --- ## Step 4 — Post variable transactions For each non-skipped CSV row, call `stage_add_budget_entry` with the mapped category/subcategory and the actual transaction amount and date. Use the Partner Name + Payment Reference as the title (truncate to 100 chars). --- ## Step 5 — Verify ``` get_budget_summary("YYYY-MM") list_subscriptions() ``` Expected for a full month with KuKita: - Fixed expenses ≥ 1,838 € (subscriptions) - Variable expenses ≥ 500 € (groceries alone) --- ## Cookie Share: how much to transfer monthly Calculated from Jan–Jun 2026 data (Cookie account, one-offs stripped): | | €/month | |---|---| | **Fixed costs (subscriptions)** | **1,839** | | Miete | 1,080 | | KuKita *(permanent from Jul 2026)* | 503 | | Strom + SYNVIA + Rundfunk + Netflix + Grover + Hundefutter + Lillydoo | 256 | | **Variable (6-month averages)** | **1,032** | | Groceries | 595 | | Children products | 142 | | Dining & cafes | 100 | | Transport | 66 | | Drugstore | 52 | | Clothing, Amazon, Pharmacy | 77 | | **Total monthly spend** | **≈ 2,871** | | Minus Kindergeld (fixed income) | −55 | | Minus Pocket Money (conservative ~600 €) | −600 | | **→ Recommended Cookie Share** | **≈ 2,650 €** | | With 200 € buffer | **≈ 2,850 €** | **Current Cookie Share (Jun 2026): 1,995 € — shortfall ~655 €.** The gap was covered by irregular Pocket Money top-ups (avg 962 €/mo over 6 months, but highly variable: 121 €–3,000 €). KuKita starting in June is the biggest step-up; raising Cookie Share to **2,650 €** makes the budget self-sufficient without relying on top-ups. --- ## Changelog ### 2026-06-29 — Corrections from first real import - Subscriptions endpoint is `/budget/subscriptions`, NOT `/subscriptions/` (404). - `recurrence_rule` RRULE strings are rejected by the API; use `cycle_interval` instead. - `GET /budget/` (no filter) returns only non-recurring entries; use `?month=` for full view. - Added Cookie Share recommendation (2,650 €/month) based on 6-month expense analysis. - Added full category taxonomy table. ### 2026-06-29 — Initial runbook Created from Jan–Jun 2026 N26 Cookie account analysis.