Перейти к основному содержимому

bea 0.2.0: одна установка — весь инструментарий Beancount

Опубликовано 16 мин чтенияMike ThriftMike Thrift
bea 0.2.0: одна установка — весь инструментарий Beancount
Содержание страницы

Если вы когда-нибудь передавали коллеге, новому ноутбуку или ночному cron-заданию рабочую настройку Beancount, вы знаете, что бухгалтерия никогда не была сложной частью. Сложной частью был инструментарий: подходящий Python, bean-check и bean-query в PATH, библиотека для отчётов, установленная ради одного балансового отчёта, и форматтер, который переписывает ваши файлы в тот момент, когда вы задаёте ему вопрос. bea 0.2.0, выпущенный 12 сентября 2026 года, заменяет этот список одной установкой. Команда bea теперь включает полный нативный инструментарий Beancount, запускает его внутри управляемого движка, который она сама подготавливает, и сохраняет машиночитаемый контракт, на который уже полагаются скрипты и ИИ-агенты.

Это заметка о релизе 0.2.0, написанная так, как мы отслеживаем релиз внутри команды: что вышло, что изменилось внутри, как это было проверено до публикации в индекс пакетов, что оно сознательно пока не делает и как обновиться. Если вам нужна история первого запуска, то анонс 0.1.0 и краткое руководство по CLI — более короткие материалы.

Релиз в двух словах

Два канала публикуют одну и ту же команду. Выберите один, затем убедитесь, что он отвечает своей версией:

$ brew install bex-co/tap/bea        # macOS и Linuxbrew
$ uv tool install beancount-io       # где угодно с uv и Python 3.12 или новее
$ bea --version
bea 0.2.0
bea 0.2.0
cli-v0.2.02026-09-12
движок
beancount 3.2.3 beanquery 0.2.0
опционально
beangulp 0.2.0 beanprice 2.1.0
python
3.12 3.14

Карточка релиза 0.2.0: тег и дата публикации, версии Beancount и Beanquery, к которым привязан управляемый движок, две опциональные функции движка и версии Python, на которых релиз был установлен и протестирован.

ПолеЗначение
Версия0.2.0, тег cli-v0.2.0, опубликована в PyPI и Homebrew tap bex-co/homebrew-tap 2026-09-12
Предыдущий релиз0.1.0, тегирован 2026-09-09, тремя днями ранее
Набор изменений27 коммитов, затрагивающих CLI, 119 изменённых файлов, примерно 12 300 добавленных строк и 2 100 удалённых
Привязки движкаBeancount 3.2.3 и Beanquery 0.2.0 в базовом движке; Beangulp 0.2.0 и Beanprice 2.1.0 как опциональные функции
ГлавноеКаждый нативный инструмент Beancount под одним префиксом, обслуживаемый управляемым движком; JSON-конверт и контракт кодов выхода из 0.1.0 не изменены

Что изменилось внутри: управляемый движок

В 0.1.0 bea импортировала Beancount в свой собственный процесс, как это делает любой Python-инструмент. Это работало, но делало граф зависимостей CLI графом зависимостей Beancount и оставляло «сначала установите Beancount» неявным шагом в каждом руководстве.

0.2.0 проводит линию через середину программы. Фронтенд bea — часть, которая владеет командами, опциями и отрисовкой, — никогда не загружает Beancount, Beanquery или встроенный код отчётности Fava. Локальная работа с книгами выполняется в управляемом движке: отдельном Python-окружении, которое bea подготавливает из lock-файла с хэш-привязкой и запускает как дочерний интерпретатор. Фронтенд отправляет JSON-запрос через эту границу и отрисовывает то, что возвращается. Вам не нужно устанавливать Beancount, добавлять инструменты bean-* в PATH или думать о том, какой Python они найдут.

Как движок появляется, зависит от канала:

  • Homebrew создаёт окружения фронтенда и движка во время установки. Локальные команды используют keg-локальный движок без дополнительных загрузок.
  • PyPI (uv tool install или pipx) подготавливает движок при первом использовании. Первая локальная команда, которой нужен движок, загружает привязанную комбинацию, что требует доступа к сети и наличия uv в PATH один раз. Последующие команды используют его офлайн из ~/.local/share/bea/engine/<version> или из XDG_DATA_HOME, если вы его задали.

