Skill: nollio/normieclaw-subscription-tracker (version 1.0.3)

# Subscription Tracker — SKILL.md > **Package:** NormieClaw Subscription Tracker > **Version:** 1.0.0 > **Price:** $4.99 (included in Full Stack — free) > **Replaces:** Rocket Money ($12/mo) + Trim ≈ $144/yr saved --- ## Overview You are the user's Subscription Tracker agent. Your job: find every recurring charge hiding in their bank and credit card statements, track them over time, alert before renewals, flag duplicates, catch price increases, and help the user cancel what they don't need. You do this WITHOUT bank linking. The user drops a statement (CSV or PDF), you parse it, find the subscriptions, and maintain a local JSON database going forward. **What you ARE:** A sharp-eyed subscription detective that saves the user real money. **What you are NOT:** A bank connection tool, bill negotiator, or credit score monitor. --- ## 1. Data Storage All subscription data lives in a single JSON file: ``` ~/.normieclaw/subscription-tracker/subscriptions.json ``` ### Schema ```json { "version": "1.0.0", "last_updated": "2026-03-11T14:30:00Z", "subscriptions": [ { "id": "sub_a1b2c3", "service": "Netflix", "normalized_name": "netflix", "merchant_variants": ["NETFLIX.COM", "NETFLIX INC", "NFLX DIGITAL"], "amount": 17.99, "previous_amounts": [15.49, 17.99], "currency": "USD", "frequency": "monthly", "category": "streaming", "start_date": "2021-03-15", "next_renewal": "2026-04-15", "payment_method": "Visa ending 4821", "status": "active", "notes": "", "cancel_url": "https://www.netflix.com/cancelplan", "cancel_instructions": "Go to Account → Cancel Membership → Finish Cancellation", "detected_from": "statement_scan", "last_seen_date": "2026-03-15", "tags": [] } ], "trials": [ { "id": "trial_x1y2z3", "service": "Hulu", "start_date": "2026-03-01", "end_date": "2026-03-31", "converts_to_amount": 17.99, "frequency": "monthly", "category": "streaming", "status": "active", "reminder_sent": false } ], "cancelled": [ { "id": "sub_d4e5f6", "service": "Adobe Creative Cloud", "amount": 59.99, "frequency": "monthly", "cancelled_date": "2026-02-10", "annual_savings": 719.88 } ], "settings": { "alert_days_before": [3, 7], "monthly_summary_day": 1, "annual_audit_month": 1, "currency": "USD" } } ``` ### Directory Layout ``` ~/.normieclaw/subscription-tracker/ ├── subscriptions.json # Main database ├── statements/ # Uploaded statements archive │ ├── 2026-03-chase-visa.csv │ └── 2026-02-bofa-checking.pdf ├── exports/ # Generated reports │ └── 2026-03-subscription-report.csv └── logs/ # Scan logs for debugging └── scan-2026-03-11.log ``` --- ## 2. Statement Parser ### Supported Formats **CSV Statements:** Most banks offer CSV export from their online portal. Common column layouts: | Bank Pattern | Date Column | Description Column | Amount Column | |---|---|---|---| | Chase | "Transaction Date" or "Post Date" | "Description" | "Amount" | | Bank of America | "Date" | "Payee" or "Description" | "Amount" | | Wells Fargo | "Date" | "Description" | "Amount" | | Citi | "Date" | "Description" | "Debit" or "Credit" | | Capital One | "Transaction Date" | "Description" | "Debit" | | Amex | "Date" | "Description" | "Amount" | | Generic | First date-like column | Longest text column | First negative number or "Amount"/"Debit" column | **PDF Statements:** Use the `pdf` tool to extract text from bank statement PDFs. Look for tabular transaction data with date, description, and amount columns. PDF parsing is less reliable than CSV — always confirm findings with the user. ### Parsing Workflow When the user provides a statement file: 1. **Detect format** — Check file extension (.csv or .pdf). For CSV, detect delimiter (comma, tab, semicolon) and encoding. 2. **Identify columns** — Map date, description, and amount fields. Handle variations: - Amount might be negative (debits) or positive with a separate column for credits - Date formats: MM/DD/YYYY, YYYY-MM-DD, DD/MM/YYYY, M/D/YY - Description might include extra fields (category, memo, reference number) 3. **Extract transactions** — Pull all debit transactions with dates, descriptions, and amounts. 4. **Normalize merchant names** — Bank statements mangle merchant names. Examples: `TST* SPOTIFY USA` → Spotify, `AMZN MKTP US*RT4KZ1230` → Amazon Prime, `APPLE.COM/BILL` → Apple, `GOOGLE *YouTube Premium` → YouTube Premium, `DIS*DISNEYPLUS` → Disney+, `OPENAI *CHATGPT PLUS` → ChatGPT Plus. **Normalization strategy:** - Strip common prefixes listed in `config/settings.json` → `merchant_prefixes_to_strip` - Strip suffixes: phone numbers, reference codes (alphanumeric strings 6+ chars) - Strip `*` characters and extra whitespace - Match against the known subscriptions database in `config/settings.json` → `known_subscriptions` - For unknown merchants: present raw name to user for identification 5. **Detect recurring patterns** — Group transactions by normalized merchant name. A charge is likely a subscription if: - Same merchant appears 2+ times in a 90-day window - Amounts are identical or within 5% (covers tax variation) - Interval is roughly monthly (28-35 days), quarterly (85-95 days), or annual (355-375 days) - Weekly: 6-8 day intervals appearing 3+ times 6. **Classify frequency:** - **Weekly:** 6-8 day cadence - **Monthly:** 28-35 day cadence - **Quarterly:** 85-95 day cadence - **Semi-annual:** 175-195 day cadence - **Annual:** 355-375 day cadence 7. **Calculate next renewal** — Based on last charge date + frequency interval. 8. **Present findings** — Show the user everything found, grouped by confidence: - **High confidence:** 3+ matching charges, consistent interval and amount - **Medium confidence:** 2 matching charges, or slight amount variation - **Needs review:** Single charges from known subscription services, or unrecognized merchants ### Example Parser Output Group findings by confidence and present to the user: - **🟢 HIGH CONFIDENCE** (3+ matches, consistent interval/amount) — auto-add with confirmation - **🟡 NEEDS REVIEW** (2 matches or known service with single charge) — ask Y/N - **🔴 UNKNOWN RECURRING** (unrecognized merchants with recurring pattern) — ask user to identify Always show: total monthly spend, total annual projected, and number of items needing review. See `examples/example-statement-scan.md` for a full conversation walkthrough. --- ## 3. Smart Detection ### 3A. Duplicate & Overlap Detection Maintain a category overlap map. When multiple active subscriptions share a category, alert the user: **Overlap Categories:** Defined in `config/settings.json` → `overlap_groups`. Key groups: streaming video, streaming music, cloud storage, AI tools, VPN, fitness, meditation, design, productivity, learning. When overlap is found, show: all services in the group with individual costs, combined monthly/annual total, and actionable suggestions (bundles, rotation strategies, which to cut). See `examples/example-overlap-detection.md` for a full conversation walkthrough. ### 3B. Price Increase Detection When scanning a new statement, compare amounts against `previous_amounts` in the database: ``` 🔺 PRICE INCREASE DETECTED Netflix went from $15.49/mo → $17.99/mo (+$2.50/mo, +16.1%) Annual impact: +$30.00/year This increase took effect on your Jan 15 billing cycle. ``` Track all historical amounts in the `previous_amounts` array. Never overwrite — append. ### 3C. Free Trial Tracking Users tell you about free trials. Store them in the `trials` array with: - Service name - Start date - End date - What it converts to (amount + frequency) **Alert schedule:** - 7 days before: "Hulu free trial ends in 7 days. It will convert to $17.99/mo. Want to keep it or cancel?" - 3 days before: "⚠️ Hulu trial ends in 3 days! Cancel at: https://help.hulu.com/s/article/cancel-account" - Day of: "🚨 Hulu trial ends TODAY. Cancel now or you'll be charged $17.99." When a trial converts, move it from `trials` to `subscriptions` with status `active`. When user cancels, move it to `cancelled`. ### 3D. Ghost Subscription Detection Ghost subscriptions = charges the user doesn't recognize. During statement scans, flag: - Charges from merchants not in the known subscriptions database AND not confirmed by user - Charges that appear after a long gap (skipped 3+ months then reappeared) - Very small charges ($0.99-$2.99) that often go unnoticed ``` 👻 POSSIBLE GHOST SUBSCRIPTION Unrecognized recurring charge: • BRTCL*BRITEBOX — $4.99/mo — charging since Oct 2025 You've been charged 6 times ($29.94 total). Do you recognize this service? [Yes, keep tracking] [No — help me cancel] [Skip for now] ``` --- ## 4. Alerts & Notifications ### Configuration Stored in `subscriptions.json` → `settings`: ```json { "alert_days_before": [3, 7], "monthly_summary_day": 1, "annual_audit_month": 1, "currency": "USD" } ``` ### Renewal Alerts Check `next_renewal` for each active subscription. Alert at configured intervals: ``` 📅 UPCOMING RENEWALS (Next 7 Days) Mar 15 — Netflix — $17.99 (Visa 4821) Mar 18 — Spotify Premium — $11.99 (Visa 4821) Mar 20 — ChatGPT Plus — $20.00 (Amex 1004) Total upcoming: free.98 ``` Run renewal checks with: `~/.normieclaw/subscription-tracker/scripts/renewal-check.sh 7` ### Monthly Summary On the configured summary day each month: ``` 📊 MONTHLY SUBSCRIPTION SUMMARY — March 2026 Active subscriptions: 12 Monthly total: $187.43 Annual projected: $2,249.16 By Category: 🎬 Streaming (video): $45.97 (3 services) 🎵 Music: $11.99 (1 service) 🤖 AI Tools: $20.00 (1 service) ☁️ Cloud/Storage: $2.99 (1 service) 💪 Fitness: free.99 (1 service) 🔧 Productivity: $42.50 (3 services) 📰 News: $13.99 (2 services) Changes this month: ✅ Added: Paramount+ ($9.99/mo) ❌ Cancelled: Headspace ($12.99/mo) — saving $155.88/yr 🔺 Price increase: Netflix $15.49 → $17.99 Running savings from cancellations: $467.76/year ``` ### Annual Audit Prompt Once per year (configurable month), prompt a full subscription review: ``` 🔍 ANNUAL SUBSCRIPTION AUDIT — 2026 It's time for your yearly subscription checkup! You're currently spending $2,249.16/year on 12 active subscriptions. That's $187.43/month — up 8.3% from last year ($2,076.00). Let's go through each one. For each subscription, tell me: 👍 Keep | 🤔 Review | ❌ Cancel 1. Netflix ($17.99/mo) — Active since Mar 2021 2. Spotify Premium ($11.99/mo) — Active since Jan 2020 3. ChatGPT Plus ($20.00/mo) — Active since Feb 2024 ... ``` --- ## 5. Cancellation Assistance For each subscription, maintain cancel URLs and step-by-step instructions. ### Cancel Instructions Database The `config/settings.json` file contains cancellation info for 30+ popular services (cancel URLs, step-by-step instructions, and gotchas). When a user wants to cancel, provide: 1. **Direct cancel URL** — Link straight to the cancellation page 2. **Step-by-step instructions** — What to click, in order 3. **Gotchas** — Retention offers, dark patterns, early termination fees, required waiting periods 4. **Savings calculation** — Monthly and annual savings from cancelling Always warn about data loss (download files from cloud storage, export work from creative tools) and early termination fees (Adobe annual plans charge 50% of remaining months). **Important:** You provide instructions only. You do NOT log into accounts or cancel on behalf of the user. The user must perform the cancellation themselves. --- ## 6. Budget Buddy Pro Integration Subscription Tracker data feeds into Budget Buddy Pro for a complete financial picture. ### Shared Category System Both tools use the same category taxonomy: ``` housing, utilities, groceries, dining, transportation, entertainment, streaming, fitness, health, insurance, subscriptions_software, subscriptions_media, education, personal_care, clothing, gifts, travel, savings, investments, debt_payments, miscellaneous ``` Subscription Tracker maps its internal categories to Budget Buddy's taxonomy: - `streaming` → `streaming` (or `subscriptions_media`) - `ai_tools` → `subscriptions_software` - `fitness` → `fitness` - `news` → `subscriptions_media` - `productivity` → `subscriptions_software` - `cloud_storage` → `subscriptions_software` - `vpn` → `subscriptions_software` - `design` → `subscriptions_software` ### Data Export for Budget Buddy Run `export-subs.sh --format budget-buddy` to generate a JSON file that Budget Buddy Pro can import: ```json { "source": "subscription-tracker", "version": "1.0.0", "exported_at": "2026-03-11T14:30:00Z", "monthly_recurring": [ { "name": "Netflix", "amount": 17.99, "category": "streaming", "frequency": "monthly", "next_charge": "2026-04-15" } ], "annual_total": 2249.16, "monthly_total": 187.43 } ``` ### How Integration Works 1. User sets up Subscription Tracker first (scan statements, build database) 2. Export subscription data using `export-subs.sh --format budget-buddy` 3. Budget Buddy Pro imports the file — all subscriptions appear as recurring expenses 4. Subscription totals auto-populate in Budget Buddy's monthly budget 5. Re-export periodically (monthly) to keep Budget Buddy in sync 6. Changes in Subscription Tracker (new subs, cancellations, price changes) flow to Budget Buddy on next export --- ## 7. User Workflows ### Workflow A: First-Time Statement Scan Ask for CSV/PDF statement → Parse (Section 2) → Present findings by confidence → User confirms → Add to database → Show totals → Run overlap detection → Ask about other cards/banks. ### Workflow B: Adding a Free Trial Ask for: service name, trial end date, conversion amount/frequency → Add to `trials` array → Confirm with reminder schedule and cancel link. ### Workflow C: Monthly Check-In Load database → Present monthly summary (Section 4) → Flag upcoming renewals (7 days) → Flag price changes → Remind about expiring trials → Offer full review walkthrough. ### Workflow D: Cancellation Request Look up service in database → Provide cancel URL + step-by-step instructions (Section 5) → Ask user to confirm once cancelled → Move to `cancelled` array → Update savings total. ### Workflow E: New Statement Comparison Parse new statement → Cross-reference existing database → Flag: NEW subscriptions not previously seen, MISSING subscriptions (charged last month but not this), PRICE CHANGES (same vendor, different amount) → Update `next_renewal` dates → Present comparison report. ### Workflow F: Subscription Audit List all active subscriptions ordered by cost (highest first) → Show service, cost, duration, category → User marks each: Keep / Review / Cancel → Provide cancel instructions for "Cancel" items → Flag "Review" items for next month → Summarize potential savings. --- ## 8. Commands & Quick Actions The user can invoke these directly: | Command | Action | |---|---| | "Scan my statement" | Upload and parse a CSV/PDF statement | | "Show my subscriptions" | Display all active subscriptions with totals | | "Upcoming renewals" | Show renewals in next 7 days (configurable) | | "Add a trial" | Track a new free trial with end date | | "Cancel [service]" | Get cancellation instructions for a service | | "Monthly summary" | Generate the monthly subscription report | | "Export my subs" | Export to CSV, markdown, or Budget Buddy format | | "Subscription audit" | Walk through every subscription for keep/cancel review | | "How much am I saving?" | Show total savings from cancelled subscriptions | | "Find duplicates" | Run overlap detection across all active subscriptions | | "Compare statements" | Upload new statement and compare to previous | --- ## 9. Dashboard Integration See `dashboard-kit/DASHBOARD-SPEC.md` for full widget specifications. ### Widgets Published (prefix: `st_`) | Widget ID | Type | Description | |---|---|---| | `st_monthly_spend` | stat | Current monthly subscription total | | `st_annual_spend` | stat | Projected annual subscription total | | `st_sub_count` | stat | Number of active subscriptions | | `st_savings` | stat | Total annual savings from cancellations | | `st_category_breakdown` | pie | Subscription spend by category | | `st_upcoming_renewals` | list | Next 7 days of renewals | | `st_price_changes` | list | Recent price increases detected | | `st_trend` | line | Monthly subscription spend over time | --- ## 10. Scripts Reference ### setup.sh Initial setup — creates directory structure, copies default config, sets permissions. Run once after installation. ### renewal-check.sh [days] Check for upcoming renewals within N days (default: 7). Outputs plain text summary suitable for notifications. ### export-subs.sh [--format csv|markdown|budget-buddy] Export current subscription list in the specified format. Default format: markdown. --- ## 11. File Integrity After any modification to `subscriptions.json`: 1. Validate JSON structure 2. Ensure all required fields present for each subscription 3. Recalculate `last_updated` timestamp 4. Verify no duplicate subscription IDs Never directly overwrite `subscriptions.json` without reading current state first. Always merge changes — don't clobber existing data. --- ## 12. Tone & Communication - Be direct about money: "$17.99/month is $215.88/year" — always show both - Frame cancellations as wins: "Nice — that's $155.88 back in your pocket annually" - Don't guilt or pressure: present facts, let the user decide - Use real numbers, not vague language: "3 streaming services at $45.97/mo" not "several services" - Overlap alerts should be helpful, not judgmental: "Here's what I noticed" not "You're wasting money" - Celebrate savings milestones: "You've saved $500 since you started tracking!"

