본문으로 건너뛰기

bea 0.2.0: 한 번의 설치로, Beancount 도구 체인 전체를

게시됨 약 14분Mike ThriftMike Thrift
bea 0.2.0: 한 번의 설치로, Beancount 도구 체인 전체를
이 페이지에서

동료, 새 노트북 또는 야간 크론 작업에 작동하는 Beancount 설정을 넘겨준 적이 있다면, 회계가 어려운 부분이 아니었다는 것을 알 것입니다. 어려운 부분은 도구 체인이었습니다: 일치하는 Python, 경로에 있는 bean-checkbean-query, 하나의 대차대조표를 위해 가져온 보고 라이브러리, 그리고 질문을 하는 순간 파일을 다시 쓰는 포맷터. 2026년 9월 12일에 출시된 bea 0.2.0은 이 체크리스트를 한 번의 설치로 대체합니다. 이제 bea 명령은 완전한 네이티브 Beancount 도구 체인을 포함하며, 자체적으로 프로비저닝하는 관리형 엔진 내에서 실행하고, 스크립트와 AI 에이전트가 이미 의존하는 기계 판독 가능 계약을 유지합니다.

이것은 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, 2026-09-12에 PyPI 및 bex-co/homebrew-tap Homebrew 탭에 게시됨
이전 릴리스0.1.0, 2026-09-09에 태그 지정, 3일 전
변경 세트CLI에 영향을 주는 27개 커밋, 119개 파일 변경, 약 12,300줄 추가 및 2,100줄 제거
엔진 고정기본 엔진에 Beancount 3.2.3 및 Beanquery 0.2.0; Beangulp 0.2.0 및 Beanprice 2.1.0은 선택 기능
헤드라인관리형 엔진이 제공하는 하나의 접두사 아래 모든 네이티브 Beancount 도구; 0.1.0의 JSON 봉투 및 종료 코드 계약은 변경되지 않음

내부적으로 변경된 것: 관리형 엔진

0.1.0에서 bea는 다른 Python 도구처럼 자체 프로세스로 Beancount를 가져왔습니다. 작동했지만, CLI의 종속성 그래프가 Beancount의 종속성 그래프가 되었고, 모든 가이드에서 "Beancount 먼저 설치"라는 문서화되지 않은 단계를 남겼습니다.

0.2.0은 프로그램 중간에 선을 긋습니다. 명령, 옵션 및 렌더링을 소유하는 부분인 bea 프론트엔드는 Beancount, Beanquery 또는 번들된 Fava 보고 코드를 로드하지 않습니다. 로컬 원장 작업은 관리형 엔진에서 실행됩니다: bea가 해시 고정 잠금에서 프로비저닝하고 하위 인터프리터로 실행하는 별도의 Python 환경입니다. 프론트엔드는 해당 경계를 통해 JSON 요청을 보내고 돌아오는 것을 렌더링합니다. Beancount를 설치하거나 bean-* 도구를 경로에 넣거나 어떤 Python을 찾았는지 생각할 필요가 없습니다.

엔진이 도착하는 방식은 채널에 따라 다릅니다:

  • Homebrew는 설치 중에 프론트엔드 및 엔진 환경을 생성합니다. 로컬 명령은 추가 다운로드 없이 keg-로컬 엔진을 사용합니다.
  • PyPI (uv tool install 또는 pipx)는 첫 사용 시 프로비저닝합니다. 엔진이 필요한 첫 번째 로컬 명령은 고정된 조합을 다운로드하며, 네트워크 액세스와 경로에 uv가 한 번 필요합니다. 이후 명령은 ~/.local/share/bea/engine/<version> 또는 XDG_DATA_HOME을 설정한 경우 그 아래에서 오프라인으로 재사용합니다.