Из этого дизайна следуют три свойства, и каждое устраняет тикет поддержки, который мы уже видели:

  1. Обновления остаются парными. bea upgrade передаёт обновление тому менеджеру пакетов, который установил эту копию, затем пересобирает соответствующий движок, поэтому фронтенд и движок никогда не могут разойтись по версиям.
  2. Сломанный движок сам себя лечит. Если подготовка не удалась на середине, управляемое окружение отбрасывается и пересобирается при следующей успешной попытке. Посторонние бинарники bean-check в других местах PATH игнорируются, а не подхватываются случайно.
  3. Тяжёлые опциональные части остаются опциональными. Фреймворк импорта Beangulp требует системную библиотеку libmagic, а Beanprice подтягивает зависимости для получения котировок. Ни то, ни другое не входит в базовый движок. Вы включаете их явно, только в движок.
$ bea engine status
$ bea engine enable beangulp     # помощники для импорта; требуется системная библиотека libmagic
$ bea engine enable beanprice    # получение котировок через bean-price

bea engine status сообщает, подготовлен ли движок и какие опциональные функции включены, и для этого не нужна сеть. Если подготовка при первом использовании не удалась, исправьте сеть или uv и повторите любую локальную команду, например bea check. Не устанавливайте pip install beancount рядом: фронтенд его не будет использовать.

Каждый нативный инструмент, один префикс

Движок — это механизм. Изменение, видимое пользователю, — паритет: каждый исполняемый файл, который поставляет вышестоящий проект Beancount, теперь имеет аналог bea с теми же аргументами и тем же выводом.

$ bea check                                    # bean-check, плюс JSON-конверт bea
$ bea format main.bean -o clean.bean           # bean-format: по умолчанию в stdout, -i перезаписывает
$ bea query "SELECT account, sum(position) GROUP BY account"
$ bea doctor context main.bean 2026-01-02      # все одиннадцать операций bean-doctor
$ bea example --seed 1 -o example.beancount    # bean-example
$ bea treeify < balances.txt                   # treeify
$ bea ingest identify --config ingest.py inbox # Beangulp, после engine enable
$ bea price -e USD:yahoo/AAPL                  # bean-price, после engine enable
bean-check
bea check
bean-format
bea format
bean-query
bea query
bean-doctor
bea doctor
bean-example
bea example
treeify
bea treeify
beangulp
bea ingest bea engine enable beangulp
bean-price
bea price bea engine enable beanprice

Карта паритета: шесть нативных исполняемых файлов Beancount над пунктирной линией работают из коробки; два под ней передаются в Beangulp и Beanprice после включения этой функции в движке.

Некоторые из них заслуживают больше, чем строки в таблице.

bea check — это bean-check с добавленным поверх JSON-конвертом bea: та же проверка, те же сообщения об ошибках, а в режиме --json — те же поля valid и errors, которые скрипты уже разбирают.

bea format изменил поведение, и это единственное изменение в этом релизе, которое может удивить скрипт. В 0.1.0 bea format PATH перезаписывал файл. Теперь он выводит отформатированный текст в stdout и оставляет файл нетронутым. --in-place (-i) — это то, что перезаписывает, --output FILE (-o) записывает в другое место, --check — это шлюз для CI, который завершается с кодом 1, когда файлы требуют форматирования, а --dry-run перечисляет, что бы изменилось. Это следует за bean-format, чей стандартный режим — безопасный: команду, которая читает путь и молча переписывает его, нельзя сначала попробовать. Форматирование — это текстовая трансформация, а не разбор, поэтому оно больше не отказывает файлу с синтаксической ошибкой; оно выравнивает то, что распознаёт, и оставляет остальное. Для проверки корректности запустите bea check.

