subs — SaaS 구독 지출 분석기
사용자의 은행/카드 CSV 내보내기 파일과 이메일 영수증에서 반복되는 구독 지출을 분석합니다. 지출 요약을 생성하고, 낭비를 표시하며, 갱신을 추적하고, 절약 방안을 추천합니다.
원장(ledge)이 핵심입니다
작업 공간의 subscriptions.yaml이 단일 진실 공급원입니다. 실행할 때마다 새로운 데이터를 *조정(reconcile)*하여 업데이트하며, 처음부터 다시 생성하지 않습니다. 이 방식이 갱신 추적과 실행 간 일관성을 실현하며, "낭비"를 계산 가능하게 만듭니다(수개월간 청구되다 갑자기 사라진 구독 = 중단되었거나 취소할 가치가 있음). 원장을 통째로 덮어쓰지 말고, 조정하여 업데이트하세요.
원장 항목 스키마 (구독당 하나의 항목):
- 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: "was 4.00 since signup"
전제 조건: Gmail 커넥터
이 스킬은 Gmail 커넥터/MCP를 통해 Gmail에서 구독 영수증을 읽습니다(예: Claude Code의 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가 준비되었는지 확인하고 plaid.md에 따라 거래 내역을 data/statements/plaid-transactions.csv로 가져옵니다. 그렇지 않으면 사용자가 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. 보고
원장을 저장한 후, 원장에서 두 가지 보고서를 모두 작성합니다:
- report-template.md에 따른 마크다운
reports/<YYYY-MM-DD>-subscriptions.md - html-report.md에 따른 자체 포함 HTML 대시보드
reports/<YYYY-MM-DD>-subscriptions.html을 열기 (open <path>)
그런 다음 채팅에 간결한 요약을 제시합니다 (주요 합계 + 상위 3개 조치).
완료 조건: 두 보고서 모두 지출 요약, 낭비 플래그, 예정된 갱신, 순위별 권장 사항을 포함하고 subscriptions.yaml이 저장되었습니다.