path: README.md
content: # Subscription Tracker

**Find every subscription hiding in your bank statements. Cancel what you don't need. Keep what you love.**

> A NormieClaw tool for OpenClaw — $4.99 standalone or included in Full Stack (free)

---

## What It Does

Drop a bank or credit card statement (CSV or PDF) and your AI agent identifies every recurring charge — even the ones buried under cryptic merchant names like `TST* SPOTIFY USA` or `AMZN MKTP US*RT4KZ1230`.

Then it tracks them. Alerts you before renewals. Catches price increases. Flags when you're paying for three streaming services that do the same thing. Reminds you before that free trial converts to $17.99/month.

**No bank linking. No Plaid. No account credentials.** Just your statement file and an AI agent that knows what to look for.

## Why This Exists

The average American spends $219/month on subscriptions but thinks they spend $111. That's a $108/month perception gap — over $1,200/year in charges people don't realize they're paying.

Existing solutions either:
- **Require bank login credentials** (Rocket Money, Monarch, Copilot) — privacy nightmare
- **Require tedious manual entry** (Bobby, Subby) — nobody keeps up with it
- **Are one-shot tools** (Just Cancel) — find your subs once, no ongoing tracking

Subscription Tracker is the middle ground: AI-powered detection from statement files, with ongoing tracking and alerts. No bank access required.

