← back to Whatsmystyle

docs/SPEC.md

108 lines

# WhatsMyStyle

**One-line:** AI personal stylist that learns your real taste — like an optometrist asks "better A or B?" — and shops resale + retail for you.

## Tagline candidates (placeholder name = WhatsMyStyle)
- "Better A — or B?"
- "Your closet, decoded."
- "Stylist in your pocket. Honesty in your closet."

## The optometrist loop (core mechanic)
Instead of asking "what's your style?", we show you pairs and you click.
After ~30 pairs the model has a usable embedding of your taste.
After ~100 pairs we can predict YES/NO on any new item with >85% accuracy.
We keep refining forever — every save, skip, buy, and return tunes the lens.

## Onboarding — single-question, large-pill UX
One question per screen. Each answer is a huge tappable pill.
Order, with rationale:

1. **Are you shopping for yourself?**  (yes / for someone else / both)
2. **Your gender expression for clothes** (women's / men's / unisex / fluid)
3. **Height** (autofill from previous-session if exists, else slider)
4. **Body shape** (illustrated pills — not weight; weight is invasive)
5. **Hair color + length** (8 illustrated pills)
6. **Age band** (under 25 / 25-34 / 35-44 / 45-54 / 55-64 / 65+)
7. **Skin undertone** (warm / cool / neutral — with swatches)
8. **City** (autofill from geolocation w/ permission)
9. **Budget per piece** (slider: $20 / $50 / $150 / $500 / $1500+ / no cap)
10. **Sustainability priority** (high / nice-to-have / don't care)
11. **The ask** — "Can I look at:"
    - **Your bank receipts** (Stripe Financial Connections — read-only)
    - **Gmail order confirmations** (read-only)
    - **Your camera roll** (selected albums only)
    - **Your social photos** (manual upload — never scrape)
    - **Your location for stores near me** (Google Maps)

Each integration is OPT-IN with a single toggle. Skipping any of them is FINE — we fall back to optometrist-loop only.

## The closet
- Upload photo of your closet → llava:13b extracts garment bounding boxes
- Each garment becomes a record: {category, color, pattern, material_guess, vendor_guess}
- Receipts (Stripe FC + Gmail) match to garments by amount + vendor + date
- Camera roll photos of you wearing items → tagged automatically

## The stylist
- Catalog ingested from RealReal, Poshmark (read-only public listings — never authed scraping)
- Local LLM ranks new arrivals against your taste embedding nightly
- Google Maps shows physical stores within 5mi that carry brands you've liked
- "Try in store" mode — pin items, get walking route through 3 stores

## Dream-team debate gates
Every significant design / spec decision is debated by the dream team (claude-codex-kimi or codex-3way) before commit. Findings logged to `data/debates/`.

## Tech stack
- Node 20 + Express
- SQLite (better-sqlite3) — single-user app, no need for PG
- Local-LLM-first: llava:13b for vision, qwen3:14b for text via Ollama
- Vanilla frontend (no SPA framework) — fast, accessible, large-pill UX
- pm2 process supervision on Mac2 :9777

## Compliance
- Stripe Financial Connections is the ONLY bank-receipt method. Never plaid scrapers, never bank login forms.
- Gmail OAuth scope = `gmail.readonly` ONLY, never modify.
- Social images = USER UPLOAD ONLY, never scrape IG/FB/TikTok.
- Location requested at the moment it's needed, not at onboarding.
- All taste data stored locally in SQLite. No cloud sync until Steve approves.

## Avatar + Virtual Try-On (the magic)

Three modes, all powered by the same digital-twin layer:

### 1. Avatar build
- User uploads 3–8 photos in `My Avatar`
- We POST them to **Dopple** (`POST /v1/twins`) → persistent `twin_id`
- Body proportions extracted via local `llava:13b` for sizing recommendations
- Once `status='ready'`, every screen in the app gets a "Try on me" button

### 2. "Try on me" (catalog item on YOUR avatar)
- Click the button on any duel card or recommendation
- Backend → Dopple `/v1/tryon { twin_id, garment_url }`
- Result lands in **My Try-Ons** in ~30s

### 3. Time-Travel Wardrobe (the killer feature)
The use case that pitched itself: *"I wish I'd worn this dress to my sister's wedding."*

- User picks a piece from **their actual closet** (a previous upload)
- User drops the **old photo** (the wedding, the graduation, prom)
- User taps the occasion pill (or types it)
- Backend → Dopple `/v1/scenes/edit { twin_id, source_image, garment, scene_hint }`
  - `preserve_identity=1` — her face stays her face
  - `preserve_others=1` — wedding party stays intact
  - `preserve_background=1` — venue stays intact
- Result: she's wearing the dress she wishes she'd worn, in the actual photo

### Provider priority (top-down — first one with creds wins)
1. **Dopple** (`DOPPLE_API_KEY`) — purpose-built, highest fidelity, persistent twin
2. **Google Gemini 2.5 Flash Image** (`GEMINI_API_KEY`) — fallback; great for general image edit, no twin persistence
3. **IDM-VTON** / **OOTDiffusion** (open-source, local GPU service) — fully offline path
4. **Stub** — pipes the source through; lets the rest of the app work end-to-end

## Out of scope (v0.1)
- No payments / no checkout — we link out to brand / resale site
- No social features
- No email blasts / push notifications

## Port
:9777