subs — SaaS 订阅支出分析工具
分析用户来自银行/信用卡 CSV 导出文件和电子邮件收据的周期性订阅支出。生成支出摘要、标记浪费、追踪续费,并推荐节省方案。
账本是核心
工作区中的 subscriptions.yaml 是唯一的真相来源。每次运行都会将新数据核对到其中 —— 它从不从头重新推导所有内容。这正是实现续费跟踪和运行间一致性的关键,也使“浪费”可计算(一个订阅连续收费数月后突然消失 = 已失效或值得取消)。切勿整体覆盖账本;应核对合并到其中。
账本条目标记(每个订阅一条):
- vendor: GitHub # 规范名称
amount: 4.00 # 最近一次收费金额
currency: USD
cycle: monthly # weekly | monthly | quarterly | semiannual | annual
category: Dev tools
first_seen: 2025-01-12 # 已知最早收费的 ISO 日期
last_seen: 2026-06-03 # 最近一次收费的 ISO 日期
next_renewal: 2026-07-03 # last_seen + 一个周期
status: active # active | price_hike | lapsed? | cancelled
notes: "自注册起为 4.00"
前提条件:Gmail 连接器
本技能通过Gmail 连接器/MCP(例如 Claude Code 的 Gmail 连接器)从 Gmail 读取订阅收据。在步骤 1 之前,请确认你的代理具备 Gmail 搜索/读取工具(search_threads / get_thread 对或等效工具)。如果没有可用的 Gmail 集成,请停止并告知用户启用该集成,然后重新运行技能。详细信息和查询见 email-receipts.md。
流程
请按顺序执行以下步骤。在步骤 5 之前不要报告。
0. 定位工作区
使用当前工作目录作为工作区。确保 data/statements/、data/receipts/ 和 reports/ 目录存在(如缺失则创建)。如果 subscriptions.yaml 存在则加载;否则将账本视为空。
完成条件: 工作区目录已存在且账本已加载(可能为空)。
如果 data/statements/ 为空且不存在 subscriptions.yaml,且用户未使用 Plaid(下一节),则告知用户将银行/信用卡 CSV 导出文件放入 data/statements/ 并停止 —— CSV 是周期性检测的基础。
1. 收集输入源
通过 Plaid CLI 获取银行数据(首选 —— 无需手动导出 CSV):确保 CLI 已就绪,并将交易拉取至 data/statements/plaid-transactions.csv,详见 plaid.md。否则,依赖用户放入 data/statements/ 的 CSV 文件。
然后列出 data/statements/ 中的每个 CSV。根据 email-receipts.md 从 Gmail 提取订阅收据,同时读取 data/receipts/ 中的任何补充 .eml/.txt 文件。
完成条件: data/statements/ 中的每个 CSV 均已枚举,并且 Gmail 收据搜索已完成(或由于缺少连接器而停止运行)。
2. 检测周期性收费
对每个声明 CSV(包括 Plaid 生成的)运行确定性检测器 —— 切勿人工查看行。<skill-dir> 是本技能自己的目录(在 Claude Code 中:~/.claude/skills/subs/):
python3 <skill-dir>/scripts/detect_recurring.py data/statements/*.csv
对于 low 置信度的候选项目以及商家名称标准化边缘情况,请参考 recurrence-detection.md。将这些候选项目与步骤 1 中收集的 Gmail 收据相结合 —— 收据可以捕捉短期账单遗漏的年度订阅,并识别模糊的描述信息。
完成条件: 每个周期性候选项目都已有商家、周期、金额和最近日期。
3. 核对至账本
将候选项目核对至 subscriptions.yaml:
- 新商家 → 添加条目;通过 categories.md 分类。
- 已有 → 更新
last_seen和next_renewal;如果金额上涨,则设置status: price_hike并在notes中记录旧金额。 - 账本中有但近期数据中缺失(在距今约 1.5 个周期内无收费) → 设置
status: lapsed?。
完成条件: 每个账本条目的 status 为 active | price_hike | lapsed? | cancelled 之一,并且每个候选项目恰好对应一个账本条目。
4. 分析
根据核对后的账本计算以下所有四项:
- (a) 支出摘要 —— 每月总额和年化总额,按类别、商家和计费周期分组。将每个条目归一化为月度金额($/月):年费 ÷ 12、半年费 ÷ 6、季费 ÷ 3、月费 × 1、双周费 × 2.17、周费 × 4.33、半月费 × 2。报告重复使用此 $/月(唯一真相来源)。
- (b) 浪费 —— 重复(同一服务两次)、重叠工具(同一类别中做相同工作的两个产品)、涨价(
status: price_hike)以及失效/未使用(status: lapsed?)。 - (c) 即将到来的续费 ——
next_renewal在接下来 60 天内的条目,按时间顺序排列。 - (d) 节省建议 —— 年付转月付、降级、合并和取消。每条建议必须引用一个账本条目及具体的美元影响。
完成条件: 已生成全部四项,并且每条建议引用一个条目及一个美元数值。
5. 报告
保存账本,然后根据账本编写两个报告:
- Markdown 格式
reports/<YYYY-MM-DD>-subscriptions.md,模板见 report-template.md; - 自包含的 HTML 仪表板
reports/<YYYY-MM-DD>-subscriptions.html,模板见 html-report.md,并打开它(open <path>)。
然后在聊天中呈现简洁摘要(关键总数 + 前 3 项操作)。
完成条件: 两个报告均包含支出摘要、浪费标记、即将到来的续费和排序后的建议,并且 subscriptions.yaml 已保存。