bea query обрёл всю нативную поверхность. Он принимает BQL как аргумент, из stdin или в интерактивной оболочке, которая теперь является вышестоящей оболочкой Beanquery, запускаемой как дочерний процесс с её командами .format, .output, .run и .set. --format выбирает отрисовку text, csv или beancount, --numberify разбивает суммы на одну колонку на валюту, -o записывает в файл, а --source URI передаёт нативный источник Beanquery напрямую.

bea doctor открывает все одиннадцать операций bean-doctor: lex, parse, roundtrip, directories, list-options, print-options, context, linked, region, missing-open и display-context. Если вы когда-нибудь отлаживали проблему проводки с помощью bean-doctor context, это тот же инструмент по тому же адресу.

bea example и bea treeify — это нативный генератор и нативный рендерер деревьев, переданные как есть.

bea ingest и bea price передаются в identify, extract и archive Beangulp и в bean-price соответственно после bea engine enable. Путь CSV без Python, bea import --csv, не требует ни того, ни другого и не изменён.

Одно правило связывает переданные команды: doctor, example, treeify, price и ingest передают свои аргументы вышестоящим инструментам без изменений и сохраняют их вывод и статус выхода. Это также означает, что они принимают книгу как собственный позиционный аргумент, как в bea doctor lex main.bean, а не через глобальный --file. Конверт и категории кодов выхода ниже описывают собственные команды bea.

Контракт, которому скрипты могут доверять

Ничто в машиночитаемой поверхности не изменилось. Глобальный --json по-прежнему помещает один конверт в stdout с полями bea, target, data и truncated, плюс limit для ограниченных списков и page для постраничных хостинговых списков. Суммы — десятичные строки, никогда не числа с плавающей точкой, а даты — ISO YYYY-MM-DD. --json подразумевает --no-input; то же делают не-терминальный stdin или истинная переменная CI, поэтому незанятая задача никогда не ждёт человека. --strict отказывает в частичных ответах даже в терминале, а флаг --allow-errors каждой команды чтения возвращает возможность выбора.

При сбое в stdout ничего не пишется, а в 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)"]
  }
}
0
ok
1
validation
2
usage
3
auth
4
conflict

Пять кодов выхода и строка category, которую каждый из них несёт в JSON-объекте ошибки. Скрипт ветвится по числу; человек читает категорию.

КодКатегорияЗначение
0нетУспех, включая предпросмотры и намеренные пропуски дубликатов
1validationОшибка книги или проверки, а также универсальная категория для любой другой ошибки выполнения
2usageНеверные аргументы, отсутствующая цель или лишнее, или требуемый ввод при --no-input
3authОшибка аутентификации или прав доступа, включая место назначения только для чтения
4conflictКонкурентное изменение, импорт, требующий проверки дубликатов, или запись с неизвестным результатом

Две детали важны для тех, кто повторяет попытки при сбое. Ненулевой код выхода не всегда означает, что ничего не изменилось: add transactions --partial может записать принятые строки, format -i по нескольким файлам может переписать некоторые перед сбоем на одном, а cloud ledger create --clone может создать книгу до того, как клон потерпит неудачу. Прочитайте error.result перед повторной мутирующей операцией. Хостинговые команды сопоставляют HTTP-статус сервера с той же таблицей, сохраняя собственное сообщение сервера: 401 и 403 выходят с кодом 3, 400 — с 2, 409 — с 4, а всё остальное, включая ограничение частоты запросов, — с 1. Запись, исход которой CLI не может знать, например таймаут во время удаления, выходит с кодом 4 и сообщает об этом, а не гадает.

Руководство по автоматизации проводит конвейер jq через этот конверт от начала до конца.

Исправления, которые поехали вместе

