Si alguna vegada heu hagut de fer funcionar una configuració de Beancount per a un company, un portàtil nou o una tasca programada de nit, sabeu que la comptabilitat mai no ha estat la part difícil. La part difícil era la cadena d'eines: un Python que coincideixi, bean-check i bean-query al PATH, una biblioteca de generació d'informes afegida per a un sol balanç, i un formatador que reescriu els vostres fitxers en el moment en què li feu una pregunta. bea 0.2.0, publicat el 12 de setembre de 2026, substitueix aquesta llista de verificacions amb una sola instal·lació. La comanda bea ara incorpora tota la cadena d'eines natives de Beancount, l'executa dins d'un motor gestionat que aprovisiona ella mateixa, i manté el contracte llegible per màquines del qual ja depenen els scripts i els agents d'IA.
Aquesta és la nota de versió per a la 0.2.0, escrita de la manera com seguim una versió internament: què s'ha publicat, què ha canviat internament, com s'ha verificat abans d'arribar a un índex de paquets, què no fa deliberadament encara, i com actualitzar. Si voleu la història de la primera execució, la publicació de llançament de la 0.1.0 i la guia d'inici ràpid de la CLI són lectures més curtes.
La versió d'un cop d'ull
Dos canals publiquen la mateixa comanda. Trieu-ne un i, després, confirmeu que respon amb la seva versió:
$ brew install bex-co/tap/bea # macOS i Linuxbrew
$ uv tool install beancount-io # a qualsevol lloc amb uv i Python 3.12 o més recent
$ bea --version
bea 0.2.0cli-v0.2.02026-09-12beancount 3.2.3 beanquery 0.2.0beangulp 0.2.0 beanprice 2.1.03.12 3.14La targeta de versió de la 0.2.0: l'etiqueta i la data de publicació, les versions de Beancount i Beanquery que fixa el motor gestionat, les dues funcions opcionals del motor i les versions de Python amb què s'ha instal·lat i provat la versió.
| Camp | Valor |
|---|---|
| Versió | 0.2.0, etiqueta cli-v0.2.0, publicada a PyPI i al tap de Homebrew bex-co/homebrew-tap el 12-09-2026 |
| Versió anterior | 0.1.0, etiquetada el 09-09-2026, tres dies abans |
| Conjunt de canvis | 27 commits que afecten la CLI, 119 fitxers modificats, aproximadament 12.300 línies afegides i 2.100 eliminades |
| Pins del motor | Beancount 3.2.3 i Beanquery 0.2.0 al motor base; Beangulp 0.2.0 i Beanprice 2.1.0 com a funcions opcionals |
| Titular | Totes les eines natives de Beancount sota un únic prefix, servides per un motor gestionat; l'envelop JSON i el contracte de codis de sortida de la 0.1.0 no canvien |
Què ha canviat internament: el motor gestionat
A la 0.1.0, bea importava Beancount al seu propi procés, com faria qualsevol eina Python. Això funcionava, però feia que el gràfic de dependències de la CLI fos el gràfic de dependències de Beancount, i deixava "instal·la Beancount primer" com un pas no escrit a cada guia.
La 0.2.0 traça una línia al mig del programa. El frontend de bea, la part que gestiona les comandes, les opcions i la representació, mai no carrega Beancount, Beanquery ni el codi de generació d'informes de Fava inclòs. El treball amb el llibre de comptes local s'executa en un motor gestionat: un entorn Python separat que bea aprovisiona a partir d'un fitxer de bloqueig amb hash fixat i llança com a intèrpret fill. El frontend envia una sol·licitud JSON a través d'aquesta frontera i representa el que torna. No instal·leu Beancount, no poseu les eines bean-* al PATH ni penseu en quin Python han trobat.
Com arriba el motor depèn del canal:
- Homebrew crea els entorns del frontend i del motor durant la instal·lació. Les comandes locals utilitzen el motor local del keg sense cap descàrrega addicional.
- PyPI (
uv tool installo pipx) l'aprovisiona en el primer ús. La primera comanda local que necessita el motor descarrega la combinació fixada, cosa que requereix accés a la xarxa iuval PATH una vegada. Les comandes posteriors el reutilitzen sense connexió des de~/.local/share/bea/engine/<version>, o sotaXDG_DATA_HOMEsi ho configureu.
D'aquest disseny se'n desprenen tres propietats, i cadascuna elimina un tiquet de suport que ja hem vist:
- Les actualitzacions es mantenen aparellades.
bea upgradepassa l'actualització al gestor de paquets que va instal·lar aquesta còpia i, després, reconstruïx el motor corresponent, de manera que un frontend i un motor mai no poden divergir a versions diferents. - Un motor trencat es repara sol. Si un aprovisionament falla a mitges, l'entorn gestionat es descarta i es reconstrueix en el següent intent amb èxit. Els binaris
bean-checkperduts en altres llocs del PATH s'ignoren en lloc de recollir-se per accident. - Les peces opcionals pesades continuen sent opcionals. El marc de treball d'importació de Beangulp necessita la biblioteca del sistema
libmagic, i Beanprice incorpora dependències de recuperació de cotitzacions. Cap d'aquestes dues no és al motor base. Les activeu explícitament, només dins del motor.
$ bea engine status
$ bea engine enable beangulp # ajudes d'importació; necessita la biblioteca del sistema libmagic
$ bea engine enable beanprice # recuperació de cotitzacions de bean-pricebea engine status informa si el motor està aprovisionat i quines funcions opcionals estan activades, i no necessita xarxa per dir-ho. Si un aprovisionament de primer ús falla, arregleu la xarxa o uv i torneu a executar qualsevol comanda local com ara bea check. No feu pip install beancount al seu costat: el frontend no l'utilitzarà.
Totes les eines natives, un sol prefix
El motor és el mecanisme. El canvi visible per a l'usuari és la paritat: tots els executables que el projecte upstream de Beancount publica ara tenen una contrapartida bea, amb els mateixos arguments enviats i la mateixa sortida conservada.
$ bea check # bean-check, més l'envelop --json de bea
$ bea format main.bean -o clean.bean # bean-format: stdout per defecte, -i reescriu
$ bea query "SELECT account, sum(position) GROUP BY account"
$ bea doctor context main.bean 2026-01-02 # totes les onze operacions de bean-doctor
$ bea example --seed 1 -o example.beancount # bean-example
$ bea treeify < balances.txt # treeify
$ bea ingest identify --config ingest.py inbox # Beangulp, després de l'activació del motor
$ bea price -e USD:yahoo/AAPL # bean-price, després de l'activació del motorbean-checkbea checkbean-formatbea formatbean-querybea querybean-doctorbea doctorbean-examplebea exampletreeifybea treeifybeangulpbea ingest bea engine enable beangulpbean-pricebea price bea engine enable beanpriceEl mapa de paritat: els sis executables natius de Beancount per sobre de la línia discontínua funcionen immediatament; els dos que hi ha a sota s'envien a Beangulp i Beanprice un cop activeu aquesta funció al motor.
Alguns d'aquests mereixen més que una fila en una taula.
bea check és bean-check amb l'envelop JSON de bea superposat: la mateixa validació, els mateixos missatges d'error i, amb --json, els mateixos camps valid i errors que els scripts ja analitzen.
bea format ha canviat de comportament, i és l'únic canvi d'aquesta versió que pot sorprendre un script. A la 0.1.0, bea format PATH reescrivia el fitxer. Ara imprimeix el text formatat a stdout i deixa el fitxer tal com està. --in-place (-i) és el que reescriu, --output FILE (-o) escriu en un altre lloc, --check és la porta de CI que surt amb l'1 quan els fitxers necessiten format, i --dry-run llista el que canviaria. Això segueix bean-format, el comportament per defecte del qual és el segur: una comanda que llegeix un camí i el reescriu silenciosament no es pot provar primer. El format és una transformació de text, no una anàlisi, de manera que ja no rebutja un fitxer amb un error de sintaxi; alinea el que reconeix i deixa la resta. Executeu bea check per a la validesa.
bea query ha crescut tota la superfície nativa. Accepta BQL com a argument, des de stdin o al shell interactiu, que ara és el shell de Beanquery upstream llançat com a procés fill amb les seves comandes .format, .output, .run i .set intactes. --format selecciona la representació text, csv o beancount, --numberify separa els imports en una columna per moneda, -o escriu en un fitxer i --source URI passa una font nativa de Beanquery directament.
bea doctor exposa totes les onze operacions de bean-doctor: lex, parse, roundtrip, directories, list-options, print-options, context, linked, region, missing-open i display-context. Si alguna vegada heu depurat un problema de registre amb bean-doctor context, és la mateixa eina a la mateixa adreça.
bea example i bea treeify són el generador natiu i el representador d'arbres natiu, enviats tal qual.
bea ingest i bea price s'envien a les comandes identify, extract i archive de Beangulp i a bean-price, respectivament, després de bea engine enable. La via CSV sense Python, bea import --csv, no necessita cap d'aquestes dues i no canvia.
Una regla uneix les comandes enviades: doctor, example, treeify, price i ingest passen els seus arguments a upstream sense canvis i mantenen la sortida i l'estat de sortida d'upstream. Això també vol dir que accepten el llibre de comptes com a argument posicional propi, com a bea doctor lex main.bean, en lloc de fer-ho a través de --file global. L'envelop i les categories de codis de sortida que hi ha a continuació descriuen les comandes pròpies de bea.
El contracte en què els scripts poden continuar confiant
Res de la superfície llegible per màquines no s'ha mogut. El --json global continua posant un envelop a stdout amb bea, target, data i truncated, més limit a les llistes limitades i page a les llistes allotjades paginades. Els imports són cadenes decimals, mai nombres de coma flotant, i les dates són ISO YYYY-MM-DD. --json implica --no-input; també ho fan un stdin que no és un terminal o una variable CI vertadera, de manera que una tasca sense supervisió mai no espera un humà. --strict rebutja respostes parcials fins i tot en un terminal, i el --allow-errors de cada comanda de lectura hi torna a optar.
Una fallada no escriu res a stdout i exactament un objecte a stderr:
{
"error": {
"category": "validation",
"message": "Ledger has 3 error(s). Pass --allow-errors to report anyway.",
"exit_code": 1,
"details": ["main.bean:1: Transaction does not balance: (2.50 USD)"]
}
}Els cinc codis de sortida i la cadena category que cadascun porta a l'objecte d'error JSON. Un script es ramifica amb el número; un humà llegeix la categoria.
| Codi | Categoria | Significat |
|---|---|---|
| 0 | cap | Èxit, incloent-hi previsualitzacions i salts de duplicats intencionats |
| 1 | validation | Error de llibre de comptes o de validació, i el calaix de sastre per a qualsevol altra fallada en temps d'execució |
| 2 | usage | Arguments incorrectes, un objectiu o extra que falta, o entrada necessària sota --no-input |
| 3 | auth | Error d'autenticació o de permisos, incloent-hi una destinació de només lectura |
| 4 | conflict | Un canvi concurrent, una importació que necessita revisió de duplicats o una escriptura amb un resultat desconegut |
Dos detalls són importants per a qualsevol que torni a intentar després d'una fallada. Un codi de sortida diferent de zero no vol dir universalment que no hagi canviat res: add transactions --partial pot escriure les files acceptades, format -i sobre diversos fitxers pot reescriure alguns abans de fallar en un, i cloud ledger create --clone pot crear el llibre de comptes abans que falli la clonació. Llegiu error.result abans de tornar a intentar una mutació. I les comandes allotjades assignen l'estat HTTP del servidor a la mateixa taula, conservant el missatge propi del servidor: 401 i 403 surten amb 3, 400 amb 2, 409 amb 4, i qualsevol altra cosa, incloent-hi la limitació de velocitat, amb 1. Una escriptura el resultat de la qual la CLI no pot saber, com un temps d'espera a mitja eliminació, surt amb 4 i ho diu en lloc d'endevinar.
La guia d'automatització recorre un pipeline jq a través d'aquest envelop de cap a cap.
Correccions que van venir de passada
Una versió de paritat també és una oportunitat per tancar els defectes que una primera versió fa aflorar. Aquests van arribar entre les dues etiquetes, cadascun amb una prova de regressió:
- Els nombres s'escriuen com a text de punt fix, mai en notació científica, incloent-hi els saldos d'obertura que
bea initrepresenta. Un llibre de comptes que diu1E+3és tècnicament vàlid i pràcticament il·legible. - Els lots de cost sobreviuen a la serialització JSON amb les seves dates i etiquetes intactes, i les etiquetes de lot s'escapen correctament quan s'escriu una transacció.
- Els apunts amb zero explícit són imports reals durant la importació, en lloc de llegir-se com "omès, equilibra'm si us plau".
- Les importacions CSV passen per un únic lector estricte. El descobriment de capçaleres solia eliminar els noms de columna mentre que l'extracció conservava les claus en brut, de manera que una capçalera amb espais que la documentació prometia acceptar fallava com a columna que faltava. Ara els noms s'eliminen una vegada, una columna assignada ha d'aparèixer exactament una vegada, i una cometa sense tancar falla amb el seu número de línia abans que s'escrigui res.
- BQL carrega el camí exacte del llibre de comptes en lloc d'una cadena de connexió analitzada com a URL, de manera que els camins inusuals es resolen de la mateixa manera que la resta de la CLI.
bea balance <terme>totalitza només el que mostra. Un pare retingut ja no informa dels totals de germans exclosos, una tinença no cotitzada no relacionada ja no fa fallar una selecció USD, i l'envelop informa del filtre que s'ha aplicat. Un patró--accountmal format en informes surt amb 2 com l'error d'ús que és.- A stderr en mode JSON sempre hi ha un objecte, fins i tot quan els avisos tolerats precedeixen la fallada.
- Les credencials allotjades fallen d'hora i de manera coherent: un
BEA_TOKENque conté espais es rebutja abans de cap sol·licitud, una credencial revocada es informa de la mateixa manera percloud statusi per les comandes de llibre de comptes, iowner/namees valida abans d'un missatge de confirmació o d'una crida autenticada.cloud logoutdeixaBEA_TOKENtal com està, icloud ledger list --jsonfa ressò de la pàgina que realment ha servit. - La fórmula de Homebrew fixa l'URL exacte de l'artefacte de PyPI, de manera que una instal·lació des del tap i una instal·lació des de PyPI són demostrablement els mateixos bytes.
Com s'ha verificat abans que ho veiéssiu
Una versió és una afirmació, i el pipeline n'és l'evidència. Una etiqueta cli-v0.2.0 ha de designar un commit a main la versió del pyproject.toml del qual coincideixi exactament; el flux de treball rebutja qualsevol altra cosa, incloent-hi sufixos de prerelease. A partir d'aquí:
- La suite de comprovacions completa s'executa primer.
make check-allcobreix lint, format, mypy estricte, detecció de codi mort, la comprovació de desviació de la referència generada i la suite de proves. El pull request de la versió registra 635 proves que passen. - El fitxer de bloqueig del motor s'exporta i es fixa amb hash, i la distribució de font i la roda es construeixen una vegada. Cada pas posterior prova aquests artefactes exactes, no una reconstrucció.
- Instal·lacions netes en tres sistemes operatius i dos Pythons. La roda s'instal·la amb
uv tooli la sdist ambpipa Linux, macOS i Windows, amb Python 3.12 i 3.14, incloent-hi l'extra d'IA opcional. Una tasca de Homebrew instal·la la sdist a través d'un tap temporal a macOS i Linux. - La publicació és seqüencial i sense testimonis. PyPI rep els artefactes a través de publicació de confiança, de manera que no existeix cap testimoni API de llarga durada que es pugui filtrar; el Release de GitHub es crea amb atestacions de publicació adjuntes; i
Formula/bea.rbes fa push al tap públic amb l'URL i el hash de la sdist que PyPI realment ha servit. - Les proves de fum posteriors a la publicació s'instal·len des dels índexs reals. Tasques separades instal·len la versió fixada des de PyPI i des del tap públic i executen les mateixes proves de fum de client contra l'executable instal·lat. Una fallada allà no reverteix res, però sí que vol dir que la versió necessita atenció abans que se n'informi ningú.
Aquesta publicació s'escriu a l'altra banda del pas cinc.
Actualització des de la 0.1.0
Executeu l'actualització a través del gestor que va instal·lar la vostra còpia, o deixeu que bea ho faci:
$ bea upgrade --check # informa de les versions instal·lada i més recent i de la comanda que s'executaria
$ bea upgrade # brew upgrade bea, uv tool upgrade beancount-io, o pipx upgrade beancount-ioDesprés que el gestor acabi, bea upgrade refresca el motor gestionat perquè els dos es mantinguin aparellats. Després comproveu tres coses:
- Qualsevol script que executava
bea format PATHper reescriure un fitxer ara necessitabea format -i PATH. El comportament per defecte anterior no es podia previsualitzar, i el nou sí. - Qualsevol script que depenia de
formatper detectar un error de sintaxi hauria de cridarbea checkper a això, perquè el format ja no analitza. - Les instal·lacions de PyPI necessiten xarxa i
uvuna vegada per a la primera comanda local després de l'actualització, perquè el motor es pugui aprovisionar. Les instal·lacions de Homebrew no necessiten res.
Tot el que els vostres scripts ja analitzen —les claus de l'envelop, les cadenes decimals i els codis de sortida— no canvia. El camp bea de l'envelop ara llegeix 0.2.0.
Què no fa aquesta versió
- La segmentació allotjada no està implementada. No hi ha cap indicador
--ledger; les comandes locals llegeixen fitxers locals i mai no en pengen cap implícitament. Els llibres de comptes allotjats es gestionen sotabea cloudi es treballa amb ells com a clons de git. bea askencara necessita l'extraaski les credencials de Beancount.io, i no admet--json. La instal·lació per defecte no porta cap dependència d'IA.- Beangulp i Beanprice són opcionals, i Beangulp necessita la biblioteca del sistema
libmagic.bea import --csvcobreix les exportacions bancàries sense cap d'aquestes dues. - Les comandes natives enviades no emeten l'envelop. Si necessiteu sortida estructurada d'una operació de doctor, aquesta és una sol·licitud que ens agradaria escoltar.
Des de l'etiqueta, main ja ha recollit la primera ronda de control de qualitat de la 0.2.0, i viatjarà amb la propera versió: bea format llegeix stdin com a filtre i el seu mode -o FILE respon amb un envelop que nomena el que ha escrit; --json check rebutja indicadors només de bean-check, i --json es rebutja directament a doctor, example i treeify perquè un script no pugui confondre text natiu amb un envelop; --json query -o FILE escriu l'envelop al fitxer de manera atòmica, amb --numberify aplicat també al JSON; bea engine status nomena quin nivell de motor serveix; una consulta BQL que comença amb un comentari s'executa; l'ajuda nativa de pas a través --help funciona abans que el motor estigui aprovisionat; i el .output del shell de consultes restaura el flux original després d'una redirecció fallida.
On anar a continuació
- Inici ràpid de la CLI: instal·lació, primer llibre de comptes, primera compra, primera comprovació de balanç.
- El vostre primer mes amb bea: des de
initfins a un informe de tancament de mes conciliat. - Importeu exportacions bancàries: la via CSV sense Python, fitxers de regles i importadors Python.
- Automatitzeu la comptabilitat amb bea: resolució del llibre de comptes, lectura de l'envelop, ramificació amb codis de sortida, programació.
- Referència de la CLI de Beancount: cada comanda, opció, variable d'entorn i codi de sortida, comprovada contra la referència generada de la CLI.
- Doneu un llibre de comptes al vostre agent d'IA: el recorregut agente-primer del llançament de la 0.1.0.
- Registre de canvis: cada versió, de la més nova a la més antiga.
Mantingueu els vostres llibres com a codi
Una cadena d'eines que podeu instal·lar en una línia és una cadena d'eines que podeu donar a qualsevol: un cofundador, un comptable, un executor de CI, un agent d'IA. Beancount.io ofereix comptabilitat en text pla que es manté transparent, versionada i reproduïble, amb bea com la comanda que manté un llibre de comptes local honest i el servei allotjat com el lloc on el vostre equip, el vostre telèfon i el vostre assistent es troben amb els mateixos llibres. Instal·leu bea i feu la vostra primera comprovació, i si la versió fa alguna cosa que no esperàveu, el repositori de GitHub és on volem sentir-ho.