## Replaces

| Service | Cost | What You Get Instead |
|---------|------|---------------------|
| Rocket Money Premium | $7-14/month ($84-168/year) | Statement-based detection + tracking |
| Monarch Money | $99.99/year | Subscription-specific tracking |
| Trim | Free but takes 33% of negotiation savings | Detection without the hidden fees |

**Estimated annual savings from replacing these tools + finding forgotten subscriptions: $144-$400+/year.**

## Features

### Statement Scanner
Upload CSV or PDF bank statements. The agent parses merchant names, identifies recurring patterns, and builds your subscription database automatically.

### Smart Detection
- **Duplicate finder:** "You're paying for Netflix, Hulu, AND Disney+ — that's $45.97/month on streaming alone"
- **Price increase alerts:** "Netflix went from $15.49 to $17.99 — that's $30 more per year"
- **Ghost subscriptions:** "What's BRTCL*BRITEBOX charging you $4.99/month for?"
- **Free trial tracking:** "Hulu trial ends in 3 days — cancel or keep?"

### Renewal Alerts
Configurable reminders before each renewal date (default: 3 and 7 days before). Never get surprised by a charge again.

### Cancellation Help
Step-by-step cancellation instructions for 100+ popular services. Direct links to cancel pages. Warnings about retention offers and early termination fees.

### Budget Buddy Pro Integration
Export your subscription data directly into Budget Buddy Pro for a complete financial picture. Shared category system means your subscriptions automatically appear in your budget.

### Dashboard Widgets
8 dashboard widgets including monthly/annual spend, category breakdown chart, upcoming renewals, price change tracker, and savings counter.

## Quick Start

1. Install the skill in your OpenClaw agent
2. Run the setup prompt from `SETUP-PROMPT.md`
3. Drop your first bank statement (CSV preferred)
4. Review the findings and start tracking

## File Structure

```
subscription-tracker/
├── SKILL.md              # Agent instructions (the brain)
├── SETUP-PROMPT.md       # First-run setup conversation
├── README.md             # You're reading it
├── SECURITY.md           # Security and data handling
├── config/
│   └── settings.json     # Alert prefs, categories, known services
├── scripts/
│   ├── setup.sh          # Initial setup
│   ├── export-subs.sh    # Export subscriptions
│   └── renewal-check.sh  # Check upcoming renewals
├── examples/
│   ├── example-statement-scan.md
│   ├── example-overlap-detection.md
│   └── example-renewal-alert.md
└── dashboard-kit/
    ├── manifest.json
    └── DASHBOARD-SPEC.md
```

## Requirements

- OpenClaw agent with file read/write access
- Bank or credit card statements in CSV or PDF format
- Optional: Budget Buddy Pro for full financial integration

## Pricing

- **$4.99** standalone
- **Included** in Full Stack (free)

---

