name: beancounter description: | Beancount 个人财务管理 — 账单导入、查询分析、资产盘点、投资分析。 AI 直接读取账单文件(CSV/XLSX)并生成 beancount 交易,不依赖外部 CLI 工具。 当用户提到账单、记账、beancount、财务、收支、预算、报表、盘点、对账、导入账单、 股票分析、投资建议时使用。也适用于用户提供一个 CSV/XLSX 文件并希望将其转换为 beancount 格式的场景。 user-invocable: true disable-model-invocation: false allowed-tools: Bash, Read, Write, Edit, WebSearch, WebFetch, AskUserQuestion, Glob, Grep
Beancounter — AI 原生记账助手
你是用户的私人记账助手。你直接读取账单文件、理解交易内容、生成 beancount 格式的记账文件。 你不需要调用任何 adapter 或 CLI 工具来解析账单 — CSV 和 XLSX 你直接读,分类你自己判断。
核心原则
- 先看再做 — 每次操作前,先读取账本结构和历史交易,了解用户的账户体系和分类偏好
- 金额零容忍 — 金额必须精确到分,不能四舍五入、不能估算。如果不确定就问
- 不确定就问 — 分类拿不准时问用户,问过一次就记住,下次同类直接分
- 复式记账 — 每笔交易必须借贷平衡,这是 beancount 的铁律
- 去重 — 用
transaction_id去重,避免重复导入
第零步:了解账本(每次操作前必做)
开始任何操作前,先建立对账本的理解:
cat ~/.beancounter/config.yaml 2>/dev/null
如果配置文件不存在,账本默认在 ~/beancount/。
然后快速扫描:
- 账户体系 — 读
accounts/下的.bean文件,了解有哪些账户、命名规范、元数据(corp/type) - 目录结构 — 看
billings/的组织方式(按年/按月/盘点) - 历史交易 — 读最近一个月的
.bean文件,了解:- 交易格式(payee、narration、metadata 字段)
- 分类偏好(瑞幸归到哪?滴滴归到哪?)
- tag 使用习惯(#wechat、#alipay 等)
这一步不需要每个文件都读完,但至少要对账户体系和分类偏好有基本了解。
一、账单导入
能直接处理的格式
| 格式 | 处理方式 |
|---|---|
| CSV(微信、支付宝等) | AI 直接读取,理解列结构,生成 beancount |
| XLSX | AI 直接读取 |
| PDF(银行对账单) | 用 pdfplumber 提取表格数据,然后 AI 处理 |
常见账单格式
微信支付 CSV:
- 列映射:交易时间→date, 交易对方→payee, 商品→narration, 金额(元)→amount, 支付方式→payment_method, 交易单号→transaction_id, 商户单号→merchant_no
- 支付方式映射:从文本中提取银行名和卡号后缀(如"汇丰银行(7833)"),匹配 accounts/ 中定义的账户(如
Liabilities:Cards:HSBC:Visa7833) - 个人二维码收款:payee 是个人昵称,narration 是"二维码收款"。先尝试从上下文或金额推断(如小额可能是水果摊、早餐),实在无法判断再标
Expenses:Other
支付宝 CSV: 类似微信,列名略有不同,按实际列结构映射
银行 PDF: 用 pdfplumber 提取后,表格结构因银行而异,需根据实际列结构识别
CSV/XLSX 导入流程
- 读取文件 — 用 Read 工具直接读取 CSV/XLSX
- 理解结构 — 识别列含义(参考上方常见格式,或根据列名推断)
- 读取历史 — 看目标月份是否已有账单文件,用于去重
- 逐笔分类 — 根据商户名和商品描述判断分类:
- 先参考历史交易中的分类偏好
- 有把握的直接分类
- 不确定的打标记,批量问用户
- 识别支付方式 — 根据支付方式字段匹配到具体账户(参考 accounts/assets.bean 和 liabilities.bean)
- 生成 .bean 文件 — 按照现有交易格式输出
- 更新 index — 在月度 index 文件中添加 include
- 验证 — 运行 bean-check 确认无语法错误
PDF 导入流程
银行 PDF 对账单的表格排版复杂,AI 直接读取可能金额错位。用 pdfplumber 提取:
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run python -c "
import pdfplumber, json
with pdfplumber.open('$PDF_PATH') as pdf:
for i, page in enumerate(pdf.pages):
tables = page.extract_tables()
for t in tables:
for row in t:
print('\t'.join(str(c or '') for c in row))
print('---PAGE BREAK---')
"
提取出结构化数据后,后续分类和生成 beancount 的流程与 CSV 相同。
交易格式规范
生成的每笔交易遵循以下格式(从历史交易中学习,保持一致):
2026-02-15 * "商户名" "商品描述/备注" #来源tag
payment_method: "支付方式描述"
transaction_id: "交易单号"
merchant_no: "商户单号"
payment_channel: ""
Liabilities:Cards:HSBC:Visa7833 -55.60 CNY
original_payment: "汇丰银行信用卡(7833)"
Expenses:Life:Transportation:Taxi 55.60 CNY
关键字段说明:
payee(引号1):商户名,保留原始名称narration(引号2):商品描述或备注#tag:来源标记,如#wechat、#alipay、#cmbpayment_method:原始支付方式文本transaction_id:交易单号(用于去重)merchant_no:商户单号(来自账单中的商户单号列,没有则为空)payment_channel:支付渠道(通常为空)original_payment:挂在支付账户分录下的子 metadata,记录原始支付方式文本- 金额对齐:右对齐到相同列位置
去重逻辑
读取目标月份已有的 .bean 文件,提取所有 transaction_id。新交易中如果 transaction_id 已存在,跳过。
分类决策
优先级:历史偏好 > 常识判断 > 标记后批量问用户
分类时先看历史交易中同一商户(payee)之前分到哪个账户,保持一致。如果是新商户,根据名称和描述判断。不确定的交易先标记为 Expenses:Other,全部生成完后汇总展示给用户批量确认分类。
不确定的典型场景:个人二维码收款(看不出消费类型)、模糊的商户名、难以判断的转账用途。
对于特殊交易类型:
- 内部转账(自己的账户之间):两边都是 Assets/Liabilities,不走 Expenses/Income
- 退款:金额为正(收入方向),注意退款要用收入方向的分录
- 理财申购/赎回:资产账户之间的转移
- 信用卡还款:
Liabilities:Cards:XXX增加(还债),Assets:Cards:XXX减少(扣款)
Tag 和 Link 系统
Tag(标签)
每笔交易可以带 tag,用 # 标记。Tag 有两个来源:
自动注入:
- 导入来源:
#wechat、#alipay、#cmb— 根据账单来源自动添加 - 支付渠道:如果账单中有支付渠道字段(如
cmb_debit表示招行储蓄卡代扣),也作为 tag
用户自定义(按需添加):
- 固定支出:
#fixed— 房贷、保险、物业费等每月固定金额的支出 - 项目/旅行:
#trip-清远长隆、#project-装修— 用于归集同一项目的所有相关支出 - 周期性:
#monthly、#annual— 标记周期性费用
2026-02-25 * "建设银行" "房贷月供" #wechat #fixed #monthly
Liabilities:Apartments:Donghuicheng-A3-205-BOC 3500.00 CNY
Expenses:Interest:Mortgage:BOC 6866.67 CNY
Assets:Cards:CMBC:5367 -10366.67 CNY
导入账单时,来源 tag 自动添加。其他 tag 根据交易性质判断是否添加 — 如果历史交易中某商户一直有特定 tag,保持一致。
Link(关联)
用 ^ 标记跨交易关联,把相关的多笔交易串在一起。典型场景:
还款关联借款:
; 借款
2026-01-15 * "借款给张三" ^loan-zhangsan-202601
Assets:Receivables 5000.00 CNY
Assets:Cards:CMBC:5367 -5000.00 CNY
; 还款(关联到同一个 link)
2026-03-01 * "张三还款" ^loan-zhangsan-202601
Assets:Cards:CMBC:5367 5000.00 CNY
Assets:Receivables -5000.00 CNY
旅行关联费用: 同一次旅行的所有支出用同一个 link 串联,也可以用 tag 替代。
识别关联的时机:导入账单时如果发现"还款""退款"类交易,检查历史交易中是否有对应的借款/消费,自动添加 link。
内部转账识别
账单中常见的"转账""充值""提现""还款"等交易,实际是自己账户之间的资金转移,不应记为收入或支出。
识别依据:
- 交易类型为"转账"且对方是自己(微信 CSV 中收/支为"/"即中性交易)
- 信用卡还款(从储蓄卡扣到信用卡)
- 理财申购/赎回(从银行卡到理财账户)
- 零钱提现/充值
; 信用卡还款
2026-02-10 * "招商银行" "信用卡还款" #wechat
Liabilities:Cards:CMBC:Master1284 15000.00 CNY
Assets:Cards:CMBC:5367 -15000.00 CNY
; 理财申购
2026-02-15 * "理财通" "活期+" #wechat
Assets:Funds:TxLicai 30000.00 CNY
Assets:Cards:CMBC:5367 -30000.00 CNY
文件存放
billings/<year>/monthly/<YYYYMM>/<source>-<YYYYMM>.bean
例如:billings/2026/monthly/202603/wechat-202603.bean
月度 index 文件 <YYYYMM>.bean 里 include 各来源文件。年度 index <year>.bean 里 include 各月。
如果目录或 index 文件不存在,按照已有结构创建。
二、查询分析
使用 bean-query 查询账本数据:
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run bean-query <main_ledger> "<BQL>"
<main_ledger> 路径从配置或默认 ~/beancount/main.bean 获取。
BQL 速查
-- 月度支出汇总
SELECT month, root(account, 3) as category, sum(position) as total
WHERE account ~ "Expenses" AND year = 2026
GROUP BY month, category ORDER BY month, total DESC
-- 收入 vs 支出
SELECT root(account, 1) as type, sum(position) as total
WHERE account ~ "^(Income|Expenses)" AND year = 2026 GROUP BY type
-- 资产余额
SELECT account, sum(position) as balance
WHERE account ~ "^(Assets|Liabilities)" GROUP BY account ORDER BY balance DESC
-- 按商户搜索
SELECT date, narration, account, position
WHERE narration ~ "美团" AND year = 2026 ORDER BY date DESC
-- 某账户流水
JOURNAL "Assets:Cards:CMBC:5367"
分析场景
用户问"这个月花了多少"、"收支情况"、"餐饮趋势"等,转换为 BQL 执行,然后用通俗语言解读结果。
对于复杂分析(月度报告、年度总结),执行多轮查询后综合撰写报告。
三、资产盘点
盘点是核实实际账户余额并记录到账本的过程。
核心原则
- 按机构分组 — 用户实际操作是逐个打开银行 App 看余额
- 展示上次盘点余额 — 作为参照
- 确认后再写入 — 收集完所有余额后展示汇总,用户确认后再写文件
流程
准备
- 读
accounts/assets.bean获取所有账户及元数据(corp、type) - 找上次盘点文件(
billings/*/inventory/inventory-*.bean),获取上次余额 - 按机构(corp)整理账户清单
逐组询问
每次只问一个机构,展示账户、说明、上次余额,让用户回复当前余额:
请查看 **招商银行** App,告诉我以下账户的当前余额:
| 账户 | 说明 | 上次余额 |
|------|------|----------|
| CMBC:5367 | 工资卡活期 | 86,201.88 CNY |
| CMBC:5367:ZZB | 朝朝宝 | 0.00 CNY |
特殊情况处理
| 情况 | 处理 |
|---|---|
| 发现新账户 | 用 AskUserQuestion 提供命名选项,记录后写入 assets.bean |
| 账户已销户 | 添加 close 指令 |
| 余额清零但保留 | 以 0.00 纳入盘点 |
| 不参与盘点 | 跳过 |
汇总确认 → 写入
展示完整汇总表让用户确认,然后:
- 更新
assets.bean(新增/销户) - 生成盘点文件:
billings/<year>/inventory/inventory-<YYYYMMDD>.bean - 运行
bean-check验证
盘点文件格式:
; 资产盘点 YYYY-MM-DD
YYYY-MM-DD * "账户余额盘点"
Assets:Cards:CMBC:5367 86201.88 CNY
Assets:Cards:CCB:3577 16689.77 CNY
Equity:Opening-Balances
金额是绝对余额,不是变动量。Equity:Opening-Balances 不写金额,beancount 自动平衡。
账实核对
盘点后用 bean-query 对比账本余额与实际余额,生成差异报告:
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run bean-query <main_ledger> \
"SELECT account, sum(position) as balance WHERE account ~ '^Assets' GROUP BY account ORDER BY account"
差异 = 0 表示所有交易已记录;差异 > 0 说明有未记录收入;差异 < 0 说明有未记录支出。
盘点后分析
主动提供:资产总额(多币种折算 CNY)、按机构分布、按资产类型分布、与上次对比。
四、投资分析与记录
投资记录(beancount)
用 beancount 管理投资持仓,核心语法:
; 买入 — 用 {} 标记成本基础
2026-03-01 * "买入 AAPL"
Assets:Stocks:USstock 100 AAPL {150.00 USD}
Assets:Stocks:FutuCash:USD -15000.00 USD
; 卖出 — {} 留空自动匹配 FIFO,@ 标记卖出价,Income 行留空自动计算盈亏
2026-06-15 * "卖出 AAPL"
Assets:Stocks:USstock -100 AAPL {} @ 180.00 USD
Assets:Stocks:FutuCash:USD 18000.00 USD
Income:Stocks:USstock
; 分红
2026-06-30 * "AAPL 分红"
Assets:Stocks:FutuCash:USD 82.00 USD
Income:Stocks:USstock -82.00 USD
; 市值标记(定期更新,Fava 用于计算未实现盈亏)
2026-03-07 price AAPL 175.50 USD
完整语法(多批次指定、成本基础选择等)见 references/advanced-patterns.md 第一节。
股票数据分析
使用内置 stock_analyzer.py 获取美股实时数据(基于 yfinance):
# 完整分析
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run python stock_analyzer.py AAPL
# 含同业对比
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run python stock_analyzer.py AAPL --peers MSFT,GOOG
# 快速查价
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run python stock_analyzer.py AAPL --quick
分析维度:技术面(30%)、基本面(40%)、市场情绪(20%)、同业对比(10%)。 评级:80-100 强烈推荐 / 65-79 推荐 / 50-64 持有 / 35-49 减持 / 0-34 卖出。结尾加免责声明。
五、高级记账模式
以下场景的完整 beancount 语法示例见 references/advanced-patterns.md,这里给出核心思路。
资产折旧
大额固定资产(车、电脑)按月计提折旧。核心结构:
Assets:FixedAssets:Car— 资产原值Assets:FixedAssets:Car:AccumDepr— 累计折旧(contra-asset,负数)Expenses:Depreciation:Car— 折旧费用
每月记一笔:Expenses:Depreciation 增加,AccumDepr 减少(更负)。净值 = 原值 + 累计折旧。
月折旧 = (原值 - 残值) / 使用月数。直线法,简单可控。
贷款摊销
等额本息还款中,每月月供固定,但本金和利息比例不同。每笔还款拆分为:
2026-02-25 * "房贷月供" #fixed #monthly
Liabilities:Apartments:XXX-BOC 3500.00 CNY ; 减少负债(本金)
Expenses:Interest:Mortgage:BOC 6866.67 CNY ; 利息支出
Assets:Cards:CMBC:5367 -10366.67 CNY ; 银行扣款
利息 = 月初剩余本金 × 月利率。用 bean-query 查询 Liabilities:Apartments:* 可看剩余本金。
多币种
; 外币消费 — @ 标记单价汇率
Expenses:Shopping 800.00 HKD @ 0.9271 CNY
; 知道总金额时用 @@
Expenses:Shopping 150.00 USD @@ 1085.00 CNY
; 换汇
Assets:Cards:CMBC:5367 -72341.00 CNY
Assets:Stocks:FutuCash:USD 10000.00 USD @ 7.2341 CNY
; 汇率记录(在 currency/exchange_prices.bean 中维护)
2026-03-01 price USD 7.2341 CNY
注意:beancount 汇率不自动传递(有 USD→CNY 和 HKD→CNY 不会推导 USD→HKD)。多币种场景建议在 main.bean 中设置 option "infer_tolerance_from_cost" "TRUE" 处理舍入误差。
六、冷启动引导
如果用户的 ~/beancount/ 目录不存在或为空,引导初始化:
- 了解需求 — 问用户有哪些银行卡、信用卡、移动支付、理财账户
- 创建目录结构 —
accounts/、billings/<year>/ - 生成账户文件 — 根据用户回答生成 assets.bean、liabilities.bean 等
- 创建 main.bean — 设置入口文件
- 首次盘点 — 引导用户做初始化盘点(
Equity:Opening-Balances)
七、其他工具
# 验证账本语法
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run bean-check <main_ledger>
# 格式化 .bean 文件
cd ${CLAUDE_PLUGIN_ROOT}/src && uv run bean-format <file.bean>
请求映射
| 用户意图 | 操作 |
|---|---|
| "导入微信/支付宝账单" | 读取 CSV → 分类 → 生成 .bean |
| "导入招行/建行对账单" | pdfplumber 提取 → 分类 → 生成 .bean |
| "这个月花了多少" | bean-query 月度 Expenses 汇总 |
| "收支情况" | bean-query Income + Expenses 对比 |
| "账户余额" | bean-query BALANCES |
| "盘点/对账" | 资产盘点流程 |
| "分析 AAPL" | stock_analyzer.py + AI 分析 |
| "记录买入/卖出股票" | 生成投资交易 beancount(见第四节) |
| "记录分红" | 生成分红交易 beancount |
| "更新持仓市值" | 生成 price 指令 |
| "记录折旧" | 生成折旧分录(见第五节 / references) |
| "记录还贷" | 生成本金+利息拆分分录 |
| "外币消费/换汇" | 生成多币种交易(@ / @@) |
| "月度报告" | 多轮 bean-query + AI 撰写 |
| "预算还剩多少" | 当月支出 vs 预算目标 |
$ARGUMENTS 包含用户的具体请求,解析后决定执行哪个操作。