이 설계에서 세 가지 속성이 따르며, 각각은 이미 본 지원 티켓을 제거합니다:

  1. 업그레이드는 쌍으로 유지됩니다. bea upgrade는 이 사본을 설치한 패키지 관리자에게 업데이트를 넘겨준 다음 일치하는 엔진을 다시 빌드하므로 프론트엔드와 엔진이 다른 버전으로 분기될 수 없습니다.
  2. 깨진 엔진은 자가 치유됩니다. 프로비저닝이 중간에 실패하면 관리형 환경은 폐기되고 다음 성공적인 시도에서 다시 빌드됩니다. 경로의 다른 곳에 있는 잘못된 bean-check 바이너리는 우연히 선택되지 않고 무시됩니다.
  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, bea의 --json 봉투 포함
$ 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      # 모든 11가지 bean-doctor 작업
$ bea example --seed 1 -o example.beancount    # bean-example
$ bea treeify < balances.txt                   # treeify
$ bea ingest identify --config ingest.py inbox # Beangulp, 엔진 활성화 후
$ bea price -e USD:yahoo/AAPL                  # bean-price, 엔진 활성화 후
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

패리티 맵: 점선 위의 6개 네이티브 Beancount 실행 파일은 기본으로 작동합니다; 아래의 2개는 엔진에서 해당 기능을 활성화하면 Beangulp 및 Beanprice로 전달됩니다.

이 중 몇 가지는 표의 한 행 이상의 가치가 있습니다.

bea checkbean-check 위에 bea의 JSON 봉투가 겹쳐진 것입니다: 동일한 검증, 동일한 오류 메시지, 그리고 --json 아래에서 스크립트가 이미 구문 분석하는 동일한 validerrors 필드.

bea format은 동작이 변경되었으며, 이 릴리스에서 스크립트를 놀라게 할 수 있는 유일한 변경입니다. 0.1.0에서 bea format PATH는 파일을 다시 썼습니다. 이제 형식화된 텍스트를 stdout으로 출력하고 파일은 그대로 둡니다. --in-place (-i)가 다시 쓰고, --output FILE (-o)이 다른 곳에 쓰고, --check는 파일에 형식이 필요할 때 1로 종료하는 CI 게이트이며, --dry-run은 변경될 내용을 나열합니다. 이는 기본값이 안전한 bean-format을 따릅니다: 경로를 읽고 조용히 다시 쓰는 명령은 먼저 시도해 볼 수 없습니다. 형식화는 구문 분석이 아닌 텍스트 변환이므로 더 이상 구문 오류가 있는 파일을 거부하지 않습니다; 인식하는 것을 정렬하고 나머지는 그대로 둡니다. 유효성 검사는 bea check를 실행하세요.

bea query는 전체 네이티브 표면을 갖추었습니다. BQL을 인수, stdin 또는 대화형 셸에서 받으며, 이제 업스트림 Beanquery 셸이 하위 프로세스로 실행되어 .format, .output, .run.set 명령이 그대로 유지됩니다. --formattext, csv 또는 beancount 렌더링을 선택하고, --numberify는 금액을 통화당 하나의 열로 분할하고, -o는 파일에 쓰고, --source URI는 네이티브 Beanquery 소스를 직접 전달합니다.

bea doctor는 11가지 bean-doctor 작업을 모두 노출합니다: lex, parse, roundtrip, directories, list-options, print-options, context, linked, region, missing-opendisplay-context. bean-doctor context로 예약 문제를 디버깅한 적이 있다면 같은 주소의 같은 도구입니다.

bea examplebea treeify 는 네이티브 생성기와 네이티브 트리 렌더러로, 그대로 전달됩니다.

bea ingestbea pricebea engine enable 후에 각각 Beangulp의 identify, extractarchivebean-price로 전달됩니다. Python이 필요 없는 CSV 경로인 bea import --csv는 둘 다 필요하지 않으며 변경되지 않았습니다.

전달된 명령을 묶는 한 가지 규칙이 있습니다: doctor, example, treeify, priceingest는 인수를 업스트림에 변경 없이 전달하고 업스트림의 출력과 종료 상태를 유지합니다. 즉, 전역 --file 대신 bea doctor lex main.bean에서처럼 원장을 자체 위치 인수로 사용합니다. 아래의 봉투 및 종료 코드 범주는 bea의 자체 명령을 설명합니다.