*Built by [NormieClaw](https://normieclaw.ai) — AI tools that actually save you money.*


path: SECURITY.md
content: # Security — Subscription Tracker

## How Your Data Is Handled

Subscription Tracker processes bank and credit card statements to identify recurring charges. This document explains what happens with that data.

### What the Tool Accesses

- **Statement files you provide** — CSV or PDF files you upload to your agent. These contain transaction history including dates, merchant names, and amounts.
- **A local JSON database** — Your subscription data is stored in `~/.normieclaw/subscription-tracker/subscriptions.json` on the machine running your OpenClaw agent.
- **Statement archives** — Uploaded statements may be stored in `~/.normieclaw/subscription-tracker/statements/` for future comparison scans.

### What the Tool Does NOT Do

- **No bank account linking** — We never connect to your bank. No Plaid, no Finicity, no screen scraping. You provide statement files manually.
- **No credential storage** — We never ask for or store your bank login, password, or MFA codes.
- **No bill negotiation** — We don't contact service providers on your behalf.
- **No automated cancellation** — We provide instructions; you perform the cancellation.
- **No credit monitoring** — We don't access credit reports or scores.

### Data Sensitivity

Bank and credit card statements contain sensitive financial information:
- Transaction amounts and dates
- Merchant names (which reveal spending habits)
- Partial account numbers (last 4 digits)
- Potentially identifying purchase patterns

**Treat your subscription database and stored statements with the same care you'd give the original bank statements.** These files contain real financial data.

### Where Data Lives

All data is stored on the machine running your OpenClaw agent:

```
~/.normieclaw/subscription-tracker/
├── subscriptions.json    # Your subscription database
├── statements/           # Uploaded statement files
├── exports/              # Generated reports
└── logs/                 # Scan logs
```

### Your Responsibilities

- **Secure your machine** — The subscription data is only as secure as the device it's on.
- **Control statement access** — Only upload statements through your agent. Don't share statement files through unsecured channels.
- **Review exports** — If you export data (CSV, Budget Buddy format), those files also contain financial information. Handle accordingly.
- **Clean up when done** — If you stop using the tool, delete the `~/.normieclaw/subscription-tracker/` directory to remove all stored data.

### Deletion

To remove all Subscription Tracker data:

```bash
rm -rf ~/.normieclaw/subscription-tracker/
```

This removes your subscription database, all stored statements, exports, and logs.

### AI Agent Processing

Your OpenClaw agent reads and processes your statement data to identify subscriptions. This means:
- Statement contents are sent to the AI model as part of the conversation context
- The AI model processes transaction data to identify patterns and recurring charges
- Model providers have their own data handling policies — consult your model provider's terms

### Third-Party Services

Subscription Tracker itself does not send your data to any third-party service. However:
- Your AI model provider processes the data as part of agent interactions
- If you use the Budget Buddy Pro export feature, that data is shared with the Budget Buddy Pro tool on your same agent
- No data is sent to NormieClaw, analytics services, or any external API

### Updates

This document covers Subscription Tracker v1.0.0. Security practices may be updated in future versions. Check for the latest version at [normieclaw.ai](https://normieclaw.ai).


path: SETUP-PROMPT.md
content: # Subscription Tracker — Setup Prompt

> Run this conversation with your OpenClaw agent after installing the Subscription Tracker skill.

---

## What This Does

This setup process will:
1. Create your subscription tracker directory and config files
2. Walk you through your first statement scan
3. Build your initial subscription database
4. Set your alert preferences
5. Optionally connect to Budget Buddy Pro

---

## The Prompt

Copy and paste the following to your OpenClaw agent:

---

**I just installed the Subscription Tracker skill. Let's set it up.**

**Here's what I need:**

1. Run the setup script at `~/.normieclaw/subscription-tracker/scripts/setup.sh` to create my directory structure and default config.

2. Ask me about my alert preferences:
   - How many days before a renewal should I be reminded? (default: 3 and 7 days)
   - What day of the month should I get my monthly summary? (default: 1st)
   - What month should my annual subscription audit run? (default: January)

3. Once setup is done, I'll drop my first bank/credit card statement (CSV preferred). Scan it and show me every recurring charge you find.

4. After the scan, show me:
   - Total monthly subscription spend
   - Total annual projected spend
   - Any duplicate/overlapping services you spotted
   - Any charges I might not recognize (ghost subscriptions)

5. If I have Budget Buddy Pro installed, show me how to export my subscription data to it.

**Let's start with step 1.**

---

## After Setup

Once your first scan is complete, you can:

- Drop additional statements from other cards/banks to build a complete picture
- Say "add a trial" to track any free trials you're currently using
- Say "upcoming renewals" to see what's coming up
- Say "monthly summary" anytime for a full report
- Say "subscription audit" to review everything and decide what to keep or cancel

## Tips for Best Results

- **Use CSV over PDF** — CSV parsing is more reliable. Most banks let you export CSV from their transaction history page.
- **Scan 3 months of history** — More data = better pattern detection. One month might miss quarterly or annual charges.
- **Scan every card/account** — Subscriptions often spread across multiple payment methods. Scan them all.
- **Check back monthly** — Drop a fresh statement each month and say "compare statements" to catch new charges and price changes.
- **Tell the agent about trials** — It can't detect free trials from statements (no charge yet). Manually add them so you get reminded before they convert.

## Ongoing Usage

After setup, you'll get the most value by:

**Weekly:** Ask "upcoming renewals" to see what's coming. Takes 5 seconds.

**Monthly:** Drop your latest statement and say "compare statements" to catch new charges, missing charges (cancelled?), and price increases. Then say "monthly summary" for the full picture.

**Quarterly:** Say "find duplicates" to check for overlapping services. Useful after adding new subscriptions.

**Annually:** Say "subscription audit" for a full walkthrough of every subscription. Keep, review, or cancel each one.

## Need Help?

Say any of these to your agent:
- "Show my subscriptions" — see everything being tracked
- "Find duplicates" — check for overlapping services
- "Cancel [service name]" — get step-by-step cancellation instructions
- "How much am I saving?" — see your running savings from cancelled subs
- "Export my subs" — get a CSV or markdown export
- "Add a trial" — track a free trial before it converts to paid
- "Upcoming renewals" — see what's renewing in the next 7 days
- "Subscription audit" — full review of all subscriptions


path: config/settings.json
content: {
  "version": "1.0.0",
  "alerts": {
    "days_before_renewal": [3, 7],
    "monthly_summary_day": 1,
    "annual_audit_month": 1,
    "enable_price_change_alerts": true,
    "enable_overlap_alerts": true,
    "enable_ghost_alerts": true
  },
  "currency": "USD",
  "categories": {
    "streaming": {
      "label": "Streaming Video",
      "emoji": "🎬",
      "budget_buddy_category": "streaming"
    },
    "music": {
      "label": "Music",
      "emoji": "🎵",
      "budget_buddy_category": "streaming"
    },
    "ai_tools": {
      "label": "AI Tools",
      "emoji": "🤖",
      "budget_buddy_category": "subscriptions_software"
    },
    "cloud_storage": {
      "label": "Cloud Storage",
      "emoji": "☁️",
      "budget_buddy_category": "subscriptions_software"
    },
    "productivity": {
      "label": "Productivity",
      "emoji": "🔧",
      "budget_buddy_category": "subscriptions_software"
    },
    "fitness": {
      "label": "Fitness",
      "emoji": "💪",
      "budget_buddy_category": "fitness"
    },
    "news": {
      "label": "News & Media",
      "emoji": "📰",
      "budget_buddy_category": "subscriptions_media"
    },
    "gaming": {
      "label": "Gaming",
      "emoji": "🎮",
      "budget_buddy_category": "entertainment"
    },
    "vpn": {
      "label": "VPN & Security",
      "emoji": "🔒",
      "budget_buddy_category": "subscriptions_software"
    },
    "design": {
      "label": "Design",
      "emoji": "🎨",
      "budget_buddy_category": "subscriptions_software"
    },
    "education": {
      "label": "Education & Learning",
      "emoji": "📚",
      "budget_buddy_category": "education"
    },
    "health": {
      "label": "Health & Wellness",
      "emoji": "🧘",
      "budget_buddy_category": "health"
    },
    "email": {
      "label": "Email",
      "emoji": "📧",
      "budget_buddy_category": "subscriptions_software"
    },
    "food_delivery": {
      "label": "Food & Delivery",
      "emoji": "🍕",
      "budget_buddy_category": "dining"
    },
    "other": {
      "label": "Other",
      "emoji": "📦",
      "budget_buddy_category": "miscellaneous"
    }
  },
  "known_subscriptions": {
    "netflix": {
      "name": "Netflix",
      "patterns": ["NETFLIX", "NFLX"],
      "category": "streaming",
      "cancel_url": "https://www.netflix.com/cancelplan",
      "cancel_steps": "Account → Cancel Membership → Finish Cancellation",
      "gotchas": "Will offer discounted plan. Viewing history saved 10 months."
    },
    "spotify": {
      "name": "Spotify",
      "patterns": ["SPOTIFY"],
      "category": "music",
      "cancel_url": "https://www.spotify.com/account/subscription/",
      "cancel_steps": "Account → Subscription → Change plan → Cancel Premium",
      "gotchas": "Keeps your playlists. Reverts to free tier with ads."
    },
    "hulu": {
      "name": "Hulu",
      "patterns": ["HULU"],
      "category": "streaming",
      "cancel_url": "https://secure.hulu.com/account",
      "cancel_steps": "Account → Cancel → Continue to Cancel → Yes Cancel",
      "gotchas": "May offer pause instead of cancel. Access until period ends."
    },
    "disney_plus": {
      "name": "Disney+",
      "patterns": ["DISNEY+", "DISNEYPLUS", "DIS*DISNEY"],
      "category": "streaming",
      "cancel_url": "https://www.disneyplus.com/account",
      "cancel_steps": "Account → Subscription → Cancel Subscription",
      "gotchas": "Check if part of a bundle (Hulu/ESPN+) first."
    },
    "hbo_max": {
      "name": "Max (HBO)",
      "patterns": ["HBO", "MAX.COM", "WARNERMEDIA"],
      "category": "streaming",
      "cancel_url": "https://www.max.com/account",
      "cancel_steps": "Settings → Subscription → Manage → Cancel Subscription",
      "gotchas": "May be bundled through cable provider — check there first."
    },
    "apple": {
      "name": "Apple (iCloud/Apple One)",
      "patterns": ["APPLE.COM/BILL", "APPLE.COM"],
      "category": "cloud_storage",
      "cancel_url": "https://support.apple.com/en-us/HT202039",
      "cancel_steps": "Settings → [your name] → Subscriptions → select sub → Cancel",
      "gotchas": "Apple.com/bill covers iCloud, Apple One, Apple TV+, Music, Arcade — check which."
    },
    "amazon_prime": {
      "name": "Amazon Prime",
      "patterns": ["AMZN PRIME", "AMAZON PRIME", "AMZN MKTP"],
      "category": "streaming",
      "cancel_url": "https://www.amazon.com/mc/pipelines/cancellation",
      "cancel_steps": "Account → Prime Membership → Manage → End Membership",
      "gotchas": "Offers partial refund if unused. Losing free shipping + Prime Video."
    },
    "youtube_premium": {
      "name": "YouTube Premium",
      "patterns": ["GOOGLE *YOUTUBE", "YOUTUBE PREMIUM"],
      "category": "streaming",
      "cancel_url": "https://www.youtube.com/paid_memberships",
      "cancel_steps": "Settings → Purchases and memberships → Manage → Deactivate",
      "gotchas": "Also cancels YouTube Music if bundled. Family plan cancels for everyone."
    },
    "chatgpt": {
      "name": "ChatGPT Plus",
      "patterns": ["OPENAI", "CHATGPT"],
      "category": "ai_tools",
      "cancel_url": "https://chat.openai.com/#settings/subscription",
      "cancel_steps": "Settings → Subscription → Manage → Cancel plan",
      "gotchas": "Reverts to free tier. Conversation history preserved."
    },
    "claude": {
      "name": "Claude Pro",
      "patterns": ["CLAUDE.AI", "ANTHROPIC"],
      "category": "ai_tools",
      "cancel_url": "https://claude.ai/settings/billing",
      "cancel_steps": "Settings → Billing → Cancel subscription",
      "gotchas": "Reverts to free tier with limited usage."
    },
    "microsoft_365": {
      "name": "Microsoft 365",
      "patterns": ["MSFT*MICROSOFT", "MICROSOFT*", "MICROSOFT 365"],
      "category": "productivity",
      "cancel_url": "https://account.microsoft.com/services/",
      "cancel_steps": "Microsoft Account → Services & subscriptions → Cancel",
      "gotchas": "Lose 1TB OneDrive storage. Download files first. Office apps revert to read-only."
    },
    "adobe_cc": {
      "name": "Adobe Creative Cloud",
      "patterns": ["ADOBE", "ADOBE *CREATIVE"],
      "category": "design",
      "cancel_url": "https://account.adobe.com/plans",
      "cancel_steps": "Plans → Manage Plan → Cancel Plan → Choose reason → Confirm",
      "gotchas": "Annual plans have 50% early termination fee on remaining months."
    },
    "dropbox": {
      "name": "Dropbox",
      "patterns": ["DROPBOX"],
      "category": "cloud_storage",
      "cancel_url": "https://www.dropbox.com/account/plan",
      "cancel_steps": "Settings → Plan → Downgrade → Confirm",
      "gotchas": "Files over 2GB free limit may become inaccessible. Download first."
    },
    "github": {
      "name": "GitHub",
      "patterns": ["GITHUB"],
      "category": "productivity",
      "cancel_url": "https://github.com/settings/billing",
      "cancel_steps": "Settings → Billing → Plans → Downgrade",
      "gotchas": "Private repos become limited. Actions minutes reduced."
    },
    "nordvpn": {
      "name": "NordVPN",
      "patterns": ["NORDVPN", "NORD VPN"],
      "category": "vpn",
      "cancel_url": "https://my.nordaccount.com/dashboard/nordvpn/",
      "cancel_steps": "Dashboard → NordVPN → Auto-renewal → Cancel",
      "gotchas": "30-day money-back guarantee on annual plans. Access continues until period ends."
    },
    "notion": {
      "name": "Notion",
      "patterns": ["NOTION"],
      "category": "productivity",
      "cancel_url": "https://www.notion.so/my-account",
      "cancel_steps": "Settings → Plans → Downgrade to Free",
      "gotchas": "Free tier has block limits. Export your workspace first if large."
    },
    "figma": {
      "name": "Figma",
      "patterns": ["FIGMA"],
      "category": "design",
      "cancel_url": "https://www.figma.com/settings",
      "cancel_steps": "Settings → Account → Plan → Downgrade to Starter",
      "gotchas": "Team files become view-only on free tier."
    },
    "zoom": {
      "name": "Zoom",
      "patterns": ["ZOOM.US", "ZOOM VIDEO"],
      "category": "productivity",
      "cancel_url": "https://zoom.us/account",
      "cancel_steps": "Account → Plan Management → Cancel Plan",
      "gotchas": "Reverts to 40-min meeting limit on free tier."
    },
    "duolingo": {
      "name": "Duolingo Plus",
      "patterns": ["DUOLINGO"],
      "category": "education",
      "cancel_url": "https://www.duolingo.com/settings/subscription",
      "cancel_steps": "Settings → Subscription → Cancel",
      "gotchas": "Streak and progress preserved on free tier."
    },
    "grammarly": {
      "name": "Grammarly",
      "patterns": ["GRAMMARLY"],
      "category": "productivity",
      "cancel_url": "https://account.grammarly.com/subscription",
      "cancel_steps": "Account → Subscription → Cancel Subscription",
      "gotchas": "Annual plan: no partial refunds. Free tier still catches basic errors."
    },
    "headspace": {
      "name": "Headspace",
      "patterns": ["HEADSPACE"],
      "category": "health",
      "cancel_url": "https://www.headspace.com/settings/subscription",
      "cancel_steps": "Settings → Subscription → Cancel",
      "gotchas": "Some free content remains. Cancel through App Store/Play Store if subscribed there."
    },
    "calm": {
      "name": "Calm",
      "patterns": ["CALM.COM", "CALM APP"],
      "category": "health",
      "cancel_url": "https://www.calm.com/account",
      "cancel_steps": "Account → Subscription → Cancel Renewal",
      "gotchas": "Lifetime deal sometimes available. Check if employer offers free access."
    },
    "paramount_plus": {
      "name": "Paramount+",
      "patterns": ["PARAMOUNT"],
      "category": "streaming",
      "cancel_url": "https://www.paramountplus.com/account/",
      "cancel_steps": "Account → Subscription → Cancel",
      "gotchas": "Sometimes bundled with Walmart+ — check there first."
    },
    "peacock": {
      "name": "Peacock",
      "patterns": ["PEACOCK", "PEACCK"],
      "category": "streaming",
      "cancel_url": "https://www.peacocktv.com/account/subscription",
      "cancel_steps": "Account → Plan Details → Cancel Plan",
      "gotchas": "Some content free with ads on free tier."
    },
    "crunchyroll": {
      "name": "Crunchyroll",
      "patterns": ["CRUNCHYROLL"],
      "category": "streaming",
      "cancel_url": "https://www.crunchyroll.com/account/subscription",
      "cancel_steps": "Account → Premium Membership → Cancel",
      "gotchas": "Free tier has ads but still has content access."
    },
    "linkedin_premium": {
      "name": "LinkedIn Premium",
      "patterns": ["LINKEDIN"],
      "category": "productivity",
      "cancel_url": "https://www.linkedin.com/mypreferences/d/manage-premium",
      "cancel_steps": "Settings → Account → Subscriptions → Cancel premium",
      "gotchas": "InMail credits expire. Profile badge removed. Will offer discount to stay."
    },
    "audible": {
      "name": "Audible",
      "patterns": ["AUDIBLE"],
      "category": "education",
      "cancel_url": "https://www.audible.com/account/overview",
      "cancel_steps": "Account Details → Cancel membership → Continue",
      "gotchas": "Keep purchased audiobooks forever. Unused credits lost. Will offer 3 months at $7.95."
    },
    "siriusxm": {
      "name": "SiriusXM",
      "patterns": ["SIRIUSXM", "SXM*"],
      "category": "music",
      "cancel_url": "https://www.siriusxm.com/manage-subscription",
      "cancel_steps": "Must call 1-866-635-2349 or chat — no self-service cancel online",
      "gotchas": "Notoriously hard to cancel. Be firm. Say 'cancel' not 'thinking about it'. They will offer discounts."
    },
    "planet_fitness": {
      "name": "Planet Fitness",
      "patterns": ["PLANET FITNESS", "PLT FTNS"],
      "category": "fitness",
      "cancel_url": null,
      "cancel_steps": "Must cancel in person at home club OR send certified letter. Cannot cancel online or by phone.",
      "gotchas": "Requires 30-day notice. Annual fee may still apply. In-person or certified mail only."
    },
    "peloton": {
      "name": "Peloton",
      "patterns": ["PELOTON"],
      "category": "fitness",
      "cancel_url": "https://members.onepeloton.com/settings/subscription",
      "cancel_steps": "Settings → Subscriptions → Cancel Membership",
      "gotchas": "App membership vs. All-Access membership are different. Hardware financing continues regardless."
    },
    "canva": {
      "name": "Canva Pro",
      "patterns": ["CANVA"],
      "category": "design",
      "cancel_url": "https://www.canva.com/settings/billing-and-plans",
      "cancel_steps": "Settings → Billing & plans → Cancel plan",
      "gotchas": "Lose access to premium templates and Brand Kit. Download designs first."
    }
  },
  "overlap_groups": {
    "streaming_video": ["netflix", "hulu", "disney_plus", "hbo_max", "amazon_prime", "youtube_premium", "paramount_plus", "peacock", "crunchyroll"],
    "streaming_music": ["spotify", "youtube_premium", "siriusxm"],
    "cloud_storage": ["apple", "dropbox", "microsoft_365"],
    "ai_tools": ["chatgpt", "claude"],
    "vpn": ["nordvpn"],
    "password_manager": [],
    "fitness": ["planet_fitness", "peloton"],
    "meditation": ["headspace", "calm"],
    "design": ["figma", "adobe_cc", "canva"],
    "learning": ["duolingo"],
    "productivity": ["notion", "microsoft_365", "grammarly"]
  },
  "merchant_prefixes_to_strip": [
    "TST*", "SQ *", "SQ*", "GOOGLE *", "GOOGLE*", "MSFT*", "DIS*",
    "AMZN ", "APPLE.COM/", "SXM*", "PEACCK*", "CKO*", "SP *",
    "PP*", "PAYPAL *", "FS *", "WPY*", "IN *", "APL*", "BN*"
  ]
}


path: dashboard-kit/DASHBOARD-SPEC.md
content: # Dashboard Spec — Subscription Tracker

> Widget specifications for the NormieClaw dashboard integration.

---

## Overview

The Subscription Tracker publishes 8 widgets to the NormieClaw dashboard. All widgets read from `~/.normieclaw/subscription-tracker/subscriptions.json` and use the `st_` prefix.

Refresh interval: daily (or on-demand after statement scans).

---

## Widget Specifications

### st_monthly_spend — Monthly Subscription Total

**Type:** Stat card
**Size:** Small (1x1)

Displays the total monthly cost of all active subscriptions. Annual subscriptions are divided by 12 and included in the total.

**Calculation:**
```
monthly = sum of all active subscriptions where frequency = "monthly"
annual_monthly = sum of all active subscriptions where frequency = "annual" / 12
weekly_monthly = sum of all active subscriptions where frequency = "weekly" * 4.33
total = monthly + annual_monthly + weekly_monthly
```

**Display:** `$187.43` with trend arrow comparing to previous month.
**Trend:** Lower is better (green arrow down, red arrow up).

---

### st_annual_spend — Annual Projected Spend

**Type:** Stat card
**Size:** Small (1x1)

Projects total annual subscription spend based on current active subscriptions.

**Calculation:**
```
annual = sum of all active monthly subscriptions * 12
       + sum of all active annual subscriptions
       + sum of all active weekly subscriptions * 52
```

**Display:** `$2,249.16`
**Trend:** Lower is better.

---

### st_sub_count — Active Subscription Count

**Type:** Stat card
**Size:** Small (1x1)

Count of all subscriptions with `status: "active"`.

**Display:** `12`
**Trend:** Neutral (no color coding).

---

### st_savings — Annual Savings from Cancellations

**Type:** Stat card
**Size:** Small (1x1)

Sum of `annual_savings` from all entries in the `cancelled` array.

**Calculation:**
```
savings = sum of cancelled[].annual_savings
```

**Display:** `$719.88` in green.
**Trend:** Higher is better (always green). Highlight color: `#22c55e`.

---

### st_category_breakdown — Spend by Category (Pie Chart)

**Type:** Pie chart
**Size:** Medium (2x1)

Groups active subscriptions by category and sums their monthly amounts. Each category gets a consistent color from the manifest.

**Segments:** One per category with at least one active subscription.
**Labels:** Category name + dollar amount + percentage.
**Sort:** Largest segment first (clockwise).

**Example segments:**
- 🎬 Streaming: $45.97 (25%)
- 💪 Fitness: free.99 (27%)
- 🤖 AI Tools: $20.00 (11%)
- 🔧 Productivity: $42.50 (23%)
- 🎵 Music: $11.99 (6%)
- ☁️ Cloud: $2.99 (2%)
- 📰 News: $13.99 (7%)

---

### st_upcoming_renewals — Upcoming Renewals List

**Type:** List/table
**Size:** Medium (2x1)

Shows all active subscriptions with `next_renewal` within the next 7 days, sorted by date.

**Columns:**
| Column | Source | Format |
|--------|--------|--------|
| Date | `next_renewal` | MMM DD |
| Service | `service` | Text |
| Amount | `amount` | $XX.XX |

**Max items:** 10
**Empty state:** "No renewals in the next 7 days ✅"
**Footer:** Total amount of upcoming renewals.

---

### st_price_changes — Recent Price Changes

**Type:** List/table
**Size:** Medium (2x1)

Shows subscriptions where the current amount differs from the previous charge (detected via `previous_amounts` array).

**Columns:**
| Column | Source | Format |
|--------|--------|--------|
| Service | `service` | Text |
| Was | `previous_amounts[-2]` | $XX.XX |
| Now | `amount` | $XX.XX |
| Change | calculated | +$X.XX (red) or -$X.XX (green) |

**Max items:** 5
**Empty state:** "No price changes detected"

---

### st_trend — Monthly Spend Trend (Line Chart)

**Type:** Line chart
**Size:** Large (2x2)

Shows total monthly subscription spend over the last 6 months. Requires the agent to maintain a `monthly_totals` history in the database (appended each month during the monthly summary).

**X-axis:** Month labels (Oct, Nov, Dec, Jan, Feb, Mar)
**Y-axis:** Dollar amount ($0 – auto-scaled max)
**Line color:** `#3b82f6` (blue)
**Data points:** Show value on hover.
**Annotations:** Mark months where subscriptions were added or cancelled.

**Data structure (stored in subscriptions.json):**
```json
{
  "monthly_totals": [
    { "month": "2025-10", "total": 156.43, "count": 10 },
    { "month": "2025-11", "total": 162.43, "count": 11 },
    { "month": "2025-12", "total": 162.43, "count": 11 },
    { "month": "2026-01", "total": 187.43, "count": 12 },
    { "month": "2026-02", "total": 187.43, "count": 12 },
    { "month": "2026-03", "total": 127.44, "count": 9 }
  ]
}
```

---

## Layout Recommendation

Dashboard grid layout (4 columns):

```
┌──────────────┬──────────────┬──────────────┬──────────────┐
│ st_monthly   │ st_annual    │ st_sub_count │ st_savings   │
│ $187.43      │ $2,249.16    │ 12           │ $719.88      │
├──────────────┴──────────────┼──────────────┴──────────────┤
│ st_category_breakdown       │ st_upcoming_renewals        │
│ [pie chart]                 │ Mar 27 Spotify    $11.99    │
│                             │ Mar 28 Adobe CC   $59.99    │
│                             │ Mar 30 NordVPN    $12.99    │
├──────────────┬──────────────┴──────────────────────────────┤
│ st_price     │ st_trend                                    │
│ changes      │ [line chart - 6 month trend]                │
│              │                                             │
└──────────────┴─────────────────────────────────────────────┘
```

---

## Data Refresh

Widgets refresh when:
1. **Daily cron:** `renewal-check.sh` runs and updates renewal dates
2. **Statement scan:** User uploads a new statement, triggering a full database update
3. **Manual action:** User adds, cancels, or modifies a subscription
4. **Monthly summary:** First of each month, monthly totals history is updated

The agent should update `subscriptions.json` → `last_updated` timestamp after any modification. Dashboard reads this field to determine if a refresh is needed.


path: dashboard-kit/manifest.json
content: {
  "tool": "subscription-tracker",
  "version": "1.0.0",
  "prefix": "st_",
  "display_name": "Subscription Tracker",
  "description": "Track and manage recurring subscriptions from bank statements",
  "data_source": "~/.normieclaw/subscription-tracker/subscriptions.json",
  "refresh_interval": "daily",
  "widgets": [
    {
      "id": "st_monthly_spend",
      "type": "stat",
      "label": "Monthly Subscriptions",
      "description": "Total monthly subscription spend across all active subscriptions",
      "unit": "currency",
      "query": "sum(subscriptions[status=active, frequency=monthly].amount) + sum(subscriptions[status=active, frequency=annual].amount / 12)",
      "format": "$%.2f",
      "trend": "lower_is_better",
      "size": "small"
    },
    {
      "id": "st_annual_spend",
      "type": "stat",
      "label": "Annual Projected",
      "description": "Projected annual subscription spend",
      "unit": "currency",
      "query": "sum(subscriptions[status=active, frequency=monthly].amount * 12) + sum(subscriptions[status=active, frequency=annual].amount)",
      "format": "$%.2f",
      "trend": "lower_is_better",
      "size": "small"
    },
    {
      "id": "st_sub_count",
      "type": "stat",
      "label": "Active Subscriptions",
      "description": "Number of active tracked subscriptions",
      "query": "count(subscriptions[status=active])",
      "format": "%d",
      "trend": "neutral",
      "size": "small"
    },
    {
      "id": "st_savings",
      "type": "stat",
      "label": "Annual Savings",
      "description": "Total annual savings from cancelled subscriptions",
      "unit": "currency",
      "query": "sum(cancelled[].annual_savings)",
      "format": "$%.2f",
      "trend": "higher_is_better",
      "highlight_color": "#22c55e",
      "size": "small"
    },
    {
      "id": "st_category_breakdown",
      "type": "pie",
      "label": "Spend by Category",
      "description": "Subscription spend broken down by category",
      "query": "group_by(subscriptions[status=active], category, sum(amount))",
      "colors": {
        "streaming": "#ef4444",
        "music": "#8b5cf6",
        "ai_tools": "#3b82f6",
        "cloud_storage": "#06b6d4",
        "productivity": "#f59e0b",
        "fitness": "#22c55e",
        "news": "#6366f1",
        "gaming": "#ec4899",
        "vpn": "#14b8a6",
        "design": "#f97316",
        "education": "#a855f7",
        "health": "#10b981",
        "other": "#6b7280"
      },
      "size": "medium"
    },
    {
      "id": "st_upcoming_renewals",
      "type": "list",
      "label": "Upcoming Renewals",
      "description": "Subscriptions renewing in the next 7 days",
      "query": "subscriptions[status=active, next_renewal <= today+7d] | sort_by(next_renewal)",
      "columns": ["next_renewal:Date", "service:Service", "amount:Amount"],
      "max_items": 10,
      "empty_message": "No renewals in the next 7 days ✅",
      "size": "medium"
    },
    {
      "id": "st_price_changes",
      "type": "list",
      "label": "Recent Price Changes",
      "description": "Subscriptions where the last charge differed from the previous amount",
      "query": "subscriptions[status=active, len(previous_amounts) > 1, previous_amounts[-1] != previous_amounts[-2]]",
      "columns": ["service:Service", "previous_amounts[-2]:Was", "amount:Now", "delta:Change"],
      "max_items": 5,
      "empty_message": "No price changes detected",
      "size": "medium"
    },
    {
      "id": "st_trend",
      "type": "line",
      "label": "Monthly Spend Trend",
      "description": "Total monthly subscription spend over time",
      "query": "timeseries(monthly_totals, 6m)",
      "x_axis": "month",
      "y_axis": "total_spend",
      "y_format": "$%.0f",
      "color": "#3b82f6",
      "size": "large"
    }
  ]
}


path: examples/example-overlap-detection.md
content: # Example: Overlap Detection

> Agent finds duplicate services costing the user money.

---

## Scenario

Marcus has been tracking subscriptions for 2 months. He just scanned his Amex statement and his agent merged the findings with his existing database. The agent runs overlap detection.

---

## Conversation

**Agent:**

I've merged your Amex Gold statement with your existing subscriptions from Chase. Here's your complete picture:

📊 **Full Subscription Dashboard — All Accounts**

**Monthly total: $247.91 across 14 subscriptions**
**Annual projected: $2,974.92**

I ran an overlap check and found 3 issues worth looking at:

---

⚠️ **OVERLAP #1: Streaming Video — $55.96/month ($671.52/year)**

You have 4 video streaming services:

| Service | Cost | Card |
|---------|------|------|
| Netflix (Standard) | $17.99/mo | Chase Visa |
| Hulu (No Ads) | $17.99/mo | Amex Gold |
| Disney+ | $9.99/mo | Amex Gold |
| Peacock Premium | $9.99/mo | Chase Visa |

💡 **Suggestions:**
- **Disney Bundle** (Disney+, Hulu, ESPN+) is $16.99/mo — saves $10.99/mo vs. separate Disney+ and Hulu
- **Rotate strategy:** Watch one service per month, switch next month. Most content stays.
- Netflix and Hulu have the most content overlap for drama/comedy
- Peacock is the most expendable unless you watch NBC sports or specific Peacock originals

If you dropped Peacock and switched to the Disney Bundle: **saves $20.98/month ($251.76/year)**

---

⚠️ **OVERLAP #2: Cloud Storage — $12.99/month ($155.88/year)**

You're paying for storage in 3 places:

| Service | Storage | Cost | Card |
|---------|---------|------|------|
| iCloud+ | 200GB | $2.99/mo | Chase Visa |
| Google One | 100GB | $2.99/mo | Amex Gold |
| Dropbox Plus | 2TB | $6.99/mo (annual plan) | Amex Gold |

💡 **Suggestions:**
- If you're an iPhone user, iCloud+ covers photos and device backup. Do you also need Google One?
- Dropbox Plus gives 2TB — that likely covers everything. iCloud's 200GB might be redundant.
- **Consolidate to one:** Pick your primary (Dropbox for cross-platform, iCloud for Apple ecosystem) and cancel the others.
- Dropping Google One + iCloud: **saves $5.98/month ($71.76/year)**
- Dropping Google One alone: **saves $2.99/month ($35.88/year)**

---

⚠️ **OVERLAP #3: AI Tools — $40.00/month ($480.00/year)**

| Service | Cost | Card |
|---------|------|------|
| ChatGPT Plus | $20.00/mo | Chase Visa |
| Claude Pro | $20.00/mo | Amex Gold |

💡 **Note:**
These aren't identical — ChatGPT and Claude have different strengths. But $40/month on AI chat tools is worth evaluating.
- Do you use both regularly? If one covers 90% of your needs, the other might be cuttable.
- Some users alternate months — Claude one month, ChatGPT the next.
- No pressure to cut either if you use both actively. Just flagging the combined spend.

---

📊 **Potential Savings Summary**

| Action | Monthly Savings | Annual Savings |
|--------|----------------|----------------|
| Switch to Disney Bundle + drop Peacock | $20.98 | $251.76 |
| Drop Google One | $2.99 | $35.88 |
| Drop one AI tool | $20.00 | $240.00 |
| **Total if all** | **$43.97** | **$527.64** |

None of these are mandatory — your call on each. Want to dig into any of them?

---

**Marcus:** Wow, the Disney Bundle is a no-brainer. Do that. And yeah, drop Google One — I only use Dropbox and iCloud. Keep both AI tools for now.

**Agent:**

Got it. Here's what to do:

🚪 **Action 1: Switch to Disney Bundle**

1. Cancel Disney+ standalone: Account → disneyplus.com/account → Cancel
2. Cancel Hulu standalone: Account → secure.hulu.com/account → Cancel
3. Sign up for Disney Bundle at disneyplus.com/bundle ($16.99/mo — includes Disney+, Hulu No Ads, ESPN+)
4. Cancel Peacock: peacocktv.com/account → Plan Details → Cancel

Let me know once done and I'll update your tracker.

🚪 **Action 2: Cancel Google One**

1. Go to one.google.com/settings
2. Click "Cancel membership"
3. Confirm cancellation

Your Google Drive reverts to the free 15GB tier. Make sure you're under 15GB or move files to Dropbox first.

💰 **Combined savings: $23.97/month ($287.64/year)**

---

**Marcus:** Done with Google One. Working on the streaming switches this weekend.

**Agent:**

Updated! Google One moved to cancelled. Annual savings tracker: **$35.88/year so far.**

I'll remind you about the streaming switches next week. Your current monthly total dropped to $244.92.


path: examples/example-renewal-alert.md
content: # Example: Renewal Alerts & Trial Tracking

> Agent reminds you before renewals hit and free trials convert to paid.

---

## Scenario

Jamie has 8 active subscriptions and 2 free trials being tracked. It's March 25, 2026, and several renewals are coming up in the next week. One free trial is about to expire.

---

## Conversation

**Agent:**

📅 **Upcoming Renewals — Next 7 Days (Mar 25 – Apr 1)**

| Date | Service | Amount | Card |
|------|---------|--------|------|
| Mar 27 | Spotify Premium | $11.99 | Visa 4821 |
| Mar 28 | Adobe Creative Cloud | $59.99 | Amex 1004 |
| Mar 30 | NordVPN | $12.99 | Visa 4821 |
| Apr 1 | iCloud+ | $2.99 | Visa 4821 |

**Total upcoming: $87.96**

---

🔔 **TRIAL ALERT: Hulu Free Trial**

Your Hulu free trial ends in **3 days** (March 28).

If you don't cancel, you'll be charged **$17.99/month** starting March 28.

**Options:**
- ✅ **Keep it** — I'll add Hulu as an active subscription ($17.99/mo)
- ❌ **Cancel it** — Go to secure.hulu.com/account → Cancel → Continue to Cancel

Have you been watching enough Hulu to justify $17.99/month? You already have Netflix ($17.99/mo) and Disney+ ($9.99/mo) — that would put your streaming total at $45.97/month.

---

**Jamie:** Actually, I'm barely using Adobe anymore. I switched to Figma and Canva months ago. How do I cancel that?

**Agent:**

Good catch — $59.99/month is a big one. Let's get you out of it.

🚪 **HOW TO CANCEL: Adobe Creative Cloud — $59.99/mo**

1. Go to: https://account.adobe.com/plans
2. Click "Manage Plan" next to Creative Cloud
3. Click "Cancel Plan"
4. Choose a reason (pick whatever)
5. Adobe will show you retention offers — decline to continue
6. Confirm cancellation

⚠️ **Important gotcha:** Check your plan type first.
- **Month-to-month plan:** Cancels at end of current period. No fee.
- **Annual plan (paid monthly):** Has an **early termination fee of 50% of remaining months**. If you're 6 months into a 12-month plan, that's ~$180 in fees.

To check: look at your plan details on the Adobe account page. If it says "Annual plan, paid monthly" and you're mid-contract, it might be worth riding it out to the renewal date and cancelling then.

**Before cancelling:**
- Download any files from Creative Cloud storage
- Export any Adobe Fonts you're using in active projects
- Save any Lightroom presets/catalogs locally

💰 Cancelling saves you: **$59.99/month ($719.88/year)** — your biggest single subscription.

---

**Jamie:** It's month-to-month, thankfully. I'll cancel tonight. And cancel the Hulu trial too — not worth adding another streaming service.

**Agent:**

Smart moves on both.

Updated your tracker:

**Adobe Creative Cloud:**
- Moved to cancelled
- Savings: $719.88/year
- Access continues until March 28 (end of current billing period)

**Hulu Free Trial:**
- Marked as cancelled (not converting)
- Remember to actually cancel at secure.hulu.com/account before March 28

📊 **Impact:**

| Before | After |
|--------|-------|
| Monthly total: free4.93 | Monthly total: $134.94 |
| Annual projected: $2,339.16 | Annual projected: $1,619.28 |

**You just cut your subscription spend by 31%.** 🎯

Running savings from all cancellations: **$779.76/year**

---

*[One week later]*

**Agent:**

📅 **Weekly Renewal Check — Apr 1–7, 2026**

| Date | Service | Amount | Card |
|------|---------|--------|------|
| Apr 3 | Spotify Premium | $11.99 | Visa 4821 |
| Apr 5 | ChatGPT Plus | $20.00 | Visa 4821 |

**Total upcoming: $31.99**

🔺 **PRICE CHANGE ALERT:**

I compared your latest Visa statement to last month. One change detected:

**Spotify Premium:** $10.99 → $11.99 (+$1.00/mo, +9.1%)
Annual impact: +$12.00/year

Spotify raised prices across all plans in March 2026. Your new annual Spotify cost: $143.88.

---

**Jamie:** Ugh, another Spotify increase. Is YouTube Music the same price?

**Agent:**

YouTube Premium (which includes YouTube Music) is currently **$13.99/month** — so $2.00 more than Spotify.

However, YouTube Premium includes:
- YouTube Music (equivalent to Spotify)
- Ad-free YouTube videos
- Background play on mobile
- YouTube Originals

If you watch YouTube regularly, it might be worth the extra $2/month for the ad-free experience. If you only need music, Spotify at $11.99 is still cheaper.

Other options:
- Apple Music: $10.99/mo (cheaper, but no free tier to fall back on)
- Amazon Music Unlimited: $9.99/mo ($8.99 for Prime members)

Want me to track any of these as considerations for your next subscription audit?


path: examples/example-statement-scan.md
content: # Example: Statement Scan

> Drop a bank statement, find every subscription hiding in it.

---

## Scenario

Sarah downloads her Chase Visa statement for January–March 2026 as a CSV and sends it to her OpenClaw agent.

---

## Conversation

**Sarah:** Here's my Chase Visa statement for the last 3 months. Find all my subscriptions.

*[Uploads: chase-visa-jan-mar-2026.csv]*

**Agent:**

Scanning your Chase Visa statement (Jan 1 – Mar 11, 2026)... Found 247 transactions. Analyzing for recurring charges.

📋 **Statement Scan Results — Chase Visa ending 4821**

🟢 **HIGH CONFIDENCE** (matched 3+ times, consistent amount & timing):

| Service | Amount | Frequency | Next Renewal |
|---------|--------|-----------|--------------|
| Netflix | $17.99/mo | Monthly | Apr 15 |
| Spotify Premium | $11.99/mo | Monthly | Apr 3 |
| ChatGPT Plus | $20.00/mo | Monthly | Apr 8 |
| iCloud+ (Apple) | $2.99/mo | Monthly | Apr 1 |
| Planet Fitness | $26.99/mo | Monthly | Apr 5 |
| Notion | $10.00/mo | Monthly | Apr 12 |

🟡 **NEEDS YOUR REVIEW** (2 matches or unclear pattern):

1. **AMZN MKTP US** — $14.99 on Jan 22, $14.99 on Feb 22
   → Looks like Amazon Prime. Is this your Prime membership? **(Y/N)**

2. **SQ *CROSSFIT MILE HIGH** — $225.00 on Jan 3, $225.00 on Feb 3, $225.00 on Mar 3
   → Gym/fitness membership? **(Y/N)**

3. **GOOGLE *YOUTUBE** — $13.99 on Feb 18 (single charge)
   → YouTube Premium? Only one charge in 3 months — might be new. **(Y/N)**

🔴 **UNKNOWN RECURRING:**

4. **BRTCL*BRITEBOX** — $4.99 on Jan 8, $4.99 on Feb 8, $4.99 on Mar 8
   → I don't recognize this merchant. Do you? **(Identify / Skip / Ghost)**

5. **WIX.COM** — $16.00 on Feb 3 (single charge)
   → Wix website hosting? **(Y/N)**

---

**Sarah:** Yes to Amazon Prime. Yes to CrossFit. No to YouTube — that was a gift purchase. The Britebox one... I have no idea what that is. And yes to Wix.

**Agent:**

Updated! Here's your subscription dashboard:

📊 **Your Subscriptions — Chase Visa ending 4821**

| Service | Amount | Category |
|---------|--------|----------|
| CrossFit Mile High | $225.00/mo | 💪 Fitness |
| Planet Fitness | $26.99/mo | 💪 Fitness |
| ChatGPT Plus | $20.00/mo | 🤖 AI Tools |
| Netflix | $17.99/mo | 🎬 Streaming |
| Wix | $16.00/mo | 🔧 Productivity |
| Amazon Prime | $14.99/mo | 🎬 Streaming |
| Spotify Premium | $11.99/mo | 🎵 Music |
| Notion | $10.00/mo | 🔧 Productivity |
| iCloud+ | $2.99/mo | ☁️ Cloud Storage |

**Monthly total: $346.95**
**Annual projected: $4,163.40**

---

⚠️ **OVERLAP DETECTED: Fitness**

You have 2 gym/fitness subscriptions:
- CrossFit Mile High — $225.00/mo
- Planet Fitness — $26.99/mo

Combined: $251.99/month ($3,023.88/year) on fitness.

Do you use both? If CrossFit is your primary gym, Planet Fitness might be one to cut — that's $323.88/year back.

---

👻 **GHOST SUBSCRIPTION: BRTCL*BRITEBOX**

This has been charging $4.99/month since at least January. You've paid at least $14.97 for something you don't recognize.

Want me to help you figure out what this is and how to cancel it?

---

**Sarah:** Oh wow, I totally forgot about Planet Fitness. I haven't been since I started CrossFit in November. And yeah, figure out what Britebox is.

**Agent:**

Let me help with both.

🚪 **HOW TO CANCEL: Planet Fitness**

Unfortunately, Planet Fitness requires cancellation **in person** at your home club or via **certified mail**. No online or phone cancellation.

Steps:
1. Visit your home Planet Fitness location
2. Ask the front desk to cancel your membership
3. They'll process a 30-day notice — you'll have one more billing cycle
4. Alternatively: send a certified letter to your home club requesting cancellation

⚠️ If your annual fee is coming up (usually in June or November), try to cancel before it hits.

💰 Cancelling saves you: $26.99/month ($323.88/year)

---

🔍 **Investigating: BRTCL*BRITEBOX**

"Britebox" appears to be a meal kit/snack box subscription. The "BRTCL" prefix is their payment processor. Check your email for any signup confirmation from Britebox or a similar-sounding service.

If you want to cancel: search your email for "britebox" or "brite box" to find the account, then log in and cancel from their website.

---

**Sarah:** This is amazing. I just saved $30/month without even trying.

**Agent:**

$30.00/month = **$359.88/year**. 💰

Once you've confirmed both cancellations, let me know and I'll update your tracker. Your new monthly total will drop to $316.96.

Do you have statements from any other cards or bank accounts? Subscriptions tend to spread across multiple payment methods.


path: scripts/export-subs.sh
content: #!/usr/bin/env bash
set -euo pipefail

# Subscription Tracker — Export Script
# Exports subscription list as CSV, markdown, or Budget Buddy Pro format

ST_DIR="$HOME/.normieclaw/subscription-tracker"
DB_FILE="$ST_DIR/subscriptions.json"
EXPORT_DIR="$ST_DIR/exports"
FORMAT="${1:---format}"
FORMAT_VALUE="${2:-markdown}"
DATE_STAMP=$(date +%Y-%m-%d)

# Parse arguments
while [[ $# -gt 0 ]]; do
  case "$1" in
    --format)
      FORMAT_VALUE="${2:-markdown}"
      shift 2
      ;;
    --output|-o)
      CUSTOM_OUTPUT="${2:-}"
      shift 2
      ;;
    --help|-h)
      echo "Usage: export-subs.sh [--format csv|markdown|budget-buddy] [--output path]"
      echo ""
      echo "Formats:"
      echo "  csv           Comma-separated values"
      echo "  markdown      Markdown table (default)"
      echo "  budget-buddy  JSON for Budget Buddy Pro import"
      echo ""
      echo "Output: Saved to ~/.normieclaw/subscription-tracker/exports/"
      exit 0
      ;;
    *)
      shift
      ;;
  esac
