Если вы когда-нибудь передавали коллеге, новому ноутбуку или ночному 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.0cli-v0.2.02026-09-12beancount 3.2.3 beanquery 0.2.0beangulp 0.2.0 beanprice 2.1.03.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, если вы его задали.
Из этого дизайна следуют три свойства, и каждое устраняет тикет поддержки, который мы уже видели:
- Обновления остаются парными.
bea upgradeпередаёт обновление тому менеджеру пакетов, который установил эту копию, затем пересобирает соответствующий движок, поэтому фронтенд и движок никогда не могут разойтись по версиям. - Сломанный движок сам себя лечит. Если подготовка не удалась на середине, управляемое окружение отбрасывается и пересобирается при следующей успешной попытке. Посторонние бинарники
bean-checkв других местах PATH игнорируются, а не подхватываются случайно. - Тяжёлые опциональные части остаются опциональными. Фреймворк импорта Beangulp требует системную библиотеку
libmagic, а Beanprice подтягивает зависимости для получения котировок. Ни то, ни другое не входит в базовый движок. Вы включаете их явно, только в движок.
$ bea engine status
$ bea engine enable beangulp # помощники для импорта; требуется системная библиотека libmagic
$ bea engine enable beanprice # получение котировок через bean-pricebea 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 enablebean-checkbea checkbean-formatbea formatbean-querybea querybean-doctorbea doctorbean-examplebea exampletreeifybea treeifybeangulpbea ingest bea engine enable beangulpbean-pricebea 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)"]
}
}Пять кодов выхода и строка category, которую каждый из них несёт в JSON-объекте ошибки. Скрипт ветвится по числу; человек читает категорию.
| Код | Категория | Значение |
|---|---|---|
| 0 | нет | Успех, включая предпросмотры и намеренные пропуски дубликатов |
| 1 | validation | Ошибка книги или проверки, а также универсальная категория для любой другой ошибки выполнения |
| 2 | usage | Неверные аргументы, отсутствующая цель или лишнее, или требуемый ввод при --no-input |
| 3 | auth | Ошибка аутентификации или прав доступа, включая место назначения только для чтения |
| 4 | conflict | Конкурентное изменение, импорт, требующий проверки дубликатов, или запись с неизвестным результатом |
Две детали важны для тех, кто повторяет попытки при сбое. Ненулевой код выхода не всегда означает, что ничего не изменилось: 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 совпадает точно; рабочий процесс отказывает всему остальному, включая суффиксы пререлизов. Отсюда:
- Сначала запускается полный набор проверок.
make check-allохватывает линт, форматирование, строгий mypy, обнаружение мёртвого кода, проверку дрейфа сгенерированной документации и набор тестов. Пулл-реквест релиза фиксирует 635 прошедших тестов. - Экспортируется lock-файл движка с хэш-привязкой, а исходный дистрибутив и wheel собираются один раз. Каждый последующий шаг тестирует именно эти артефакты, а не пересборку.
- Чистые установки на трёх операционных системах и двух Python. Wheel устанавливается через
uv tool, а sdist черезpipна Linux, macOS и Windows, на Python 3.12 и 3.14, включая опциональный AI-доп. Работа Homebrew устанавливает sdist через временный tap на macOS и Linux. - Публикация последовательна и без токенов. PyPI получает артефакты через доверенную публикацию, поэтому не существует долгоживущего API-токена, который мог бы утечь; GitHub Release создаётся с прикреплёнными аттестациями публикации; а
Formula/bea.rbотправляется в публичный tap с URL sdist и хэшем, которые фактически отдал PyPI. - Постпубликационные смоук-тесты устанавливают из реальных индексов. Отдельные работы устанавливают привязанную версию из 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 оболочки запросов восстанавливает исходный поток после неудачного перенаправления.
Куда двигаться дальше
- Краткое руководство по CLI: установка, первая книга, первая покупка, первая проверка остатков.
- Ваш первый месяц с bea: от
initдо сверенного отчёта за месяц. - Импорт банковских выписок: путь CSV без Python, файлы правил и Python-импортёры.
- Автоматизация бухгалтерии с bea: сверка книги, чтение конверта, ветвление по кодам выхода, планирование.
- Справочник Beancount CLI: каждая команда, опция, переменная окружения и код выхода, сверенные со сгенерированной документацией CLI.
- Дайте вашему ИИ-агенту книгу: пошаговое руководство для агентов из запуска 0.1.0.
- Журнал изменений: каждый релиз, новейшие первыми.
Держите свои книги как код
Инструментарий, который можно установить одной строкой, — это инструментарий, который можно передать любому: сооснователю, бухгалтеру, CI-раннеру, ИИ-агенту. Beancount.io предоставляет бухгалтерию в открытом тексте, которая остаётся прозрачной, версионируемой и воспроизводимой, с bea как командой, которая держит локальную книгу честной, и хостинговым сервисом как местом, где ваша команда, ваш телефон и ваш помощник встречаются с одними и теми же книгами. Установите bea и запустите первую проверку, а если релиз делает что-то, чего вы не ожидали, репозиторий GitHub — это то место, где мы хотим об этом услышать.