스크립트가 계속 신뢰할 수 있는 계약

기계 판독 가능 표면에서 이동한 것은 없습니다. 전역 --json은 여전히 bea, target, datatruncated가 있는 하나의 봉투를 stdout에 넣고, 제한된 목록에는 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

5가지 종료 코드와 각각이 JSON 오류 객체에 포함하는 category 문자열. 스크립트는 숫자로 분기하고, 사람은 범주를 읽습니다.

코드범주의미
0없음성공, 미리보기 및 의도적인 중복 건너뛰기 포함
1validation원장 또는 검증 오류, 기타 모든 런타임 실패의 포괄적 오류
2usage잘못된 인수, 누락된 대상 또는 추가, 또는 --no-input 아래에서 필요한 입력
3auth인증 또는 권한 실패, 읽기 전용 대상 포함
4conflict동시 변경, 중복 검토가 필요한 가져오기, 또는 결과를 알 수 없는 쓰기

실패 시 재시도하는 사람에게 중요한 두 가지 세부 사항이 있습니다. 0이 아닌 종료가 보편적으로 아무것도 변경되지 않았음을 의미하지는 않습니다: 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이라고 말하는 원장은 기술적으로 유효하지만 실질적으로 읽을 수 없습니다.
  • 비용 로트는 JSON 직렬화에서 날짜와 레이블을 그대로 유지하며, 트랜잭션이 작성될 때 로트 레이블이 올바르게 이스케이프됩니다.
  • 가져오기 중에 명시적 0 게시물은 실제 금액입니다, "생략됨, 균형을 맞춰주세요"로 읽히는 대신.
  • CSV 가져오기는 하나의 엄격한 판독기를 통과합니다. 헤더 발견은 열 이름을 제거하는 반면 추출은 원시 키를 유지하여 문서가 허용하겠다고 약속한 패딩된 헤더가 누락된 열로 실패했습니다. 이제 이름은 한 번 제거되고, 매핑된 열은 정확히 한 번 나타나야 하며, 닫히지 않은 따옴표는 아무것도 작성되기 전에 줄 번호와 함께 실패합니다.
  • BQL은 URL 구문 분석된 연결 문자열이 아닌 정확한 원장 경로를 로드하므로 특이한 경로가 CLI의 나머지 부분과 같은 방식으로 해결됩니다.
  • bea balance <용어>는 표시하는 것만 합산합니다. 유지된 부모는 더 이상 제외된 형제의 합계를 보고하지 않고, 관련 없는 가격 미지정 보유는 더 이상 USD 선택을 실패시키지 않으며, 봉투는 적용된 필터를 보고합니다. 보고서의 잘못된 --account 패턴은 사용법 오류로 2로 종료합니다.
  • JSON 모드 stderr는 항상 하나의 객체입니다, 허용된 경고가 실패보다 먼저 발생하더라도.
  • 호스팅 자격 증명은 빠르고 일관되게 실패합니다: 공백이 포함된 BEA_TOKEN은 요청 전에 거부되고, 폐기된 자격 증명은 cloud status와 원장 명령에서 동일하게 보고되며, owner/name은 확인 프롬프트 또는 인증된 호출 전에 검증됩니다. cloud logoutBEA_TOKEN을 그대로 두고, cloud ledger list --json은 실제로 제공한 페이지를 에코합니다.
  • Homebrew 수식은 정확한 PyPI 아티팩트 URL을 고정하므로 탭 설치와 PyPI 설치는 동일한 바이트임을 증명할 수 있습니다.

보시기 전에 어떻게 검증되었는지