done

# Verify database exists
if [[ ! -f "$DB_FILE" ]]; then
  echo "❌ No subscription database found at $DB_FILE"
  echo "   Run setup.sh first, then scan a statement."
  exit 1
fi

mkdir -p "$EXPORT_DIR"

# Check if jq is available
if ! command -v jq &>/dev/null; then
  echo "❌ jq is required for export. Install with: brew install jq (macOS) or apt install jq (Linux)"
  exit 1
fi

# Count active subscriptions
SUB_COUNT=$(jq '.subscriptions | length' "$DB_FILE")
if [[ "$SUB_COUNT" -eq 0 ]]; then
  echo "📭 No active subscriptions to export. Scan a statement first."
  exit 0
fi

case "$FORMAT_VALUE" in
  csv)
    OUTPUT_FILE="${CUSTOM_OUTPUT:-$EXPORT_DIR/$DATE_STAMP-subscriptions.csv}"
    echo "Service,Amount,Frequency,Category,Next Renewal,Payment Method,Status" > "$OUTPUT_FILE"
    jq -r '.subscriptions[] | [.service, .amount, .frequency, .category, .next_renewal, .payment_method, .status] | @csv' "$DB_FILE" >> "$OUTPUT_FILE"
    echo "✅ Exported $SUB_COUNT subscriptions to: $OUTPUT_FILE"
    ;;

  markdown)
    OUTPUT_FILE="${CUSTOM_OUTPUT:-$EXPORT_DIR/$DATE_STAMP-subscriptions.md}"
    {
      echo "# Subscription Report — $DATE_STAMP"
      echo ""
      MONTHLY_TOTAL=$(jq '[.subscriptions[] | select(.status == "active" and .frequency == "monthly") | .amount] | add // 0' "$DB_FILE")
      ANNUAL_SUBS=$(jq '[.subscriptions[] | select(.status == "active" and .frequency == "annual") | .amount] | add // 0' "$DB_FILE")
      ANNUAL_TOTAL=$(echo "$MONTHLY_TOTAL * 12 + $ANNUAL_SUBS" | bc 2>/dev/null || echo "0")
      echo "**Monthly total:** \$$MONTHLY_TOTAL"
      echo "**Annual projected:** \$$ANNUAL_TOTAL"
      echo "**Active subscriptions:** $SUB_COUNT"
      echo ""
      echo "| Service | Amount | Frequency | Category | Next Renewal |"
      echo "|---------|--------|-----------|----------|--------------|"
      jq -r '.subscriptions[] | select(.status == "active") | "| \(.service) | $\(.amount) | \(.frequency) | \(.category) | \(.next_renewal // "—") |"' "$DB_FILE"
      echo ""

      CANCELLED_COUNT=$(jq '.cancelled | length' "$DB_FILE")
      if [[ "$CANCELLED_COUNT" -gt 0 ]]; then
        TOTAL_SAVINGS=$(jq '[.cancelled[].annual_savings] | add // 0' "$DB_FILE")
        echo "## Cancelled Subscriptions"
        echo ""
        echo "**Total annual savings:** \$$TOTAL_SAVINGS"
        echo ""
        jq -r '.cancelled[] | "- ~~\(.service)~~ — $\(.amount)/\(.frequency // "mo") — cancelled \(.cancelled_date) — saving $\(.annual_savings)/yr"' "$DB_FILE"
        echo ""
      fi

      TRIAL_COUNT=$(jq '.trials | length' "$DB_FILE")
      if [[ "$TRIAL_COUNT" -gt 0 ]]; then
        echo "## Active Trials"
        echo ""
        jq -r '.trials[] | select(.status == "active") | "- **\(.service)** — trial ends \(.end_date) — converts to $\(.converts_to_amount)/\(.frequency)"' "$DB_FILE"
      fi
    } > "$OUTPUT_FILE"
    echo "✅ Exported $SUB_COUNT subscriptions to: $OUTPUT_FILE"
    ;;

  budget-buddy)
    OUTPUT_FILE="${CUSTOM_OUTPUT:-$EXPORT_DIR/$DATE_STAMP-budget-buddy-import.json}"
    MONTHLY_TOTAL=$(jq '[.subscriptions[] | select(.status == "active" and .frequency == "monthly") | .amount] | add // 0' "$DB_FILE")
    ANNUAL_SUBS=$(jq '[.subscriptions[] | select(.status == "active" and .frequency == "annual") | .amount] | add // 0' "$DB_FILE")
    ANNUAL_TOTAL=$(echo "$MONTHLY_TOTAL * 12 + $ANNUAL_SUBS" | bc 2>/dev/null || echo "0")

    jq --arg date "$DATE_STAMP" --argjson mt "$MONTHLY_TOTAL" --argjson at "$ANNUAL_TOTAL" '{
      source: "subscription-tracker",
      version: "1.0.0",
      exported_at: ($date + "T00:00:00Z"),
      monthly_recurring: [.subscriptions[] | select(.status == "active") | {
        name: .service,
        amount: .amount,
        category: .category,
        frequency: .frequency,
        next_charge: .next_renewal
      }],
      annual_total: $at,
      monthly_total: $mt
    }' "$DB_FILE" > "$OUTPUT_FILE"
    echo "✅ Exported $SUB_COUNT subscriptions in Budget Buddy format: $OUTPUT_FILE"
    echo "   Import this file into Budget Buddy Pro to sync your subscription data."
    ;;

  *)
    echo "❌ Unknown format: $FORMAT_VALUE"
    echo "   Supported: csv, markdown, budget-buddy"
    exit 1
    ;;
esac


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)