Larin och ledgerctl — kuvertbudget

Envelope budgeting ovanpå finance.journal

[2026-07-24 Fri]

Syfte

Kuvertbudgeten ger varje krona ett jobb utan att blanda ihop budgetplanering med de verkliga banktransaktionerna.

Läs först Introduktion till kuvertbudgetering om du vill förstå principerna bakom kuvert, Ej fördelat, väntande köp och Att kategorisera innan du går vidare till kommandona.

Grundmodell

Betydelse Konto
Pengar på banken konfigurerat assets:*-konto
Ej fördelat budget:unallocated
Väntande inkomster budget:pending-income
Ett kuvert budget:groceries, budget:books, …
Virtuellt motkonto budget:external
Verklig konsumtion expenses:*

Utöver balansinvarianten gäller en kuverttäckningsinvariant: varje verklig post på ett budgetrelevant expenses:*-konto måste matcha exakt ett namngivet kuvert. Noll träffar gör utgiften osynlig för budgeten; flera träffar skulle tömma flera kuvert.

Det reserverade kuvertet Att kategorisera äger endast expenses:uncategorized och används som inkorg för okända utgifter.

Systemets centrala balansinvariant är:

banktillgång + budget:external = 0

Om budgeten påstår att mer eller mindre pengar finns än banklagret stödjer, misslyckas ledgerctl budget check.

Initiera budgetlagret

Stå i en initierad ledgerctl-arbetsyta:

cd ~/budget
ledgerctl budget init

Det skapar:

all.journal
budget/
  envelopes.conf
  auto.journal
  funding.journal

och lägger normalt följande i ledgerctl.conf:

BUDGET_DIR=budget
ALL_LEDGER=all.journal
BUDGET_ENABLED=1

Standardläget bootstrappar den ospeglade skillnaden mellan bankkontot och budget:external till budget:unallocated. Hoppa över detta med:

ledgerctl budget init --no-bootstrap

--force regenererar konfiguration och genererade filer men bevarar den append-only historiken i funding.journal.

Skapa kuvert med Larin CLI

Den rekommenderade vardagsvägen är:

larin kuvert add

Klienten frågar efter namn, kuvert-id och ett eller flera expenses:-konton. Kända konton har TAB-komplettering. Motorn bygger en staged konfiguration, validerar den och visar preview innan apply. larin skriver aldrig envelopes.conf eller auto.journal direkt.

Direkt form:

larin kuvert add \
  --label "Kläder" \
  --id clothes \
  --account expenses:shopping:clothes \
  --account expenses:clothing

Använd --preview-only för att granska utan skrivning.

Uppdatera ett befintligt kuvert

Lägg till eller ta bort kontorötter utan att redigera filer:

larin envelope update groceries \
  --add-account expenses:restaurants \
  --add-account expenses:fika

Namnbyte och borttagning kan kombineras i samma preview:

larin envelope update groceries \
  --label "Mat och restaurang" \
  --remove-account expenses:food \
  --preview-only

Ledgerctl bygger envelopes.conf och auto.journal i staging, kontrollerar överlappning, reservkuvert och hledger check och publicerar filerna atomiskt först efter apply.

Tilldela många kategorier med suggest-envelopes

När flera routes eller merchantkonton saknar kuvert:

ledgerctl suggest-envelopes
ledgerctl suggest-envelopes --scope all
ledgerctl suggest-envelopes --preview-only

Standardomfattningen är routes. --scope all tar även med merchantstandardkonton och verkliga journalposter. Assistenten:

  1. samlar unika otäckta utgiftskonton,
  2. rankar befintliga kuvert genom mekaniska träffar mot ID, etikett och kontohierarki,
  3. visar alla befintliga kuvert med nummer, ID och namn,
  4. erbjuder TAB-komplettering, numrerade val, nytt kuvert, detaljer, hoppa över och avbryt,
  5. accepterar kuvertnamn och ID utan hänsyn till stora och små bokstäver samt entydiga prefix,
  6. visar textmässigt liknande kuvert och frågar om ett nytt kuvert ska skapas när det angivna namnet inte finns,
  7. använder exakt konto som standard,
  8. erbjuder en bredare föräldrarot endast efter separat bekräftelse,
  9. samlar hela sessionen i en enda plan,
  10. visar en gemensam preview och skriver ingenting förrän den godkänts.

Exempel: om du skriver Matvaror men endast kuvertet Mat [groceries] finns, visar assistenten det liknande befintliga kuvertet och frågar sedan om Matvaror ska skapas som ett nytt kuvert. Ett ja lägger bara till det i den ännu oskrivna planen; den samlade previewn och slutliga bekräftelsen återstår.