릴리스는 주장이고, 파이프라인은 증거입니다. cli-v0.2.0 태그는 pyproject.toml 버전이 정확히 일치하는 main의 커밋을 지정해야 합니다; 워크플로는 사전 릴리스 접미사를 포함한 다른 모든 것을 거부합니다. 거기서부터:

  1. 전체 검사 스위트가 먼저 실행됩니다. make check-all은 린트, 형식, 엄격한 mypy, 죽은 코드 감지, 생성된 참조 드리프트 검사 및 테스트 스위트를 포함합니다. 릴리스 풀 리퀘스트는 635개의 테스트 통과를 기록합니다.
  2. 엔진 잠금이 내보내지고 해시 고정되며, 소스 배포판과 휠이 한 번 빌드됩니다. 이후의 모든 단계는 재빌드가 아닌 정확한 아티팩트를 테스트합니다.
  3. 세 운영 체제와 두 Python에서의 클린 설치. 휠은 uv tool을 통해, sdist는 Linux, macOS 및 Windows에서 Python 3.12 및 3.14에서 pip를 통해 설치되며, 선택적 AI 확장을 포함합니다. Homebrew 작업은 macOS 및 Linux에서 임시 탭을 통해 sdist를 설치합니다.
  4. 게시는 순차적이고 토큰이 없습니다. PyPI는 신뢰할 수 있는 게시를 통해 아티팩트를 받으므로 누출될 장기 API 토큰이 없습니다; GitHub 릴리스는 게시 증명을 첨부하여 생성됩니다; 그리고 Formula/bea.rb는 PyPI가 실제로 제공한 sdist URL과 해시와 함께 공개 탭에 푸시됩니다.
  5. 게시 후 스모크 테스트는 실제 인덱스에서 설치합니다. 별도의 작업이 PyPI와 공개 탭에서 고정된 버전을 설치하고 설치된 실행 파일에 대해 동일한 고객 스모크 테스트를 실행합니다. 거기서 실패하면 아무것도 롤백되지 않지만, 누구에게나 알리기 전에 릴리스에 주의가 필요하다는 의미입니다.

이 게시물은 5단계의 건너편에서 작성되고 있습니다.

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을 지원하지 않습니다. 기본 설치에는 AI 종속성이 없습니다.
  • Beangulp 및 Beanprice는 선택 사항이며, Beangulp는 시스템 libmagic 라이브러리가 필요합니다. bea import --csv는 둘 다 없이 은행 수출을 다룹니다.
  • 전달된 네이티브 명령은 봉투를 출력하지 않습니다. doctor 작업에서 구조화된 출력이 필요하다면, 그것은 우리가 듣고 싶은 요청입니다.

태그 이후, main은 이미 0.2.0에 대한 첫 번째 QA 라운드를 수집했으며 다음 릴리스에 탑승할 것입니다: bea format은 필터로 stdin을 읽고 -o FILE 모드는 쓴 내용을 명명하는 봉투로 응답합니다; --json checkbean-check 전용 플래그를 거부하고, --jsondoctor, exampletreeify에서 outright 거부되어 스크립트가 네이티브 텍스트를 봉투로 착각할 수 없습니다; --json query -o FILE은 봉투를 원자적으로 파일에 쓰고, --numberify도 JSON에 적용됩니다; bea engine status는 어떤 엔진 계층이 제공 중인지 명명합니다; 주석으로 시작하는 BQL 쿼리가 실행됩니다; 네이티브 통과 --help는 엔진이 프로비저닝되기 전에 작동합니다; 그리고 쿼리 셸의 .output은 실패한 리디렉션 후 원래 스트림을 복원합니다.

다음 단계

장부를 코드로 유지하세요

한 줄에 설치할 수 있는 도구 체인은 누구에게나 넘겨줄 수 있는 도구 체인입니다: 공동 창업자, 회계사, CI 러너, AI 에이전트. Beancount.io는 투명하고 버전 관리되며 재현 가능한 일반 텍스트 회계를 제공하며, bea는 로컬 원장을 정직하게 유지하는 명령이고 호스팅 서비스는 팀, 휴대폰 및 어시스턴트가 같은 장부를 만나는 곳입니다. bea를 설치하고 첫 검사를 실행하세요, 그리고 릴리스가 예상치 못한 일을 한다면, GitHub 저장소가 우리가 듣고 싶은 곳입니다.

이 글 공유하기

출처: https://beancount.io/ko/blog/2026/09/16/bea-0-2-0-one-install-whole-beancount-toolchain

게시됨: 2026년 9월 16일