feat: Tier B operator scaffolding — bundle, copy SoT, posts, emails
Pick up and finish yesterday's cut-off Tier B pass. - build/: PyInstaller scaffold (datatools.spec + launcher.py + hook-streamlit.py + README) — folder-mode bundle, locked 127.0.0.1, per-OS recipe - marketing/COPY.md: single source of truth for every customer-facing string — landing H1/sub/CTAs, demo CTAs, email subjects, Gumroad listing, banned phrases - marketing/community-posts/: 9 drafts (3 posts × 3 niches: bookkeeper, revops, shopify-pet) — story / tip / soft-offer - marketing/emails/: 18 drafts (Gumroad delivery + 5-touch onboarding × 3 niches), per-niche segmentation guidance - docs/NEXT-STEPS.md: flip 2.2 / 2.4 / 3.1 / 3.4 to done with pointers to the new assets; add Phase 0 inventory rows - .gitignore: narrow `build/` ignore so PyInstaller spec + launcher + hooks get tracked, only generated artifacts (build/build/, build/__pycache__/, build/dist/) stay ignored Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
34
marketing/emails/shopify-pet/00-delivery.md
Normal file
34
marketing/emails/shopify-pet/00-delivery.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Shopify-pet · Day 0 — Delivery email
|
||||
|
||||
**Subject:** Your DataTools download (start here)
|
||||
**Send:** immediately on Gumroad purchase confirmation
|
||||
**Goal:** download + first run within 24h
|
||||
|
||||
---
|
||||
|
||||
Hi {{first_name}},
|
||||
|
||||
Thanks for buying DataTools. Your download:
|
||||
|
||||
→ **{{download_url}}**
|
||||
|
||||
Three things to do in the next 5 minutes:
|
||||
|
||||
**1. Download the installer for your OS** (Mac `.dmg`, Windows `.exe`, or Linux `.tar.gz`). About 280 MB. The link auto-detects.
|
||||
|
||||
**2. Run it.** First launch takes ~5 seconds; a browser tab opens to `127.0.0.1:8501`. That's the app — running locally on your machine. No data leaves the box. Your customer list never goes to a server.
|
||||
|
||||
**3. Drop in a real Shopify customer export.** Don't bother with the bundled samples. Customers > Export > "All customers" > CSV in Shopify admin. Drag it into DataTools' analyzer, click **"Run all"**. You'll see what it catches — typically a few hundred phone-format issues, some hidden-character emails, and a handful of cross-row duplicates — in about 30 seconds.
|
||||
|
||||
If something doesn't work: reply to this email. Goes to my inbox.
|
||||
|
||||
Refund: also reply. 30-day no-questions; no form.
|
||||
|
||||
Tomorrow I'll send a sample Shopify customer export with the tricky cases pre-built in, so you can see what the cleanup catches on a known input. After that you'll get one email a week for the next month with one tip each. Unsubscribe at the bottom of any of them.
|
||||
|
||||
Welcome aboard.
|
||||
|
||||
— Michael
|
||||
{{support_email}}
|
||||
|
||||
P.S. Got a fellow store owner who'd find this useful? {{landing_page}}.
|
||||
32
marketing/emails/shopify-pet/01-day1.md
Normal file
32
marketing/emails/shopify-pet/01-day1.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Shopify-pet · Day 1 — Try it on this Shopify customer export first
|
||||
|
||||
**Subject:** Try it on this Shopify customer export first
|
||||
**Send:** Day 1, ~9am buyer-local-time
|
||||
|
||||
---
|
||||
|
||||
Hi {{first_name}},
|
||||
|
||||
Yesterday's email had your download. Today's email has a *file* — a synthetic Shopify customer export I built specifically to break things Klaviyo silently chokes on.
|
||||
|
||||
→ **{{sample_file_url}}** (480 KB CSV, 2,200 rows — fully synthetic, no real customer data)
|
||||
|
||||
What's hidden in there:
|
||||
|
||||
- Phone numbers in 6 different formats (`(415) 555-0143`, `415.555.0143`, `4155550143`, `+44 20 7946 0958` without country field, `+1-415-555-0143 ext 12`, `415 555 0143`)
|
||||
- Email addresses with embedded zero-width spaces (looks identical to a clean email; Klaviyo treats as different addresses)
|
||||
- ~80 obvious customer duplicates (same email, different case)
|
||||
- ~40 cross-row duplicates (different email, same name + same shipping address — usually the same person ordering with two emails)
|
||||
- Shipping addresses with mixed `St.` / `Street` / `St` / `STREET` for the same street name
|
||||
- 12 customers from outside North America with country field blank
|
||||
|
||||
Drop it into DataTools. Click **"Run all"** in the analyzer. Then run **format → dedupe → text-clean → gate** in that order.
|
||||
|
||||
Look at the **gate report** at the end — it'll tell you exactly which rows would have broken Klaviyo, with a one-line "why" per row.
|
||||
|
||||
If you want to see the difference: import the **raw** file to a test Klaviyo list, then import the **cleaned** file to a different test list. Compare the SMS-deliverable count. The delta is what you've been losing every month.
|
||||
|
||||
Reply and tell me what it caught (or missed) — v1.1 detector improvements come from real-world feedback.
|
||||
|
||||
— Michael
|
||||
{{support_email}}
|
||||
33
marketing/emails/shopify-pet/02-day3.md
Normal file
33
marketing/emails/shopify-pet/02-day3.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Shopify-pet · Day 3 — The phone-format step Klaviyo cares about
|
||||
|
||||
**Subject:** The phone-format step Klaviyo cares about
|
||||
**Send:** Day 3
|
||||
**Goal:** deepen feature understanding around the format standardizer
|
||||
|
||||
---
|
||||
|
||||
Hi {{first_name}},
|
||||
|
||||
The single biggest source of "Klaviyo dropped this customer silently" is phone formatting. DataTools fixes this in one tool — the **format standardizer** — but the *settings* matter.
|
||||
|
||||
Klaviyo (and basically every modern SMS platform) wants phones in **E.164** format: `+` then country code then number, no spaces, no dashes, no extension. Like: `+14155550143`.
|
||||
|
||||
Three settings in DataTools' format standardizer that get this right:
|
||||
|
||||
**1. Set "Phone output format" to `E.164`.** Default is `national` (`(415) 555-0143`) — fine for display, broken for Klaviyo. Change it once; the preset remembers.
|
||||
|
||||
**2. Set "Default country" per row, not per file.** This is the non-obvious one. For each customer:
|
||||
- If the `country` field has a value (e.g., "Canada", "CA", "Canadá"), use it.
|
||||
- If blank, fall back to the country in the *shipping address*.
|
||||
- If still blank, fall back to the file-level default (you set this — typically your store's primary market).
|
||||
|
||||
DataTools does this automatically when you check "Use per-row country detection". *Skip this and ~30% of international customers will end up with US country codes prepended to their numbers — which Klaviyo accepts but routes wrong, and your SMS never arrives.*
|
||||
|
||||
**3. Set "Quarantine un-parseable phones" to ON.** Don't drop them silently; don't pass them to Klaviyo broken. Send them to `<filename>.quarantine.csv` so you can fix the worst 10-20 by hand and re-include them.
|
||||
|
||||
The combination — E.164 + per-row country + quarantine — typically takes a Shopify export from "60-70% of phones survive Klaviyo's import" to "97-99%". On a 10,000-customer list, that's 2,500 - 3,500 more customers reachable per campaign.
|
||||
|
||||
Reply if you want me to walk through these settings on a screen-share — happy to do this for any buyer in the first 30 days.
|
||||
|
||||
— Michael
|
||||
{{support_email}}
|
||||
35
marketing/emails/shopify-pet/03-day7.md
Normal file
35
marketing/emails/shopify-pet/03-day7.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Shopify-pet · Day 7 — Run it before every Klaviyo sync
|
||||
|
||||
**Subject:** Run it before every Klaviyo sync
|
||||
**Send:** Day 7
|
||||
**Goal:** reframe from one-off tool to per-sync workflow
|
||||
|
||||
---
|
||||
|
||||
Hi {{first_name}},
|
||||
|
||||
A week in. By now you've probably run DataTools on a real customer export once or twice and seen the cleanup catch things you'd been losing in Klaviyo for months.
|
||||
|
||||
The thing that turns DataTools into a recurring win instead of a one-off purchase: **run it before every sync, not just the first time.**
|
||||
|
||||
The pattern that works for most stores:
|
||||
|
||||
**1. Pick a cadence.** Most stores I talk to do this monthly; high-volume stores do it weekly. The cadence should match your "I'm planning a campaign" rhythm.
|
||||
|
||||
**2. The Sunday-morning ritual:**
|
||||
- Pull a fresh customer export from Shopify (Customers > Export > "All customers")
|
||||
- Drop into DataTools
|
||||
- Run the pipeline (analyzer → format → text-clean → dedupe → gate)
|
||||
- Review the gate quarantine file (typically 0.5-2% of rows)
|
||||
- Push the cleaned CSV to Klaviyo (their CSV import or via their API)
|
||||
|
||||
**3. Save your settings as a preset.** The "Save settings" button writes a `.datatools-preset.json`. Keep it in your store's Drive / Notion / wherever your shop docs live. Next month, load preset, run pipeline, done in 4 minutes.
|
||||
|
||||
**4. After 3 months, retune the preset.** Look at your manual-review queue across the 3 runs. If you're consistently approving 0.86-confidence merges, drop the auto-merge threshold to 0.85. If you're rejecting 0.92 merges, raise it to 0.94. The preset improves with use.
|
||||
|
||||
The store owners doing this monthly tell me their open rates go up 8-15% in the first 90 days — not from new content, just from the email actually reaching the inbox.
|
||||
|
||||
If you want, reply with a sanitized export and I'll suggest a starting preset for your store — happy to do this for the first 50 buyers.
|
||||
|
||||
— Michael
|
||||
{{support_email}}
|
||||
32
marketing/emails/shopify-pet/04-day14.md
Normal file
32
marketing/emails/shopify-pet/04-day14.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Shopify-pet · Day 14 — Two-minute trick: hidden-character cleanup
|
||||
|
||||
**Subject:** Two-minute trick: hidden-character cleanup
|
||||
**Send:** Day 14
|
||||
**Goal:** surface the text cleaner — non-obvious, high-value
|
||||
|
||||
---
|
||||
|
||||
Hi {{first_name}},
|
||||
|
||||
The tool inside DataTools that buyers find last is the **text cleaner** — and on Shopify customer exports it's usually the one with the most "wait, that was a problem?" moments.
|
||||
|
||||
What it catches: invisible characters that got into your customer data when customers typed on their phones. The most common offenders:
|
||||
|
||||
- **Zero-width space** (`U+200B`) inside emails — Klaviyo treats `sarah@acme.com` (with hidden char) and `sarah@acme.com` (without) as different addresses
|
||||
- **Non-breaking space** (`U+00A0`) inside addresses — Shopify accepts it, Klaviyo accepts it, but USPS address validation fails on it
|
||||
- **BOM marker** (`U+FEFF`) at the start of CSV cells — usually from a customer pasting from Word or a PDF
|
||||
- **Right-to-left mark** (`U+200F`) — rare, but appears in customer names from Hebrew/Arabic locales
|
||||
|
||||
The 2-minute workflow:
|
||||
|
||||
1. After the format standardizer pass, run the text cleaner.
|
||||
2. It produces an additional sidecar file: `<filename>.hidden-chars.csv` — every cell where it found a hidden char, with a "what was hidden where" annotation.
|
||||
3. Skim it. Most are fine to silently strip (zero-width spaces, BOMs). For rare ones (right-to-left marks in a name), confirm before stripping — sometimes they're load-bearing.
|
||||
4. Click "Apply cleanup". The text cleaner replaces the hidden chars in the cleaned CSV.
|
||||
|
||||
The reason this matters: **dedupe runs after text-clean.** Two emails with a hidden char difference look identical in the GUI but get treated as two separate customers — and your dedupe pass won't catch them unless the text cleaner ran first.
|
||||
|
||||
The pipeline order baked into the GUI is: `analyzer → format → text-clean → dedupe → gate`. Stick to it; per-tool runs out of order are the most common source of "wait, why didn't dedupe catch this?".
|
||||
|
||||
— Michael
|
||||
{{support_email}}
|
||||
26
marketing/emails/shopify-pet/05-day30.md
Normal file
26
marketing/emails/shopify-pet/05-day30.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Shopify-pet · Day 30 — Heard from another store owner?
|
||||
|
||||
**Subject:** Heard from another store owner?
|
||||
**Send:** Day 30
|
||||
**Goal:** referral / review ask
|
||||
|
||||
---
|
||||
|
||||
Hi {{first_name}},
|
||||
|
||||
A month in. If DataTools earned its $49 — would you do me one small favor?
|
||||
|
||||
**Pick the one that's easiest.**
|
||||
|
||||
1. **Gumroad review** (60 seconds): {{download_url}}#reviews — every line helps the next Shopify owner trust the listing enough to click "buy".
|
||||
2. **Reply to this email with one sentence I can quote** on the landing page. Anonymous if you prefer; I'll never use a name without explicit permission.
|
||||
3. **Share the landing page** with one fellow store owner who'd benefit: {{landing_page}}. No referral commission, just a link.
|
||||
|
||||
If DataTools *didn't* earn its $49 — also reply. Tell me what's missing or broken. The 30-day refund window is still open and I'd rather refund than have an unhappy customer in the wild.
|
||||
|
||||
Either way, this is the last automated email you'll get from me. After this you only hear from me when there's a v1.x update or if you reply to one of the previous emails.
|
||||
|
||||
Thanks for being an early buyer — the first 50 customers shape the next 5,000.
|
||||
|
||||
— Michael
|
||||
{{support_email}}
|
||||
Reference in New Issue
Block a user