När ett nytt kuvert skapas normaliseras namnet så att det börjar med stor bokstav. Det permanenta kuvert-ID:t härleds därefter från det slutliga namnet, skrivs med små bokstäver och använder bindestreck vid behov. Skriver du matvaror blir därför standardvärdena Matvaror och matvaror. Skriver du Hushåll och el blir standard-ID:t hushall-och-el. Båda värdena visas innan planen godkänns och kan fortfarande ändras manuellt.

Valet detaljer visar endast underkonton och konton i en tillräckligt specifik gemensam gren. För expenses:subscriptions:software kan exempelvis expenses:subscriptions:streaming visas, men ett enkelt konto som expenses:groceries leder inte längre till att samtliga expenses:* listas.

Hela planen valideras mot den slutliga kuvertmodellen. Därför kan flera ändringar och nya kuvert publiceras som en enda revisions- och digest-skyddad mutation utan halvdant mellanläge.

Avancerad manuell konfiguration

För mer omfattande ändringar kan du redigera budget/envelopes.conf:

[settings]
asset_account = assets:se:swedbank:konto
currency = SEK

[income]
accounts = income:salary, income:other

[envelope groceries]
label = Mat
accounts = expenses:groceries, expenses:food

[envelope books]
label = Böcker
accounts = expenses:hobbies:books, expenses:hobbies:bookshop

Efter varje ändring:

ledgerctl budget regen-auto
ledgerctl budget doctor

En kontorot matchar både kontot och underkonton. expenses:food matchar expenses:food:takeaway men inte expenses:foodtruck.

Kontorötter får inte överlappa mellan kuvert. Samma utgift skulle annars tömma flera kuvert och bryta invarianten.

Reserverade systemnamn som unallocated, pending-income och external får inte användas som kuvert-id.

Filer du får och inte får redigera

Fil Ägare Redigering
finance.journal bokföringslagret endast med normal hLedger-försiktighet
budget/envelopes.conf användaren ja, följt av regen-auto
budget/auto.journal ledgerctl nej; regenerera
budget/funding.journal ledgerctl nej; append-only maskintillstånd
all.journal ledgerctl-layout ändra inte include-strukturen manuellt

funding.journal har ett strikt versionsmärkt format. Försök inte laga ett valideringsfel genom att göra filen mer "hLedger-kompatibel" för hand; då kan hLedger och ledgerctl få olika uppfattning om budgeten.

Kontrollera kuverttäckningen

Snabb kontroll före import:

ledgerctl budget coverage --scope routes

Full kontroll av routes, merchants och journalposter:

ledgerctl budget coverage --scope all

Resultatet skiljer på otäckta konton och konton som matchar flera kuvert. Verkliga journalposter utan entydigt kuvert är blockerande fel. En merchant med fel standardkonto rapporteras även om den ännu inte har skapat en journalpost.

Läs status

Användarvänlig vy:

larin status
larin status --month 2026-07

Motornära tabell och JSON:

ledgerctl budget status
ledgerctl budget status --month 2026-07
ledgerctl budget status --month 2026-07 --format json

Tabellen skiljer på:

Pengar i JSON är exakta decimalsträngar, till exempel "700.00", aldrig flyttal.

Läs kuverthistorik

ledgerctl budget history books
ledgerctl budget history books --month 2026-07 --months 12
ledgerctl budget history books --month 2026-07 --format json

Historiken visar bland annat:

Analytics för diagram

För analys av ett kuvert:

ledgerctl budget analytics books \
  --month 2026-07 \
  --months 12 \
  --format json

ledgerctl räknar förbrukningsgrad, analystillstånd, historik och snitt. Emacs väljer sedan presentation: SVG i grafiskt läge och Unicode eller ASCII i terminal. Konsumenterna räknar inte om den ekonomiska analysen.

Säker mutationsmodell

Följande budgetkommandon är preview som standard:

--format json ändrar bara presentationen. Det gör inte kommandot skrivande.

För att verkställa krävs:

  1. en preview,
  2. revisionen som previewn/statusen visar,
  3. samma operation med --expected-revision REV,
  4. --apply.

Om någon relevant fil ändras mellan läsning och apply stoppas operationen utan skrivning.

Hämta aktuell revision i shell

revision=$(ledgerctl budget status --month 2026-07 --format json \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["revision"])')

Tilldela pengar från Ej fördelat

Preview:

ledgerctl budget fund groceries 5000 --format json

Verkställ med revisionen från den granskade previewn:

ledgerctl budget fund groceries 5000 \
  --expected-revision "$revision" \
  --format json \
  --apply

Beloppet ska vara positivt. Normalfallet tillåter inte att du allokerar mer än vad som finns i Ej fördelat.

Sätt månadens budgetbelopp

Preview:

