fleece-cli 0.3.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.agents/skills/fleece/SKILL.md +27 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-compare.md +12 -0
- fleece_cli-0.4.0/.claude/skills/fleece-profile.md +81 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-rates.md +10 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-recommend.md +16 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-wallet.md +17 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.github/workflows/publish.yml +3 -0
- fleece_cli-0.4.0/CLAUDE.md +123 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/PKG-INFO +1 -1
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/cli.py +111 -17
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/db.py +85 -0
- fleece_cli-0.4.0/docs/SEO.md +113 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/docs/index.html +112 -6
- fleece_cli-0.4.0/docs/robots.txt +4 -0
- fleece_cli-0.4.0/docs/sitemap.xml +9 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/install.sh +5 -3
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/pyproject.toml +1 -1
- fleece_cli-0.3.0/CLAUDE.md +0 -49
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-card.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-credits.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-flights.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-hotels.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-mcc.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-news.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-partners.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.claude/skills/fleece-roi.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.devcontainer/devcontainer.json +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.github/workflows/publish-skills.yml +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.gitignore +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/.streamlit/config.toml +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/Advertiser Disclosure.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/KnowledgeCatalog.json +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/LICENSE +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/MyCards.json +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/README.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/app.yaml +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/assets/default_card.png +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/assets/default_card.svg +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/docs/CNAME +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/fleece poc.ipynb +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/fleece.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/image_service.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/mcc_codes.jsonl +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/migrate.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/pages/credit_cards.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/pages/my_credit_cards.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/plan.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/pointsyeah.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/prompts/agent_system_prompt.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/reference/Analyzer.md +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/requirements-test.txt +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/requirements.txt +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/style.css +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/test_fleece.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tests/__init__.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tests/test_brave_client.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tests/test_cli.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tests/test_pointsyeah.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tests/test_tools.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tools/__init__.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tools/brave_client.py +0 -0
- {fleece_cli-0.3.0 → fleece_cli-0.4.0}/tools/credit_card_tools.py +0 -0
|
@@ -14,9 +14,36 @@ Use this skill when the user asks about:
|
|
|
14
14
|
- **Card recommendations**: "Best travel credit card for beginners", "No annual fee cash back card"
|
|
15
15
|
- **ROI / value**: "Is the Amex Platinum worth the $695 fee?", "First-year value of the Sapphire Preferred"
|
|
16
16
|
- **Award redemptions**: "Find business class flights JFK to Tokyo", "Search hotels in Paris with points"
|
|
17
|
+
- **Merchant lookup**: "What card should I use at Costco?", "Which card earns the most at gas stations?", "What MCC is a pharmacy?"
|
|
17
18
|
|
|
18
19
|
Live US credit card data via Brave Search. All commands output JSON for programmatic use.
|
|
19
20
|
|
|
21
|
+
## MCC-enriched workflow
|
|
22
|
+
|
|
23
|
+
The bundled MCC dataset (981 codes, offline) enables a precise end-to-end flow:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
fleece wallet → identify category gaps
|
|
27
|
+
fleece mcc 5411 → confirm "Grocery Stores, Supermarkets"
|
|
28
|
+
fleece mcc 5411 --wallet → find best card for that exact merchant type
|
|
29
|
+
fleece recommend "grocery stores, gas, transit" → suggest a card to fill the gap
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Common MCCs to know:**
|
|
33
|
+
|
|
34
|
+
| MCC | Category | Typical card bonus |
|
|
35
|
+
|------|----------|--------------------|
|
|
36
|
+
| 5411 | Grocery Stores | Amex Gold 4x, BofA Cash Rewards 3% |
|
|
37
|
+
| 5812 | Restaurants | Amex Gold 4x, CSP 3x |
|
|
38
|
+
| 5814 | Fast Food | Varies — not always same as 5812 |
|
|
39
|
+
| 5541 | Gas Stations | Citi Custom Cash 5x, BofA 3% |
|
|
40
|
+
| 4511 | Airlines | Amex Platinum 5x, CSR 3x |
|
|
41
|
+
| 7011 | Hotels | Amex Platinum 5x (Amex Travel), CSR 3x |
|
|
42
|
+
| 4111 | Transit / Commuter | CSR 3x, Bilt 3x |
|
|
43
|
+
| 5912 | Drugstores | Chase Freedom Flex 3x |
|
|
44
|
+
|
|
45
|
+
Use `fleece mcc <code>` (no API key needed) to resolve any MCC before running a rates or wallet query.
|
|
46
|
+
|
|
20
47
|
## Prerequisites
|
|
21
48
|
|
|
22
49
|
```bash
|
|
@@ -29,3 +29,15 @@ fleece compare "Capital One Venture X" "Chase Sapphire Reserve" --json
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
After receiving the result, synthesize a clear recommendation based on the user's stated priorities.
|
|
32
|
+
|
|
33
|
+
## MCC-precise comparison
|
|
34
|
+
|
|
35
|
+
When comparing two cards on rewards, use `fleece mcc` to identify the exact merchant category first — then compare on that specific category for a more accurate result:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# User wants to know which card earns more at Costco (a grocery/wholesale club)
|
|
39
|
+
fleece mcc 5411 # → Grocery Stores, Supermarkets
|
|
40
|
+
|
|
41
|
+
# Then compare with that category as the focus
|
|
42
|
+
fleece compare "Amex Gold" "Chase Sapphire Preferred" --aspects "grocery rewards,supermarket earning rate" --json
|
|
43
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fleece-profile
|
|
3
|
+
description: Manage the user's spending profile — monthly spend by category, annual fee tolerance, points programs, home airport, and redemption goal. Profile context is automatically injected into fleece wallet, fleece roi, and fleece recommend. Use when setting up or updating the user's preferences.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /fleece-profile
|
|
7
|
+
|
|
8
|
+
Manages the user's persistent spending profile stored in `fleece.db`. Once set, profile context is automatically injected into `fleece wallet`, `fleece roi`, and `fleece recommend` — no need to re-enter spend amounts each time.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
- User wants to set up their profile so research commands are personalised
|
|
12
|
+
- User updates their spending habits or preferences
|
|
13
|
+
- User asks why recommendations don't match their situation (profile may be empty or stale)
|
|
14
|
+
- Before running `fleece recommend` or `fleece roi` for the first time
|
|
15
|
+
|
|
16
|
+
## Profile fields
|
|
17
|
+
|
|
18
|
+
| Field | Description |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `dining_monthly` | Monthly dining spend ($) |
|
|
21
|
+
| `groceries_monthly` | Monthly groceries spend ($) |
|
|
22
|
+
| `travel_monthly` | Monthly travel spend ($) |
|
|
23
|
+
| `gas_monthly` | Monthly gas spend ($) |
|
|
24
|
+
| `other_monthly` | Monthly other spend ($) |
|
|
25
|
+
| `annual_fee_tolerance` | Max annual fee willing to pay ($) |
|
|
26
|
+
| `points_programs` | Preferred points programs (e.g. Amex MR, Chase UR) |
|
|
27
|
+
| `home_airport` | Home airport IATA code (e.g. JFK) |
|
|
28
|
+
| `goal` | Current redemption goal (e.g. business class to Tokyo) |
|
|
29
|
+
| `preferences` | Other preferences (e.g. no foreign transaction fees) |
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# See all available fields
|
|
35
|
+
fleece profile fields
|
|
36
|
+
|
|
37
|
+
# Show current profile
|
|
38
|
+
fleece profile show
|
|
39
|
+
fleece profile show --json
|
|
40
|
+
|
|
41
|
+
# Set fields
|
|
42
|
+
fleece profile set dining_monthly 600
|
|
43
|
+
fleece profile set travel_monthly 300
|
|
44
|
+
fleece profile set annual_fee_tolerance 550
|
|
45
|
+
fleece profile set points_programs "Amex MR, Chase UR"
|
|
46
|
+
fleece profile set home_airport JFK
|
|
47
|
+
fleece profile set goal "business class to Tokyo, June 2027"
|
|
48
|
+
|
|
49
|
+
# Clear a field
|
|
50
|
+
fleece profile unset goal
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## How profile enriches other commands
|
|
54
|
+
|
|
55
|
+
Once set, you don't need to pass spend amounts manually:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Without profile: must pass all spend flags
|
|
59
|
+
fleece roi "Amex Gold" --dining 600 --travel 300 --other 800
|
|
60
|
+
|
|
61
|
+
# With profile set: spend values pulled automatically
|
|
62
|
+
fleece roi "Amex Gold"
|
|
63
|
+
|
|
64
|
+
# fleece wallet and fleece recommend also use profile context automatically
|
|
65
|
+
fleece wallet
|
|
66
|
+
fleece recommend "travel rewards"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Setup workflow
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
fleece profile set dining_monthly 600
|
|
73
|
+
fleece profile set groceries_monthly 400
|
|
74
|
+
fleece profile set travel_monthly 300
|
|
75
|
+
fleece profile set gas_monthly 150
|
|
76
|
+
fleece profile set other_monthly 800
|
|
77
|
+
fleece profile set annual_fee_tolerance 250
|
|
78
|
+
fleece profile set home_airport JFK
|
|
79
|
+
fleece profile set goal "Fly business to Tokyo in 2027"
|
|
80
|
+
fleece profile show
|
|
81
|
+
```
|
|
@@ -27,3 +27,13 @@ Categories: `dining`, `travel`, `groceries`, `gas`, `streaming`, `drugstores`, e
|
|
|
27
27
|
fleece rates "Chase Sapphire Preferred" --json
|
|
28
28
|
fleece rates "Amex Gold" --category dining --json
|
|
29
29
|
```
|
|
30
|
+
|
|
31
|
+
## MCC precision tip
|
|
32
|
+
|
|
33
|
+
Category names like `dining` are broad — a card may earn differently at MCC 5812 (sit-down restaurants) vs 5814 (fast food) vs 5411 (grocery stores with a café). When exact merchant-level precision matters, pair with `fleece mcc`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Confirm the MCC for the merchant type, then look up the rate
|
|
37
|
+
fleece mcc 5814 # → Fast Food Restaurants
|
|
38
|
+
fleece rates "Amex Gold" --category "fast food restaurants" --json
|
|
39
|
+
```
|
|
@@ -30,3 +30,19 @@ fleece recommend "frequent international traveler" --preferences "priority pass
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
After receiving results, present 2–3 top recommendations with a brief rationale for each.
|
|
33
|
+
|
|
34
|
+
## MCC-informed spending profiles
|
|
35
|
+
|
|
36
|
+
For more precise recommendations, identify the MCC codes for the user's top merchants first, then describe the profile by category name:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# User shops at Whole Foods (5411), commutes by subway (4111), eats out often (5812)
|
|
40
|
+
fleece mcc 5411 # → Grocery Stores, Supermarkets
|
|
41
|
+
fleece mcc 4111 # → Transportation / Commuter
|
|
42
|
+
fleece mcc 5812 # → Eating Places, Restaurants
|
|
43
|
+
|
|
44
|
+
# Then recommend based on confirmed categories
|
|
45
|
+
fleece recommend "grocery stores, transit, restaurants" --json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This avoids vague profiles like "I spend a lot on food" and maps the user's real spend to known card bonus categories.
|
|
@@ -60,3 +60,20 @@ fleece wallet
|
|
|
60
60
|
# Explicit cards
|
|
61
61
|
fleece wallet "Amex Gold" "Chase Sapphire Preferred" "Citi Double Cash"
|
|
62
62
|
```
|
|
63
|
+
|
|
64
|
+
## MCC-enriched gap analysis
|
|
65
|
+
|
|
66
|
+
After `fleece wallet` identifies a gap (e.g., "no bonus on grocery stores"), use `fleece mcc` to drill into the precise merchant category and find the best card for it:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Wallet says "gap on groceries" → confirm the MCC and cross-reference wallet
|
|
70
|
+
fleece mcc 5411 --wallet --json # Grocery Stores, Supermarkets
|
|
71
|
+
|
|
72
|
+
# Other common gap MCCs to check after a wallet analysis
|
|
73
|
+
fleece mcc 5541 --wallet # Gas stations
|
|
74
|
+
fleece mcc 5912 --wallet # Drugstores / pharmacies
|
|
75
|
+
fleece mcc 4111 --wallet # Transit / commuter
|
|
76
|
+
fleece mcc 5812 --wallet # Restaurants
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This turns a vague "gap on groceries" into a precise card recommendation for a specific merchant category.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Fleece — Credit Card Research & Redemption
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
**Fleece** is a credit card research and award redemption toolkit. Tagline: "Find the best card for deal saviors."
|
|
6
|
+
|
|
7
|
+
It has two surfaces:
|
|
8
|
+
1. **Streamlit chatbot** (`fleece.py`) — conversational AI assistant backed by OpenAI
|
|
9
|
+
2. **CLI** (`cli.py`) — 12 commands for card research, wallet analysis, MCC lookup, and award redemption
|
|
10
|
+
|
|
11
|
+
Published on PyPI as [`fleece-cli`](https://pypi.org/project/fleece-cli/) · current version **0.3.1**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Tech Stack
|
|
16
|
+
|
|
17
|
+
| Layer | Technology |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Chatbot frontend | Streamlit |
|
|
20
|
+
| Chatbot LLM | OpenAI (gpt-3.5-turbo, gpt-4, gpt-4o) via LangChain |
|
|
21
|
+
| Chatbot memory | ConversationEntityMemory |
|
|
22
|
+
| CLI framework | Typer |
|
|
23
|
+
| Live research | Brave Search API |
|
|
24
|
+
| Card portfolio | SQLite (`fleece.db`) via `db.py` |
|
|
25
|
+
| MCC dataset | Bundled `mcc_codes.jsonl` (981 codes, offline) |
|
|
26
|
+
| Redemption URLs | `pointsyeah.py` (pure stdlib, no deps) |
|
|
27
|
+
| Language | Python 3.11+ |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## CLI Commands
|
|
32
|
+
|
|
33
|
+
### Research (requires `BRAVE_API_KEY`)
|
|
34
|
+
| Command | Description |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `fleece card "<name>"` | Full card report — fees, welcome offer, rates, credits, benefits |
|
|
37
|
+
| `fleece rates "<name>"` | Earning rates by spend category |
|
|
38
|
+
| `fleece partners "<name>"` | Transfer partners, ratios, timing |
|
|
39
|
+
| `fleece credits "<name>"` | Statement credits and perks |
|
|
40
|
+
| `fleece news "<name>"` | Recent changes (past month, freshness-filtered) |
|
|
41
|
+
| `fleece compare "<A>" "<B>"` | Side-by-side comparison |
|
|
42
|
+
| `fleece wallet` | Portfolio analysis — coverage, overlaps, gaps, next-card suggestions |
|
|
43
|
+
| `fleece roi "<name>"` | First-year ROI estimate by spend profile |
|
|
44
|
+
| `fleece recommend "<profile>"` | Card recommendations for a spending profile |
|
|
45
|
+
|
|
46
|
+
### Redemption (no API key needed — work fully offline)
|
|
47
|
+
| Command | Description |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `fleece mcc <code>` | Offline MCC code lookup (981 codes bundled). Add `--wallet` to cross-reference saved cards |
|
|
50
|
+
| `fleece flights <ORIGIN> <DEST> --date <YYYY-MM-DD>` | PointsYeah award flight search URL |
|
|
51
|
+
| `fleece hotels "<location>" --checkin <date> --checkout <date>` | PointsYeah award hotel search URL |
|
|
52
|
+
|
|
53
|
+
All commands support `--json` for agent-friendly output and `-` to read arguments from stdin.
|
|
54
|
+
|
|
55
|
+
### BRAVE_API_KEY
|
|
56
|
+
Optional at startup — checked only when a research command actually runs. `mcc`, `flights`, and `hotels` work with no key set.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Key Files
|
|
61
|
+
|
|
62
|
+
| File | Purpose |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `cli.py` | Main CLI entry point (Typer app) |
|
|
65
|
+
| `fleece.py` | Streamlit chatbot app |
|
|
66
|
+
| `db.py` | SQLite helpers for card portfolio (`fleece.db`) |
|
|
67
|
+
| `pointsyeah.py` | PointsYeah URL generation (pure stdlib, merged from archived `pointsyeah-cli`) |
|
|
68
|
+
| `mcc_codes.jsonl` | Bundled MCC dataset (981 codes, source: greggles/mcc-codes) |
|
|
69
|
+
| `tools/brave_client.py` | Brave Search API client |
|
|
70
|
+
| `tools/credit_card_tools.py` | LangChain tools for the chatbot |
|
|
71
|
+
| `pyproject.toml` | Package config — hatchling build, `fleece` entry point |
|
|
72
|
+
| `install.sh` | Installs Claude Code skills and/or agent skill |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Agent Skills
|
|
77
|
+
|
|
78
|
+
### Claude Code (`/.claude/skills/`)
|
|
79
|
+
12 slash commands installed via `bash install.sh --claude`:
|
|
80
|
+
|
|
81
|
+
**Research:** `/fleece-card` `/fleece-rates` `/fleece-partners` `/fleece-credits` `/fleece-news` `/fleece-compare` `/fleece-wallet` `/fleece-roi` `/fleece-recommend`
|
|
82
|
+
|
|
83
|
+
**Redemption:** `/fleece-mcc` `/fleece-flights` `/fleece-hotels`
|
|
84
|
+
|
|
85
|
+
### ClawHub / OpenClaw (`/.agents/skills/fleece/SKILL.md`)
|
|
86
|
+
Published on ClawHub as `fleece@1.3.0`. Install via `clawhub install fleece` or `bash install.sh --agents`.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## CI/CD
|
|
91
|
+
|
|
92
|
+
| Workflow | Trigger | Action |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `publish.yml` | Push `v*` tag | Build and publish to PyPI via OIDC trusted publishing |
|
|
95
|
+
| `publish-skills.yml` | Push to `main` touching `.agents/skills/` or `.claude/skills/` | Publish to ClawHub via `CLAWHUB_TOKEN` secret |
|
|
96
|
+
|
|
97
|
+
GitHub environment `pypi` is required for the PyPI workflow (OIDC).
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Landing Page
|
|
102
|
+
|
|
103
|
+
`docs/` is served as GitHub Pages at **https://getfleece.io/**.
|
|
104
|
+
|
|
105
|
+
Contains `index.html`, `sitemap.xml`, `robots.txt`. Submitted to Google Search Console. JSON-LD structured data included.
|
|
106
|
+
|
|
107
|
+
SEO notes tracked in `docs/SEO.md`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Infrastructure Notes
|
|
112
|
+
|
|
113
|
+
- **Databricks**: No resources available. Do not suggest Databricks solutions until provisioned.
|
|
114
|
+
- **pointsyeah-cli**: Archived. All functionality merged into fleece (`pointsyeah.py`, `fleece flights`, `fleece hotels`).
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Development Notes
|
|
119
|
+
|
|
120
|
+
- Author: Yuan Chen
|
|
121
|
+
- Created: March 16, 2025
|
|
122
|
+
- Chatbot uses custom CSS styling (`style.css`)
|
|
123
|
+
- OpenAI API key entered via Streamlit sidebar — not stored
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fleece-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Credit card research and redemption CLI — live data via Brave Search, PointsYeah URL generation, designed for humans and AI agents.
|
|
5
5
|
Author-email: Yuan Chen <cysbc1999@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -4,10 +4,13 @@ Fleece CLI — agent-friendly companion to the Fleece Streamlit chatbot.
|
|
|
4
4
|
Exposes credit card research tools as shell commands backed by Brave Search.
|
|
5
5
|
Designed for use by AI agents (Claude Code, Codex) and humans alike.
|
|
6
6
|
|
|
7
|
+
BRAVE_API_KEY is optional — commands that don't need live search (mcc, flights,
|
|
8
|
+
hotels) work fully offline. Research commands (card, rates, wallet, …) require it.
|
|
9
|
+
|
|
7
10
|
Exit codes:
|
|
8
11
|
0 success
|
|
9
12
|
1 search / tool error
|
|
10
|
-
2
|
|
13
|
+
2 BRAVE_API_KEY required but not set
|
|
11
14
|
"""
|
|
12
15
|
import json
|
|
13
16
|
import sys
|
|
@@ -18,7 +21,11 @@ from dotenv import load_dotenv
|
|
|
18
21
|
|
|
19
22
|
app = typer.Typer(
|
|
20
23
|
name="fleece",
|
|
21
|
-
help=
|
|
24
|
+
help=(
|
|
25
|
+
"Fleece credit card research CLI — live data via Brave Search.\n\n"
|
|
26
|
+
"BRAVE_API_KEY is optional: mcc, flights, and hotels work offline.\n"
|
|
27
|
+
"Research commands (card, rates, wallet, …) require it."
|
|
28
|
+
),
|
|
22
29
|
no_args_is_help=True,
|
|
23
30
|
)
|
|
24
31
|
|
|
@@ -27,20 +34,21 @@ app = typer.Typer(
|
|
|
27
34
|
# ---------------------------------------------------------------------------
|
|
28
35
|
|
|
29
36
|
def _resolve_key(api_key: Optional[str], no_dotenv: bool) -> str:
|
|
30
|
-
"""Load env and return the Brave API key
|
|
37
|
+
"""Load env and return the Brave API key (may be empty — checked at use time)."""
|
|
31
38
|
import os
|
|
32
39
|
if not no_dotenv:
|
|
33
40
|
load_dotenv()
|
|
34
|
-
|
|
41
|
+
return api_key or os.getenv("BRAVE_API_KEY", "")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _get_wrapper(key: str, freshness: Optional[str] = None):
|
|
35
45
|
if not key:
|
|
36
46
|
_error_exit(
|
|
37
|
-
"BRAVE_API_KEY
|
|
47
|
+
"BRAVE_API_KEY is required for live research. "
|
|
48
|
+
"Set it in your environment, add it to .env, or pass --api-key. "
|
|
49
|
+
"Commands mcc, flights, and hotels work without it.",
|
|
38
50
|
code=2,
|
|
39
51
|
)
|
|
40
|
-
return key
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def _get_wrapper(key: str, freshness: Optional[str] = None):
|
|
44
52
|
from tools.brave_client import build_brave_wrapper
|
|
45
53
|
return build_brave_wrapper(key, freshness=freshness)
|
|
46
54
|
|
|
@@ -242,14 +250,18 @@ def wallet(
|
|
|
242
250
|
except Exception as e:
|
|
243
251
|
_error_exit(str(e), code=1)
|
|
244
252
|
|
|
253
|
+
import db as _db
|
|
254
|
+
profile_ctx = _db.profile_as_context()
|
|
255
|
+
|
|
245
256
|
combined = "\n\n".join(parts)
|
|
246
|
-
combined +=
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
257
|
+
combined += "\n\nBased on the above, identify:\n"
|
|
258
|
+
combined += "1. Category coverage map\n"
|
|
259
|
+
combined += "2. Overlapping benefits or redundant categories\n"
|
|
260
|
+
combined += "3. Gaps — categories with no bonus multiplier\n"
|
|
261
|
+
combined += "4. Top 1-2 cards that would complement this portfolio"
|
|
262
|
+
if profile_ctx:
|
|
263
|
+
combined += f"\n\nUser profile context: {profile_ctx}"
|
|
264
|
+
combined += "\nTailor the gap analysis and recommendations to this profile."
|
|
253
265
|
_emit(combined, as_json, "wallet", ", ".join(card_list))
|
|
254
266
|
|
|
255
267
|
|
|
@@ -266,10 +278,20 @@ def roi(
|
|
|
266
278
|
"""First-year ROI estimate — welcome bonus + earn + credits minus annual fee."""
|
|
267
279
|
from tools.brave_client import search_and_format
|
|
268
280
|
from tools.credit_card_tools import _guess_cpp
|
|
281
|
+
import db as _db
|
|
269
282
|
|
|
270
283
|
name = _read_stdin_or_arg(name)
|
|
271
284
|
key = _resolve_key(api_key, no_dotenv)
|
|
272
285
|
|
|
286
|
+
# Pull spend values from saved profile if not provided on the command line
|
|
287
|
+
p = _db.get_profile()
|
|
288
|
+
if travel == 0.0 and p.get("travel_monthly"):
|
|
289
|
+
travel = float(p["travel_monthly"])
|
|
290
|
+
if dining == 0.0 and p.get("dining_monthly"):
|
|
291
|
+
dining = float(p["dining_monthly"])
|
|
292
|
+
if other == 0.0 and p.get("other_monthly"):
|
|
293
|
+
other = float(p["other_monthly"])
|
|
294
|
+
|
|
273
295
|
annual_travel = travel * 12
|
|
274
296
|
annual_dining = dining * 12
|
|
275
297
|
annual_other = other * 12
|
|
@@ -302,10 +324,16 @@ def recommend(
|
|
|
302
324
|
no_dotenv: NoDotenv = False,
|
|
303
325
|
):
|
|
304
326
|
"""Card recommendations matched to a spending profile and preferences."""
|
|
327
|
+
import db as _db
|
|
305
328
|
profile = _read_stdin_or_arg(profile)
|
|
306
329
|
key = _resolve_key(api_key, no_dotenv)
|
|
307
330
|
pref = f"{preferences} " if preferences else ""
|
|
308
|
-
|
|
331
|
+
|
|
332
|
+
# Enrich with saved profile context if available
|
|
333
|
+
saved_ctx = _db.profile_as_context(cards=_db.get_card_names())
|
|
334
|
+
ctx = f"{saved_ctx} | " if saved_ctx else ""
|
|
335
|
+
|
|
336
|
+
query = f"best credit cards {ctx}{profile} {pref}US 2025 site:nerdwallet.com OR site:thepointsguy.com OR site:doctorofcredit.com"
|
|
309
337
|
_run_search(_get_wrapper(key), query, "recommend", as_json)
|
|
310
338
|
|
|
311
339
|
|
|
@@ -457,6 +485,72 @@ def hotels(
|
|
|
457
485
|
webbrowser.open(url)
|
|
458
486
|
|
|
459
487
|
|
|
488
|
+
# ---------------------------------------------------------------------------
|
|
489
|
+
# profile — spending profile management
|
|
490
|
+
# ---------------------------------------------------------------------------
|
|
491
|
+
|
|
492
|
+
profile_app = typer.Typer(name="profile", help="Manage your spending profile — used to personalise research commands.", no_args_is_help=True)
|
|
493
|
+
app.add_typer(profile_app)
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
@profile_app.command("show")
|
|
497
|
+
def profile_show(as_json: JsonOpt = False):
|
|
498
|
+
"""Show your current spending profile."""
|
|
499
|
+
import db as _db
|
|
500
|
+
p = _db.get_profile()
|
|
501
|
+
if not p:
|
|
502
|
+
typer.echo("No profile set. Run: fleece profile set <field> <value>")
|
|
503
|
+
typer.echo(f"Fields: {', '.join(_db.PROFILE_FIELDS)}")
|
|
504
|
+
return
|
|
505
|
+
if as_json:
|
|
506
|
+
typer.echo(json.dumps({"command": "profile show", "profile": p, "ok": True, "error": None}))
|
|
507
|
+
return
|
|
508
|
+
for key, label in _db.PROFILE_FIELDS.items():
|
|
509
|
+
val = p.get(key, "")
|
|
510
|
+
if val:
|
|
511
|
+
typer.echo(f" {label:<45} {val}")
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@profile_app.command("set")
|
|
515
|
+
def profile_set(
|
|
516
|
+
field: Annotated[str, typer.Argument(help=f"Field name. One of: {', '.join(__import__('db').PROFILE_FIELDS)}")],
|
|
517
|
+
value: Annotated[str, typer.Argument(help="Value to set.")],
|
|
518
|
+
as_json: JsonOpt = False,
|
|
519
|
+
):
|
|
520
|
+
"""Set a profile field."""
|
|
521
|
+
import db as _db
|
|
522
|
+
try:
|
|
523
|
+
_db.set_profile_field(field, value)
|
|
524
|
+
except ValueError as e:
|
|
525
|
+
_error_exit(str(e), code=1)
|
|
526
|
+
if as_json:
|
|
527
|
+
typer.echo(json.dumps({"command": "profile set", "field": field, "value": value, "ok": True, "error": None}))
|
|
528
|
+
else:
|
|
529
|
+
typer.echo(f"Profile updated: {field} = {value}")
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
@profile_app.command("unset")
|
|
533
|
+
def profile_unset(
|
|
534
|
+
field: Annotated[str, typer.Argument(help="Field name to clear.")],
|
|
535
|
+
as_json: JsonOpt = False,
|
|
536
|
+
):
|
|
537
|
+
"""Clear a single profile field."""
|
|
538
|
+
import db as _db
|
|
539
|
+
_db.clear_profile_field(field)
|
|
540
|
+
if as_json:
|
|
541
|
+
typer.echo(json.dumps({"command": "profile unset", "field": field, "ok": True, "error": None}))
|
|
542
|
+
else:
|
|
543
|
+
typer.echo(f"Cleared: {field}")
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
@profile_app.command("fields")
|
|
547
|
+
def profile_fields():
|
|
548
|
+
"""List all available profile fields and their descriptions."""
|
|
549
|
+
import db as _db
|
|
550
|
+
for key, label in _db.PROFILE_FIELDS.items():
|
|
551
|
+
typer.echo(f" {key:<30} {label}")
|
|
552
|
+
|
|
553
|
+
|
|
460
554
|
# ---------------------------------------------------------------------------
|
|
461
555
|
# cards — profile management (read/write user_cards.json)
|
|
462
556
|
# ---------------------------------------------------------------------------
|
|
@@ -23,8 +23,26 @@ CREATE TABLE IF NOT EXISTS cards (
|
|
|
23
23
|
image_url TEXT NOT NULL DEFAULT '',
|
|
24
24
|
date_added TEXT NOT NULL DEFAULT (date('now'))
|
|
25
25
|
);
|
|
26
|
+
CREATE TABLE IF NOT EXISTS profile (
|
|
27
|
+
key TEXT PRIMARY KEY,
|
|
28
|
+
value TEXT NOT NULL DEFAULT ''
|
|
29
|
+
);
|
|
26
30
|
"""
|
|
27
31
|
|
|
32
|
+
# Default profile fields and their human-readable labels
|
|
33
|
+
PROFILE_FIELDS = {
|
|
34
|
+
"dining_monthly": "Monthly dining spend ($)",
|
|
35
|
+
"groceries_monthly": "Monthly groceries spend ($)",
|
|
36
|
+
"travel_monthly": "Monthly travel spend ($)",
|
|
37
|
+
"gas_monthly": "Monthly gas spend ($)",
|
|
38
|
+
"other_monthly": "Monthly other spend ($)",
|
|
39
|
+
"annual_fee_tolerance": "Max annual fee willing to pay ($)",
|
|
40
|
+
"points_programs": "Preferred points programs (e.g. Amex MR, Chase UR)",
|
|
41
|
+
"home_airport": "Home airport IATA code (e.g. JFK)",
|
|
42
|
+
"goal": "Current redemption goal (e.g. business class to Tokyo)",
|
|
43
|
+
"preferences": "Other preferences (e.g. no foreign transaction fees)",
|
|
44
|
+
}
|
|
45
|
+
|
|
28
46
|
_COLUMNS = ("id", "name", "last_four", "annual_fee", "credit_limit",
|
|
29
47
|
"rewards", "expiration", "image_url", "date_added")
|
|
30
48
|
|
|
@@ -133,6 +151,73 @@ def remove_card(name: str) -> bool:
|
|
|
133
151
|
return cur.rowcount > 0
|
|
134
152
|
|
|
135
153
|
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
# Profile
|
|
156
|
+
# ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
def get_profile() -> dict[str, str]:
|
|
159
|
+
"""Return the full profile as {key: value}. Missing keys return ''."""
|
|
160
|
+
init_db()
|
|
161
|
+
with _conn() as con:
|
|
162
|
+
rows = con.execute("SELECT key, value FROM profile").fetchall()
|
|
163
|
+
return {r["key"]: r["value"] for r in rows}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def set_profile_field(key: str, value: str) -> None:
|
|
167
|
+
"""Upsert a single profile field."""
|
|
168
|
+
if key not in PROFILE_FIELDS:
|
|
169
|
+
raise ValueError(f'Unknown profile field "{key}". Valid fields: {", ".join(PROFILE_FIELDS)}')
|
|
170
|
+
init_db()
|
|
171
|
+
with _conn() as con:
|
|
172
|
+
con.execute(
|
|
173
|
+
"INSERT INTO profile (key, value) VALUES (?, ?) "
|
|
174
|
+
"ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
|
175
|
+
(key, value),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def clear_profile_field(key: str) -> None:
|
|
180
|
+
"""Remove a single profile field."""
|
|
181
|
+
init_db()
|
|
182
|
+
with _conn() as con:
|
|
183
|
+
con.execute("DELETE FROM profile WHERE key = ?", (key,))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def profile_as_context(cards: list[str] | None = None) -> str:
|
|
187
|
+
"""
|
|
188
|
+
Return a compact natural-language summary of the user profile suitable
|
|
189
|
+
for injecting into a Brave Search query or LLM prompt.
|
|
190
|
+
"""
|
|
191
|
+
p = get_profile()
|
|
192
|
+
parts = []
|
|
193
|
+
|
|
194
|
+
spend_fields = [
|
|
195
|
+
("dining_monthly", "dining"),
|
|
196
|
+
("groceries_monthly", "groceries"),
|
|
197
|
+
("travel_monthly", "travel"),
|
|
198
|
+
("gas_monthly", "gas"),
|
|
199
|
+
("other_monthly", "other"),
|
|
200
|
+
]
|
|
201
|
+
spend_parts = [f"${p[k]}/mo {label}" for k, label in spend_fields if p.get(k)]
|
|
202
|
+
if spend_parts:
|
|
203
|
+
parts.append("Spending: " + ", ".join(spend_parts))
|
|
204
|
+
|
|
205
|
+
if p.get("annual_fee_tolerance"):
|
|
206
|
+
parts.append(f"Max annual fee: ${p['annual_fee_tolerance']}")
|
|
207
|
+
if p.get("points_programs"):
|
|
208
|
+
parts.append(f"Points programs: {p['points_programs']}")
|
|
209
|
+
if p.get("home_airport"):
|
|
210
|
+
parts.append(f"Home airport: {p['home_airport']}")
|
|
211
|
+
if p.get("goal"):
|
|
212
|
+
parts.append(f"Goal: {p['goal']}")
|
|
213
|
+
if p.get("preferences"):
|
|
214
|
+
parts.append(f"Preferences: {p['preferences']}")
|
|
215
|
+
if cards:
|
|
216
|
+
parts.append(f"Current cards: {', '.join(cards)}")
|
|
217
|
+
|
|
218
|
+
return " | ".join(parts) if parts else ""
|
|
219
|
+
|
|
220
|
+
|
|
136
221
|
# ---------------------------------------------------------------------------
|
|
137
222
|
# Migration
|
|
138
223
|
# ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# ClawHub Skill SEO Log
|
|
2
|
+
|
|
3
|
+
Tracking description changes, tag updates, and search ranking results for the `fleece` skill on ClawHub.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## v1.0.0 — Initial publish (2026-05-18)
|
|
8
|
+
|
|
9
|
+
**Description:**
|
|
10
|
+
> Fleece credit card research CLI. Provides live US credit card data via Brave Search — full reports, earning rates, transfer partners, statement credits, recent news, card comparisons, portfolio analysis, ROI estimates, and profile-based recommendations. Install with `pip install fleece-cli`. Use whenever you need current credit card information.
|
|
11
|
+
|
|
12
|
+
**Tags:** `latest`
|
|
13
|
+
|
|
14
|
+
**Search results:**
|
|
15
|
+
| Query | Rank | Score |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `credit card` | #13 | 0.701 |
|
|
18
|
+
|
|
19
|
+
**Issues identified:**
|
|
20
|
+
- Generic name "Fleece" gives no signal to vector search
|
|
21
|
+
- Description truncated in results — key terms buried
|
|
22
|
+
- No categorical tags
|
|
23
|
+
- Zero results for conversational queries like "what card should I use for dining"
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## v1.1.0 — Keyword-rich description + tags (2026-05-18)
|
|
28
|
+
|
|
29
|
+
**Changes:**
|
|
30
|
+
- Rewrote description to front-load issuer names (Chase, Amex, Citi, Capital One, Bilt) and reward types (points, miles, cash back, annual fees, welcome bonuses, transfer partners)
|
|
31
|
+
- Added "Use this skill when..." section with 8 natural-language trigger phrases near top of SKILL.md body
|
|
32
|
+
- Added 14 categorical tags
|
|
33
|
+
|
|
34
|
+
**Tags:** `latest, credit-cards, rewards, points, miles, travel, finance, research, amex, chase, citi, capital-one, brave-search, wallet, transfer-partners`
|
|
35
|
+
|
|
36
|
+
**Search results:**
|
|
37
|
+
| Query | Rank | Score |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `credit card research` | **#1** | 0.817 |
|
|
40
|
+
| `credit card redemption` | **#1** | 0.782 |
|
|
41
|
+
| `credit card` | #13 | 0.702 |
|
|
42
|
+
| `what card should I use for dining` | — | no results |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## v1.1.1 — Conversational query language (2026-05-18)
|
|
47
|
+
|
|
48
|
+
**Changes:**
|
|
49
|
+
- Rewrote description opening to directly mirror user query phrasing:
|
|
50
|
+
> "What credit card should I use for dining, travel, groceries, or gas?" — Fleece answers this with live data...
|
|
51
|
+
- Added `recommendations`, `dining`, `groceries`, `gas` tags
|
|
52
|
+
|
|
53
|
+
**Rationale:** Vector search scores on embedding similarity — starting the description with the exact question users ask maximizes cosine similarity for that query bucket.
|
|
54
|
+
|
|
55
|
+
**Tags:** `latest, credit-cards, rewards, points, miles, travel, finance, research, amex, chase, citi, capital-one, brave-search, wallet, transfer-partners, recommendations, dining, groceries, gas`
|
|
56
|
+
|
|
57
|
+
**Search results:**
|
|
58
|
+
| Query | Rank | Score |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `credit card research` | **#1** | 0.817 |
|
|
61
|
+
| `credit card redemption` | **#1** | 0.782 |
|
|
62
|
+
| `what card should I use for dining` | — | no results (below threshold) |
|
|
63
|
+
|
|
64
|
+
**Note:** ClawHub has a minimum score threshold (~0.6–0.7). Conversational queries fall below it for all skills — not specific to fleece. Vector index update lag (~minutes) observed between publish and ranking change.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## v1.2.0 — MCC command added (2026-05-18)
|
|
69
|
+
|
|
70
|
+
**Changes:**
|
|
71
|
+
- Added `fleece mcc` command (offline MCC code lookup + wallet cross-reference)
|
|
72
|
+
- Added `mcc`, `merchant-category` tags
|
|
73
|
+
|
|
74
|
+
**Tags:** added `mcc, merchant-category`
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## v1.2.1 — Claude skill for MCC published (2026-05-18)
|
|
79
|
+
|
|
80
|
+
**Changes:**
|
|
81
|
+
- Added `fleece-mcc.md` Claude Code skill
|
|
82
|
+
- No description change
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## v1.3.0 — MCC-enriched workflows across all skills (2026-05-18)
|
|
87
|
+
|
|
88
|
+
**Changes:**
|
|
89
|
+
- Added merchant lookup as an explicit trigger phrase in agent SKILL.md:
|
|
90
|
+
> "What card should I use at Costco?", "Which card earns the most at gas stations?", "What MCC is a pharmacy?"
|
|
91
|
+
- Added MCC workflow table to agent SKILL.md mapping common codes to typical card bonuses (5411 groceries, 5812 restaurants, 5541 gas, 4511 airlines, 7011 hotels, 4111 transit, 5912 drugstores)
|
|
92
|
+
- **fleece-wallet**: added post-gap-analysis MCC flow (`fleece mcc <code> --wallet`)
|
|
93
|
+
- **fleece-rates**: added MCC precision tip (5812 vs 5814 vs 5411 distinctions)
|
|
94
|
+
- **fleece-recommend**: added MCC-informed spending profile workflow
|
|
95
|
+
- **fleece-compare**: added MCC-precise comparison example
|
|
96
|
+
|
|
97
|
+
**Rationale:** MCC lookup answers "what card should I use at [merchant]?" with precision. Cross-referencing wallet gaps with MCC codes turns vague category gaps into specific merchant-level card recommendations. Adding merchant phrasing to trigger phrases broadens the query surface the skill matches.
|
|
98
|
+
|
|
99
|
+
**Tags:** unchanged from v1.2.1
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Observations & lessons
|
|
104
|
+
|
|
105
|
+
1. **Description is the primary ranking signal** — ClawHub's vector search indexes the frontmatter `description` field. The body content appears to have lower weight. Front-load the highest-value keywords.
|
|
106
|
+
|
|
107
|
+
2. **Conversational queries hit a threshold floor** — queries phrased as full sentences ("what card should I use for...") return 0 results across all skills, suggesting the registry-wide similarity is below ClawHub's cutoff for this query type. Not a fleece-specific problem.
|
|
108
|
+
|
|
109
|
+
3. **Intent buckets matter** — "credit card" ranks us #13 because the top results are payment/spend skills (giving agents a card to transact). We're a research tool — different intent, different bucket. Competing in the right bucket ("credit card research", "credit card redemption") yields #1 rankings.
|
|
110
|
+
|
|
111
|
+
4. **Tags are for filtering, not ranking** — adding tags didn't move needle on search scores but helps with tag-based browsing.
|
|
112
|
+
|
|
113
|
+
5. **Index update lag** — ClawHub rebuilds vector embeddings asynchronously after publish. The `inspect` summary field reflects the old content until the rebuild completes. Wait ~5–10 minutes before testing ranking changes.
|
|
@@ -3,7 +3,56 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
<!-- Primary SEO -->
|
|
8
|
+
<title>Fleece — Credit Card Research CLI & Rewards Optimizer</title>
|
|
9
|
+
<meta name="description" content="Fleece is a free, open-source CLI that researches credit cards with live data. Compare Chase, Amex, Citi, and Capital One cards — earning rates, transfer partners, statement credits, ROI, and MCC-level merchant lookup. pip install fleece-cli." />
|
|
10
|
+
<meta name="robots" content="index, follow" />
|
|
11
|
+
<meta name="author" content="Yuan Chen" />
|
|
12
|
+
<link rel="canonical" href="https://getfleece.io/" />
|
|
13
|
+
<meta name="google-site-verification" content="9DkACCiooe0-omtkzGJUZJPqoG0HAj4QejFEom9wrGA" />
|
|
14
|
+
|
|
15
|
+
<!-- Open Graph -->
|
|
16
|
+
<meta property="og:type" content="website" />
|
|
17
|
+
<meta property="og:url" content="https://getfleece.io/" />
|
|
18
|
+
<meta property="og:title" content="Fleece — Credit Card Research CLI & Rewards Optimizer" />
|
|
19
|
+
<meta property="og:description" content="Research credit cards with live data. Compare Chase, Amex, Citi, Capital One — earning rates, transfer partners, ROI, MCC lookup, and award flight search. Free and open source." />
|
|
20
|
+
<meta property="og:site_name" content="Fleece" />
|
|
21
|
+
|
|
22
|
+
<!-- Twitter Card -->
|
|
23
|
+
<meta name="twitter:card" content="summary" />
|
|
24
|
+
<meta name="twitter:title" content="Fleece — Credit Card Research CLI & Rewards Optimizer" />
|
|
25
|
+
<meta name="twitter:description" content="Research credit cards with live data. Compare Chase, Amex, Citi, Capital One — earning rates, transfer partners, ROI, MCC lookup, and award flight search. Free and open source." />
|
|
26
|
+
|
|
27
|
+
<!-- JSON-LD Structured Data -->
|
|
28
|
+
<script type="application/ld+json">
|
|
29
|
+
{
|
|
30
|
+
"@context": "https://schema.org",
|
|
31
|
+
"@type": "SoftwareApplication",
|
|
32
|
+
"name": "Fleece",
|
|
33
|
+
"alternateName": "fleece-cli",
|
|
34
|
+
"applicationCategory": "FinanceApplication",
|
|
35
|
+
"operatingSystem": "macOS, Linux, Windows",
|
|
36
|
+
"programmingLanguage": "Python",
|
|
37
|
+
"offers": {
|
|
38
|
+
"@type": "Offer",
|
|
39
|
+
"price": "0",
|
|
40
|
+
"priceCurrency": "USD"
|
|
41
|
+
},
|
|
42
|
+
"description": "Fleece is an open-source credit card research CLI. Look up earning rates, transfer partners, statement credits, annual fees, and first-year ROI for Chase, Amex, Citi, Capital One, and all major US issuers. Includes offline MCC merchant category lookup and PointsYeah award flight and hotel search.",
|
|
43
|
+
"url": "https://getfleece.io/",
|
|
44
|
+
"downloadUrl": "https://pypi.org/project/fleece-cli/",
|
|
45
|
+
"softwareVersion": "0.3.0",
|
|
46
|
+
"license": "https://github.com/chenyuan99/fleece/blob/main/LICENSE",
|
|
47
|
+
"codeRepository": "https://github.com/chenyuan99/fleece",
|
|
48
|
+
"author": {
|
|
49
|
+
"@type": "Person",
|
|
50
|
+
"name": "Yuan Chen"
|
|
51
|
+
},
|
|
52
|
+
"keywords": "credit card research, rewards optimizer, transfer partners, MCC lookup, Chase Sapphire, Amex Gold, Citi, Capital One, points miles cash back"
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
55
|
+
|
|
7
56
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
57
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
58
|
<link href="https://fonts.googleapis.com/css2?family=Oswald:wght@400;600;700&family=Source+Sans+3:wght@400;600&display=swap" rel="stylesheet">
|
|
@@ -463,7 +512,7 @@
|
|
|
463
512
|
<section class="hero">
|
|
464
513
|
<div class="hero-inner">
|
|
465
514
|
<div>
|
|
466
|
-
<h1>
|
|
515
|
+
<h1>Credit card research for <span>deal saviors</span></h1>
|
|
467
516
|
<p>AI-powered credit card research and award redemption. Live data via Brave Search, PointsYeah flight and hotel search — every command outputs clean JSON, built for humans and AI agents alike.</p>
|
|
468
517
|
<div class="hero-actions">
|
|
469
518
|
<a class="btn-pill-dark" href="https://github.com/chenyuan99/fleece" target="_blank">
|
|
@@ -476,7 +525,7 @@
|
|
|
476
525
|
<div class="hero-install-box">
|
|
477
526
|
<h2>Install CLI</h2>
|
|
478
527
|
<div class="install-cmd"><span>$</span> pip install fleece-cli</div>
|
|
479
|
-
<p
|
|
528
|
+
<p><code style="color:rgba(255,255,255,0.5);font-size:0.85em">BRAVE_API_KEY</code> is optional — <code style="color:rgba(255,255,255,0.5);font-size:0.85em">mcc</code>, <code style="color:rgba(255,255,255,0.5);font-size:0.85em">flights</code>, and <code style="color:rgba(255,255,255,0.5);font-size:0.85em">hotels</code> work fully offline. Live research commands require it. Requires Python 3.11+.</p>
|
|
480
529
|
</div>
|
|
481
530
|
</div>
|
|
482
531
|
</section>
|
|
@@ -520,7 +569,7 @@
|
|
|
520
569
|
<path d="M38 28l8-4-2 8" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
521
570
|
</svg>
|
|
522
571
|
<h3>Redemption</h3>
|
|
523
|
-
<p>Generate PointsYeah search URLs for award flights and hotels
|
|
572
|
+
<p>Look up any merchant category code to find your best card at checkout. Generate PointsYeah search URLs for award flights and hotels. No API key needed for either — works fully offline.</p>
|
|
524
573
|
<a class="btn-arrow" href="#commands" >
|
|
525
574
|
See commands
|
|
526
575
|
<svg viewBox="0 0 16 16" fill="none"><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
@@ -533,8 +582,8 @@
|
|
|
533
582
|
<!-- ABOUT -->
|
|
534
583
|
<section class="announcement">
|
|
535
584
|
<div class="announcement-inner">
|
|
536
|
-
<h2>About</h2>
|
|
537
|
-
<p>Fleece is
|
|
585
|
+
<h2>About Fleece</h2>
|
|
586
|
+
<p>Fleece is a free, open-source credit card research tool built for people who take rewards seriously. Unlike chatbots that rely on stale training data, Fleece pulls live information from the web on every query — so you always get current fees, earning rates, and benefit details. The CLI is designed to work seamlessly with AI agents: every command supports <code style="font-size:0.95em;background:rgba(0,0,0,0.06);padding:1px 5px;border-radius:3px">--json</code> output and reads from stdin, so it plugs into any workflow.</p>
|
|
538
587
|
<a class="btn-arrow" href="https://github.com/chenyuan99/fleece" target="_blank" style="background:var(--black);color:var(--white);">
|
|
539
588
|
Read the docs
|
|
540
589
|
<svg viewBox="0 0 16 16" fill="none" width="14" height="14"><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
@@ -542,6 +591,62 @@
|
|
|
542
591
|
</div>
|
|
543
592
|
</section>
|
|
544
593
|
|
|
594
|
+
<!-- AGENT INTEGRATION -->
|
|
595
|
+
<section class="cards-section" id="agents" style="border-top: 1px solid var(--border);">
|
|
596
|
+
<div style="max-width:1100px;margin:0 auto;padding:0 0 2rem;">
|
|
597
|
+
<p class="section-label" style="color:var(--mid);font-size:0.72rem;font-weight:800;letter-spacing:2px;text-transform:uppercase;margin-bottom:0.6rem;">Agent Integration</p>
|
|
598
|
+
<h2 style="font-family:var(--font-head);font-size:clamp(1.75rem,3vw,2.2rem);font-weight:900;letter-spacing:-0.5px;margin-bottom:0.75rem;">Works with your AI agent</h2>
|
|
599
|
+
<p style="font-size:1rem;color:var(--mid);max-width:540px;margin-bottom:2.5rem;">Install once and every supported agent gains access to all 12 Fleece commands — research, wallet analysis, MCC lookup, and award redemption.</p>
|
|
600
|
+
</div>
|
|
601
|
+
|
|
602
|
+
<div class="cards-inner" style="grid-template-columns: repeat(3, 1fr);">
|
|
603
|
+
|
|
604
|
+
<div class="card">
|
|
605
|
+
<svg class="card-icon" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
606
|
+
<rect x="8" y="8" width="44" height="44" rx="8" stroke="black" stroke-width="2.5"/>
|
|
607
|
+
<path d="M20 30h20M20 22h12M20 38h16" stroke="black" stroke-width="2.5" stroke-linecap="round"/>
|
|
608
|
+
</svg>
|
|
609
|
+
<h3>Claude Code</h3>
|
|
610
|
+
<p>Install 12 slash commands directly into your Claude Code session. Use <code style="font-size:0.85em;background:#f0f0f0;padding:1px 4px;border-radius:3px">/fleece-wallet</code>, <code style="font-size:0.85em;background:#f0f0f0;padding:1px 4px;border-radius:3px">/fleece-mcc</code>, and more without leaving the terminal.</p>
|
|
611
|
+
<div style="font-family:'Courier New',monospace;font-size:0.8rem;background:#f7f7f5;border:1px solid var(--border);border-radius:6px;padding:0.9rem 1rem;line-height:1.8;">
|
|
612
|
+
<div><span style="color:var(--mid)">$</span> bash install.sh --claude</div>
|
|
613
|
+
<div style="color:var(--mid);font-size:0.75rem;margin-top:4px">/fleece-card /fleece-wallet /fleece-mcc</div>
|
|
614
|
+
<div style="color:var(--mid);font-size:0.75rem">/fleece-flights /fleece-hotels +7 more</div>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
|
|
618
|
+
<div class="card">
|
|
619
|
+
<svg class="card-icon" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
620
|
+
<circle cx="30" cy="30" r="22" stroke="black" stroke-width="2.5"/>
|
|
621
|
+
<path d="M22 30c0-4.4 3.6-8 8-8s8 3.6 8 8-3.6 8-8 8" stroke="black" stroke-width="2.5" stroke-linecap="round"/>
|
|
622
|
+
<circle cx="30" cy="30" r="3" fill="black"/>
|
|
623
|
+
</svg>
|
|
624
|
+
<h3>OpenClaw & Codex</h3>
|
|
625
|
+
<p>Install the agent skill to give OpenClaw or Codex full Fleece capability — card research, wallet gaps, MCC lookup, and redemption, all in one skill.</p>
|
|
626
|
+
<div style="font-family:'Courier New',monospace;font-size:0.8rem;background:#f7f7f5;border:1px solid var(--border);border-radius:6px;padding:0.9rem 1rem;line-height:1.8;">
|
|
627
|
+
<div><span style="color:var(--mid)">$</span> bash install.sh --agents</div>
|
|
628
|
+
<div style="color:var(--mid);font-size:0.75rem;margin-top:4px">.agents/skills/fleece/SKILL.md</div>
|
|
629
|
+
<div style="color:var(--mid);font-size:0.75rem">or: clawhub install fleece</div>
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
632
|
+
|
|
633
|
+
<div class="card">
|
|
634
|
+
<svg class="card-icon" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
635
|
+
<path d="M10 20l20-10 20 10v20L30 50 10 40V20z" stroke="black" stroke-width="2.5" stroke-linejoin="round"/>
|
|
636
|
+
<path d="M30 40V20M10 20l20 10 20-10" stroke="black" stroke-width="2.5" stroke-linejoin="round"/>
|
|
637
|
+
</svg>
|
|
638
|
+
<h3>ClawHub Registry</h3>
|
|
639
|
+
<p>Fleece is published on ClawHub. Any agent that supports the ClawHub registry can install and use it with a single command — no git clone required.</p>
|
|
640
|
+
<div style="font-family:'Courier New',monospace;font-size:0.8rem;background:#f7f7f5;border:1px solid var(--border);border-radius:6px;padding:0.9rem 1rem;line-height:1.8;">
|
|
641
|
+
<div><span style="color:var(--mid)">$</span> clawhub install fleece</div>
|
|
642
|
+
<div style="color:var(--mid);font-size:0.75rem;margin-top:4px">fleece@1.3.0 · MIT-0</div>
|
|
643
|
+
<div style="color:var(--mid);font-size:0.75rem">clawhub search "credit card research"</div>
|
|
644
|
+
</div>
|
|
645
|
+
</div>
|
|
646
|
+
|
|
647
|
+
</div>
|
|
648
|
+
</section>
|
|
649
|
+
|
|
545
650
|
<!-- COMMANDS + LINKS -->
|
|
546
651
|
<section class="contact-section" id="commands">
|
|
547
652
|
<div class="contact-inner">
|
|
@@ -585,6 +690,7 @@
|
|
|
585
690
|
<div class="cmd-row"><span class="cmd-name">fleece wallet</span><span class="cmd-desc">Portfolio analysis — coverage, overlaps, gaps</span></div>
|
|
586
691
|
<div class="cmd-row"><span class="cmd-name">fleece roi</span><span class="cmd-desc">First-year ROI estimate by spend profile</span></div>
|
|
587
692
|
<div class="cmd-row"><span class="cmd-name">fleece recommend</span><span class="cmd-desc">Card recommendations for a spending profile</span></div>
|
|
693
|
+
<div class="cmd-row"><span class="cmd-name" style="color:var(--yellow)">fleece mcc</span><span class="cmd-desc">Look up a merchant category code — find your best card at checkout</span></div>
|
|
588
694
|
<div class="cmd-row"><span class="cmd-name" style="color:var(--yellow)">fleece flights</span><span class="cmd-desc">PointsYeah award flight search URL — no API key needed</span></div>
|
|
589
695
|
<div class="cmd-row"><span class="cmd-name" style="color:var(--yellow)">fleece hotels</span><span class="cmd-desc">PointsYeah award hotel search URL — no API key needed</span></div>
|
|
590
696
|
</div>
|
|
@@ -20,8 +20,9 @@ install_claude() {
|
|
|
20
20
|
cp "$f" "$dest"
|
|
21
21
|
done
|
|
22
22
|
echo "✓ Claude Code skills installed to $TARGET/"
|
|
23
|
-
echo "
|
|
24
|
-
echo "
|
|
23
|
+
echo " Research: /fleece-card /fleece-rates /fleece-partners /fleece-credits"
|
|
24
|
+
echo " /fleece-news /fleece-compare /fleece-wallet /fleece-roi /fleece-recommend"
|
|
25
|
+
echo " Redemption: /fleece-mcc /fleece-flights /fleece-hotels"
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
install_agents() {
|
|
@@ -58,4 +59,5 @@ case "${1:-auto}" in
|
|
|
58
59
|
esac
|
|
59
60
|
|
|
60
61
|
echo ""
|
|
61
|
-
echo "
|
|
62
|
+
echo "BRAVE_API_KEY is optional — mcc, flights, and hotels work without it."
|
|
63
|
+
echo "Set BRAVE_API_KEY in your environment or .env file to enable live research commands."
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fleece-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Credit card research and redemption CLI — live data via Brave Search, PointsYeah URL generation, designed for humans and AI agents."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
fleece_cli-0.3.0/CLAUDE.md
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Fleece - Credit Card Research Chatbot
|
|
2
|
-
|
|
3
|
-
## Project Overview
|
|
4
|
-
**Fleece** is a Streamlit-based conversational AI application designed to help users find the best credit cards for their needs. The tagline is "Find the best card for deal saviors."
|
|
5
|
-
|
|
6
|
-
### Core Purpose
|
|
7
|
-
Fleece is a chatbot that:
|
|
8
|
-
- Uses OpenAI's chat models (gpt-3.5-turbo, gpt-4, gpt-4-turbo, gpt-4o) to provide conversational credit card research and recommendations
|
|
9
|
-
- Maintains entity-based memory across conversations to remember user details and preferences
|
|
10
|
-
- Allows users to explore available credit cards and manage their existing card portfolio
|
|
11
|
-
- Stores conversation history and provides download capability
|
|
12
|
-
|
|
13
|
-
### Tech Stack
|
|
14
|
-
- **Frontend**: Streamlit (Python web app framework)
|
|
15
|
-
- **LLM**: OpenAI ChatGPT (via LangChain)
|
|
16
|
-
- **Memory**: ConversationEntityMemory (tracks entities mentioned in conversation)
|
|
17
|
-
- **Language**: Python
|
|
18
|
-
|
|
19
|
-
## Key Features
|
|
20
|
-
1. **Conversational Interface**: Chat with an AI assistant about credit cards
|
|
21
|
-
2. **Entity Memory**: Remembers details about the user across conversation turns
|
|
22
|
-
3. **Multi-model Support**: Choose between different OpenAI models
|
|
23
|
-
4. **Conversation Management**:
|
|
24
|
-
- Start new chats
|
|
25
|
-
- Browse past conversation sessions
|
|
26
|
-
- Download conversation history
|
|
27
|
-
- Customize memory buffer size (K parameter)
|
|
28
|
-
5. **Navigation**: Planned pages for "Credit Cards" exploration and "My Credit Cards" management
|
|
29
|
-
|
|
30
|
-
## Current Limitations & Opportunities
|
|
31
|
-
- **Limited knowledge**: Currently relies on OpenAI's training data, which may be outdated for credit card details
|
|
32
|
-
- **No specialized tools**: The chatbot cannot search current issuer websites or real-time data sources
|
|
33
|
-
- **No structured research**: Lacks the ability to provide specific, verified credit card information (fees, benefits, offers, transfer partners, etc.)
|
|
34
|
-
|
|
35
|
-
## Future Integration Opportunities
|
|
36
|
-
- **Multi-page app expansion**: Build out the "Credit Cards" discovery page and "My Credit Cards" portfolio management
|
|
37
|
-
- **Database backend**: Store user profiles, card portfolios, and preferences
|
|
38
|
-
|
|
39
|
-
## CLI — Redemption Commands
|
|
40
|
-
The `fleece flights` and `fleece hotels` commands are merged from the former `pointsyeah-cli` project (now archived). They generate PointsYeah search URLs with no API key required — pure stdlib, zero external dependencies. Source lives in `pointsyeah.py`.
|
|
41
|
-
|
|
42
|
-
## Development Notes
|
|
43
|
-
- Author: Yuan Chen
|
|
44
|
-
- Created: March 16, 2025
|
|
45
|
-
- Uses custom CSS styling (style.css)
|
|
46
|
-
- Requires OpenAI API key (entered via sidebar, not stored)
|
|
47
|
-
|
|
48
|
-
## Infrastructure Notes
|
|
49
|
-
- **Databricks**: No Databricks resources are available at the moment. The Databricks App deployment workflow has been removed. Do not suggest or implement Databricks-based solutions until resources are provisioned.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|