7-Day AIS Challenge - DAY 3 - Skills
It's been a few days since I started day 3.... I got sidetracked setting up my AIOS!
That said, I now have my aios running.
I also created two skills:
/leads <niche> <city> - If any of the values are omitted, the last successful one is tracked in .status and just fills it in. So if I do /leads plumbers reno ... I get a list of 50 plumbers in reno. If I then just do /leads cincinnati, I get 50 plumbers in cincinatti.
/enrich <niche> <city> - uses the same "last run" logic as /leads. This goes out to each lead's website and searches for names, phones, social accounts, blogs, and more, and saves them all into the same table as the leads skill.
Next will be generating customized outreach messaging.
Here's the skill, if folks are interested!
---
name: leads
description: Run a lead scan — pull 50 fresh local-business leads from the gmaps scraper and append them to the lead-gen Google Sheet. One spreadsheet per NICHE, one tab per CITY. Use when asked to get leads, pull leads, scan a market, or refresh the lead sheet.
trigger: /leads
args: optional locus as "NICHE in CITY" (e.g. "landscaping in Raleigh NC"). Omit to reuse the last locus.
---
# Leads Scan
## Goal
Append 50 fresh leads to the lead-gen Google Sheet for a NICHE-in-CITY locus.
Reuse the last locus unless a new one is given. **One spreadsheet per niche; each
tab is a city** — a new city adds a tab to the niche's sheet, a new niche needs its
own spreadsheet.
## Inputs
- **Locus (optional):** free text like `landscaping in Raleigh NC` or `lawn care, Charlotte NC`.
Parse it into a **niche** and a **city** (city keeps its state, e.g. `Charlotte NC`).
If no locus is given, the worker reuses the last one from its state file.
## Steps
1. **Parse the locus** from the argument, if any, into `niche` and `city`.
- "lawn care in Charlotte NC" → niche=`lawn care`, city=`Charlotte NC`.
- If the argument is empty, pass neither flag — the worker reuses the last locus.
2. **Run the worker** from the repo root:
```bash
python .claude/skills/leads/scripts/get_leads.py [--niche "<niche>" --city "<city>"]
```
It self-handles: Google auth (refresh token); **sheet resolution — a new niche
auto-creates `Leads - <niche>` in the same Drive folder as the existing lead
sheets, no prompt**; tab resolution (a new city adds a tab); the gmaps
submit→poll→download; dedupe against rows already in the tab; appending up to 50
fresh rows; and saving the locus. A scan takes a few minutes (the scraper drives a
headless browser) — let it run.
3. **Handle a non-zero exit:**
- Exit **2** (no locus): no locus was given and none is remembered. Ask user
for a `NICHE in CITY` and re-run with `--niche`/`--city`.
- To point a niche at a *pre-existing* Sheet instead of auto-creating, pass
`--spreadsheet-id "<url>"` once; the mapping is then persisted for that niche.
4. **Report** the worker's summary: locus, tab, how many fresh leads landed, how
many score ≥70 (strong fit), and the Sheet link.
## Output Format
```
## Scan complete — <niche> in <city>
- Tab: <tab name>
- Appended: <N> fresh leads (<H> scoring ≥70)
- Sheet: <url>
```
## Rules
- **One spreadsheet per niche; one tab per city.** Tab name is the city (e.g.
`Charlotte NC`). A new city adds a tab; a new niche auto-creates `Leads - <niche>`
in the same Drive folder as the existing lead sheets.
- **Fresh only.** The worker dedupes against rows already in the tab (by phone, then
title+address) — never re-append a known lead.
- **Schema = core + enrichment + disposition** (`HEADER` in the worker). Core (A–J)
is filled from the scrape. The enrichment block (K–AC: `website_status`, social
profiles, blog freshness, lead-capture gaps, `pain_signals`, etc.) is written **empty**
by `/leads` and filled later by the `/enrich` website-visit pass. `disposition` stays
last. Every new sheet/tab gets the full column set automatically.
- **Styling is automatic.** New tabs get a frozen, bold, deep-green header, per-column
widths, centered enum/number columns, a header filter, and score color-coding
(green ≥70 / amber 40–69 / red <10) — see `format_tab`.
- **Maintenance flags:** `--rescore` recomputes the score column across all tabs after
a scoring change; `--format` re-applies the styling. Both iterate every known niche
sheet and exit.
- **Don't disposition.** Leads land raw; the `disposition` column stays blank for the
Sales Closer to fill later. Sales Closer ≠ AI Receptionist — don't conflate.
- **Configuration.**
- Secrets come from the repo-root `.env`. Never echo or hardcode them.
- The per-niche spreadsheet map and last locus persist in `scripts/.state.json`.
Don't commit real lead data; the state file holds only config.
9
2 comments
Simon Page
4
7-Day AIS Challenge - DAY 3 - Skills
AI Automation Society
skool.com/ai-automation-society
Learn to get paid for AI solutions, regardless of your background.
Leaderboard (30-day)
Powered by