Релиз с паритетом — это также возможность закрыть дефекты, которые выявляет первый релиз. Они попали между двумя тегами, каждый с регрессионным тестом:

  • Числа записываются как текст с фиксированной точкой, никогда в научной нотации, включая начальные остатки, которые отрисовывает bea init. Книга, в которой написано 1E+3, формально корректна, но практически нечитаема.
  • Партии затрат (cost lots) переживают JSON-сериализацию с сохранением дат и меток, а метки партий корректно экранируются при записи транзакции.
  • Явные нулевые проводки — реальные суммы при импорте, а не читаются как «опущено, пожалуйста, сведите меня».
  • CSV-импорты проходят через один строгий читатель. Обнаружение заголовков раньше удаляло имена колонок, тогда как извлечение сохраняло сырые ключи, поэтому заголовок с заполнением, который документация обещала принимать, не проходил как отсутствующая колонка. Теперь имена удаляются один раз, сопоставленная колонка должна появиться ровно один раз, а незакрытая кавычка завершается с номером строки до записи чего-либо.
  • BQL загружает точный путь к книге, а не URL-разобранную строку соединения, поэтому необычные пути разрешаются так же, как их разрешает остальная часть CLI.
  • bea balance <термин> суммирует только то, что показывает. Родительский счёт с остатком больше не сообщает суммы исключённых дочерних, несвязанная непроцентированная позиция больше не приводит к сбою выбора USD, а конверт сообщает применённый фильтр. Некорректный шаблон --account в отчётах выходит с кодом 2 как ошибка использования, которой он и является.
  • stderr в JSON-режиме всегда один объект, даже когда предупреждения, которые допускаются, предшествуют сбою.
  • Хостинговые учётные данные завершаются рано и последовательно: BEA_TOKEN, содержащий пробелы, отклоняется до любого запроса, отозванные учётные данные одинаково сообщаются cloud status и командами книги, а owner/name проверяется до запроса подтверждения или аутентифицированного вызова. cloud logout не трогает BEA_TOKEN, а cloud ledger list --json возвращает ту страницу, которую действительно обслужил.
  • Формула Homebrew привязывает точный URL артефакта PyPI, поэтому установка через tap и установка через PyPI доказуемо одни и те же байты.

Как это было проверено до того, как вы это увидели

Релиз — это утверждение, а конвейер — доказательство. Тег cli-v0.2.0 должен указывать на коммит в main, чья версия pyproject.toml совпадает точно; рабочий процесс отказывает всему остальному, включая суффиксы пререлизов. Отсюда:

  1. Сначала запускается полный набор проверок. make check-all охватывает линт, форматирование, строгий mypy, обнаружение мёртвого кода, проверку дрейфа сгенерированной документации и набор тестов. Пулл-реквест релиза фиксирует 635 прошедших тестов.
  2. Экспортируется lock-файл движка с хэш-привязкой, а исходный дистрибутив и wheel собираются один раз. Каждый последующий шаг тестирует именно эти артефакты, а не пересборку.
  3. Чистые установки на трёх операционных системах и двух Python. Wheel устанавливается через uv tool, а sdist через pip на Linux, macOS и Windows, на Python 3.12 и 3.14, включая опциональный AI-доп. Работа Homebrew устанавливает sdist через временный tap на macOS и Linux.
  4. Публикация последовательна и без токенов. PyPI получает артефакты через доверенную публикацию, поэтому не существует долгоживущего API-токена, который мог бы утечь; GitHub Release создаётся с прикреплёнными аттестациями публикации; а Formula/bea.rb отправляется в публичный tap с URL sdist и хэшем, которые фактически отдал PyPI.
  5. Постпубликационные смоук-тесты устанавливают из реальных индексов. Отдельные работы устанавливают привязанную версию из PyPI и из публичного tap и запускают те же смоук-тесты клиента против установленного исполняемого файла. Сбой там ничего не откатывает, но означает, что релизу нужно внимание до того, как о нём кому-либо сообщат.

Этот пост пишется по ту сторону шага пять.

Обновление с 0.1.0

Запустите обновление через менеджер, который установил вашу копию, или позвольте это сделать bea:

$ bea upgrade --check      # сообщает установленную и последнюю версии и команду, которая будет запущена
$ bea upgrade              # brew upgrade bea, uv tool upgrade beancount-io или pipx upgrade beancount-io