ledgerctl budget set-budget books 900 \
  --month 2026-07 \
  --expected-revision "$revision" \
  --format json

Verkställ:

ledgerctl budget set-budget books 900 \
  --month 2026-07 \
  --expected-revision "$revision" \
  --format json \
  --apply

Detta sätter månadens målbelopp genom en kontrollerad differenspost; det skriver inte om äldre budgethistorik. set-budget får användas för aktuell eller framtida månad. En framtida plan dateras kanoniskt den första dagen i målmånaden.

I Emacs står du på kuvertet i den månad som visas och trycker e. Om budgetbokföringen har drift erbjuds en separat mirror-preview. Efter godkänd reparation läses den valda månaden om och den ursprungliga budgetredigeringen fortsätter automatiskt. Ingen reparation sker tyst.

Flytta budget mellan kuvert

Preview:

ledgerctl budget move transport books 210 \
  --month 2026-07 \
  --expected-revision "$revision" \
  --format json

Verkställ med --apply efter granskning.

Flytten påverkar inte Ej fördelat. Källans budgeterade belopp får inte bli negativt, men dess faktiska Kvar kan redan vara negativt när du gör en medveten omprioritering.

Pending och cleared

En pending utgift (!) tömmer kuvertet omedelbart, så att pengarna reserveras. När samma post blir cleared (*) ska Kvar förbli detsamma.

En pending inkomst läggs i budget:pending-income och kan inte fördelas. När den blir cleared flyttas den automatiskt till budget:unallocated genom auto-reglerna.

Transaktioner utan statusmarkering träffar inte dessa regler och kan därför bryta invarianten. Använd pending eller cleared.

Spegla off-budget-förändringar

En överföring mellan egna konton ändrar bankkontot utan att vara inkomst eller utgift:

assets:se:swedbank:konto   -5000 SEK
assets:se:sparande          5000 SEK

Då bryts invarianten tills ändringen speglas.

Preview mot Ej fördelat:

ledgerctl budget mirror --note "Överföring till sparande"

Preview mot ett särskilt kuvert:

ledgerctl budget mirror \
  --envelope buffer \
  --note "Överföring till buffert" \
  --format json

Verkställ med previewns revision och --apply. När driften redan är noll är operationen idempotent och skriver ingenting.

Svep positiva rester vid månadsslut

Preview:

ledgerctl budget sweep-month --format json

Kommandot visar vilka positiva kuvertsaldon som skulle flyttas till Ej fördelat. Verkställ med revision och --apply.

Negativa kuvert stoppar normalt sweep. Täck dem först med move. CLI-flaggan --force finns för ett uttryckligt undantag, men Emacs-gränssnittet exponerar inte den.

Sweep skapar inte en permanent periodlåsning; det är en batchmutation som nollställer positiva månadssaldon.

Periodskydd

Historiska perioder är skrivskyddade i Emacs. Budgetmål får däremot planeras för aktuell eller framtida månad med set-budget eller e. Övriga normala budgetmutationer gäller aktuell månad.

För en avsiktlig historisk rättelse via CLI krävs både ett explicit datum och --allow-noncurrent, där kommandot stöder det.

Exempel:

ledgerctl budget move transport books 100 \
  --month 2026-06 \
  --date 2026-06-30 \
  --allow-noncurrent \
  --expected-revision "$revision"

Granska alltid sådana rättelser extra noggrant. Emacs exponerar inte den historiska undantagsvägen.

Kontrollera invarianten

ledgerctl budget check

Vid korrekt läge summerar bankkontot och budget:external till noll.

Djup kontroll:

ledgerctl budget doctor
ledgerctl budget doctor --format json

Vanliga problem

Invarianten är bruten efter överföring till sparkonto

Kör budget mirror efter att du verifierat den verkliga banktransaktionen.

En utgift tömmer inget kuvert

Kör först:

ledgerctl budget coverage --scope all

Om problemet är en route eller kontorot använder du ledgerctl suggest-envelopes eller larin envelope update. Om det är ett manuellt köp med fel konto trycker du C i Emacs och klassificerar om posten. Försök inte stänga sådan drift med mirror; då skulle klassificeringsfelet bara maskeras.

Ett kuvert töms två gånger

Det tyder på överlappande kontorötter eller en manuellt modifierad auto-journal. Kör ledgerctl budget doctor och regenerera auto.journal först när konfigurationen är korrigerad.

Funding-format v2 avvisas

Återställ en känd korrekt version från backup eller versionskontroll. Redigera inte maskinjournalen godtyckligt.

Koppling till årsarkiv

ledgerctl archive tar snapshots av budget/envelopes.conf och budget/funding.journal. Den aktiva, kumulativa budgethistoriken fortsätter ändå in i nästa år.