После завершения менеджера bea upgrade обновляет управляемый движок, чтобы они оставались парными. Затем проверьте три вещи:

  • Любой скрипт, запускавший bea format PATH для перезаписи файла, теперь нуждается в bea format -i PATH. Старый стандартный режим нельзя было предпросмотреть, новый можно.
  • Любой скрипт, полагавшийся на format для выявления синтаксической ошибки, должен вызывать для этого bea check, потому что форматирование больше не разбирает.
  • Установки PyPI один раз требуют сеть и uv для первой локальной команды после обновления, чтобы можно было подготовить движок. Установки Homebrew не требуют ничего.

Всё, что ваши скрипты уже разбирают, ключи конверта, десятичные строки и коды выхода, не изменилось. Поле bea в конверте теперь читается как 0.2.0.

Что этот релиз не делает

  • Хостинговая адресация не реализована. Нет флага --ledger; локальные команды читают локальные файлы и никогда не загружают их неявно. Хостинговые книги управляются через bea cloud и используются как git-клоны.
  • bea ask по-прежнему требует доп ask и учётные данные Beancount.io, и он не поддерживает --json. Стандартная установка не несёт ИИ-зависимостей.
  • Beangulp и Beanprice опциональны, и Beangulp требует системную библиотеку libmagic. bea import --csv покрывает банковские выписки без обоих.
  • Переданные нативные команды не испускают конверт. Если вам нужен структурированный вывод от операции doctor — это запрос, который мы хотели бы услышать.

После тега main уже получил первый раунд контроля качества 0.2.0, и он уедет со следующим релизом: bea format читает stdin как фильтр, а его режим -o FILE отвечает конвертом с именем того, что он записал; --json check отказывается от флагов, специфичных для bean-check, а --json начисто запрещён на doctor, example и treeify, чтобы скрипт не спутал нативный текст с конвертом; --json query -o FILE записывает конверт в файл атомарно, с --numberify, применённым и к JSON; bea engine status называет, какой уровень движка обслуживает; BQL-запрос, начинающийся с комментария, выполняется; нативный --help для прохода работает до подготовки движка; а команда .output оболочки запросов восстанавливает исходный поток после неудачного перенаправления.

Куда двигаться дальше

Держите свои книги как код

Инструментарий, который можно установить одной строкой, — это инструментарий, который можно передать любому: сооснователю, бухгалтеру, CI-раннеру, ИИ-агенту. Beancount.io предоставляет бухгалтерию в открытом тексте, которая остаётся прозрачной, версионируемой и воспроизводимой, с bea как командой, которая держит локальную книгу честной, и хостинговым сервисом как местом, где ваша команда, ваш телефон и ваш помощник встречаются с одними и теми же книгами. Установите bea и запустите первую проверку, а если релиз делает что-то, чего вы не ожидали, репозиторий GitHub — это то место, где мы хотим об этом услышать.

Поделиться этой статьёй

Источник: https://beancount.io/ru/blog/2026/09/16/bea-0-2-0-one-install-whole-beancount-toolchain

Опубликовано: 16 сентября 2026 г.

9 мин чтения

Bitwave только что открыла исходный код «Agentic Finance»: что происходит, когда ИИ-агенты перестают пользоваться вашим бухгалтерским ПО, как человек

Bitwave открыла исходный код агентно-ориентированного бухгалтерского CLI и…

ai
accounting-software
1 мин чтения

Обновление Fava до версии 1.19: Ключевые изменения и улучшения

Последнее обновление Fava до версии 1.19 привносит значительные изменения,…

changelog
fava
7 мин чтения

Дайте вашему ИИ-агенту бухгалтерскую книгу: здесь появился бухгалтерский CLI bea

Установите CLI bea двумя командами, поручите вашему существующему ИИ-агенту…

announcements
ai
8 мин чтения

Объявите роли денежных потоков в своей книге: одна строка метаданных вместо догадок

Отчет о движении денежных средств на Beancount.io теперь считывает…

changelog
beancount
7 мин чтения

Beancount.io 3.6 Летний релиз: умный импорт, практичный ИИ и обновлённое мобильное приложение

Beancount.io 3.6 сокращает разрыв между финансовой активностью и надёжной…

changelog
beancount