il-marketplace-pull skill (v2 — consolidated 2026-04-28)
Role: IL-specific data adapter feeding the centralized acquisition_deals table. Adds wholesaler company-level enrichment that the base IL pipeline doesn’t cover.
v2 change vs v1: Five scripts that duplicated existing workspace code have been retired. v2 keeps only the genuinely-new pieces.
⚡ Execution-mode model routing (G-MODEL-ROUTING-AT-EXEC)
This skill is execution-mode by definition. Per CLAUDE.md “MANDATORY: Execution-Mode Model Routing” + feedback_model_routing_at_exec.md:
Step 1 of every invocation: decompose the work and dispatch via the Agent tool with model: "sonnet" using the 8-element prompt contract (task goal, evidence, tool to use, test requirements, acceptance criteria, rollback command, rule constraints, output format).
Opus (main conversation) role = dispatcher + verifier + Henry-gate. Direct Opus script invocation / code edits = governance violation unless the work fails the Sonnet rubric (novel architecture, rule arbitration, Henry decision gate, first instance of a new pattern). Verify each subagent report against acceptance criteria before marking complete.
Architecture (where this skill sits)
IL list/detail API
│
▼
[workspace/scripts/sync-il-api-to-supabase.js] ← list pull (existing, NOT in this skill)
[workspace/scripts/enrich-il-deals-detail-api.js] ← detail + description regex mining (existing)
│
▼
acquisition_deals (CCP — universal source-agnostic table)
│
▼
[acquisitions-outreach skill] ──→ HubSpot via [hubspot-deal-ingest skill]
│
▼ (parallel branch — what THIS skill adds)
[il-marketplace-pull/scripts/enrich-contacts.js] → wholesaler_contacts (Apollo + Hunter)
[il-marketplace-pull/scripts/account-rollup.js] → analytics (no DB write)
What this skill provides (only the net-new)
1. enrich-contacts.js — wholesaler company-level enrichment
For each unique account_id in acquisition_deals (one wholesaler can have 50+ deals), find the wholesaler’s company domain via Apollo and the dispositions manager’s email via Hunter. Writes to wholesaler_contacts table (source-agnostic — works for any source, not just IL).
node ~/.claude/skills/il-marketplace-pull/scripts/enrich-contacts.js \
[--top=50] # top-N accounts by deal count
[--account-id=N] # specific account
[--budget=50] # max Hunter credits per run (free tier = 50/mo)
[--dry-run]Pipeline per account: Apollo /v1/organizations/enrich (free) → Hunter /v2/email-finder (1 credit/match).
2. account-rollup.js — wholesaler analytics
Group by account_id, surface top wholesalers by deal volume. Read-only — no DB writes.
node ~/.claude/skills/il-marketplace-pull/scripts/account-rollup.js \
[--top=25]
[--from-list=/tmp/il-list.json] # offline mode, no DB needed
[--from-db] # query acquisition_deals
[--with-managers] # include manager namesOutput: account_id, total deals, active/pending/sold split, top 3 states, avg price, top wholesalers.
3. cookie-status.sh — IL session probe (kept; doesn’t conflict)
bash ~/.claude/skills/il-marketplace-pull/scripts/cookie-status.shReturns OK (live) or STALE (refresh needed). Auto-SSHes to Mac if run from VPS.
What this skill does NOT do anymore (use existing workspace scripts)
| Task | Use this | Not the v1 script |
|---|---|---|
| Pull IL list, upsert to Supabase | workspace/scripts/sync-il-api-to-supabase.js | scripts/upsert-list.js |
| Detail enrichment + description mining | workspace/scripts/enrich-il-deals-detail-api.js | scripts/enrich-detail.jsscripts/mine-descriptions.js |
| Daily sync orchestration | workspace/scripts/investorlift-daily-sync.sh | scripts/pull-list.sh |
| Cookie refresh | workspace/scripts/investorlift-refresh-cookies.js (Playwright auto-refresh on Mac) | scripts/cookie-refresh.sh |
| HubSpot sync | hubspot-deal-ingest skill (calls workspace/scripts/hubspot-deal-creator.js) | — |
Centralized schema (READ FIRST)
Per project_acquisition_deals_centralized_schema.md (2026-04-28):
- All deal data →
acquisition_deals(CCPsvueekfvfrvhylxygktb, ~70 columns includingmetaJSONB) - All wholesaler company-level data →
wholesaler_contacts(renamed fromdata_il_marketplace_contacts) - NEVER create per-source
data_<source>_*tables again (this skill v1 made that mistake)
Triggers
User says any of:
- “enrich IL wholesaler contacts” / “find IL wholesaler emails”
- “rollup IL accounts” / “top IL wholesalers”
- “check IL cookies” / “are IL cookies stale”
For “pull IL deals” / “scrape investorlift” → DO NOT route here. Route to workspace/scripts/investorlift-daily-sync.sh (the existing pipeline).
Capabilities matrix
| Capability | Where it lives | Cost |
|---|---|---|
| List pull (54K rows) | workspace/scripts (NOT this skill) | Free |
| Detail enrichment (60+ fields, regex-mined phones/emails) | workspace/scripts (NOT this skill) | Free, ~22h sequential |
| Wholesaler domain + LinkedIn (Apollo) | this skill — enrich-contacts.js | Free |
| Wholesaler manager email (Hunter) | this skill — enrich-contacts.js | 1 credit/match, 50/mo free |
| Account-level analytics | this skill — account-rollup.js | Free, query only |
| Cookie freshness probe | this skill — cookie-status.sh | Free |
Failure modes
| Symptom | Cause | Recovery |
|---|---|---|
relation "wholesaler_contacts" does not exist | Schema migration not yet applied | Run schema migration (see HANDOFF-FOR-KIMI Phase 0) |
relation "acquisition_deals" does not exist | Wrong Supabase project | Confirm SUPABASE_URL points to CCP svueekfvfrvhylxygktb |
Hunter 429 | Rate limit | Sleep 60s, retry; consider --budget |
| Apollo returns nothing | Wholesaler too small for Apollo’s index | Skill falls back to heuristic domain (lowercase company.com) |
| Cookie status STALE | IL cookies expired | Run workspace/scripts/investorlift-refresh-cookies.js on Mac (NOT this skill) |
Memory cross-references
- project_acquisition_deals_centralized_schema.md — universal schema decision
- reference_il_marketplace_pipeline.md — IL endpoint discovery memo
- feedback_credentials_via_1password_cli.md — Hunter/Apollo key rotation pattern
v1 → v2 retirement summary (audit by Kimi)
Five scripts retired because they duplicate live workspace code:
| v1 retired | Reason | Replacement |
|---|---|---|
scripts/upsert-list.js | Duplicates sync-il-api-to-supabase.js (writes to acquisition_deals, not data_il_marketplace) | workspace/scripts/sync-il-api-to-supabase.js |
scripts/enrich-detail.js | Duplicates enrich-il-deals-detail-api.js | workspace/scripts/enrich-il-deals-detail-api.js |
scripts/mine-descriptions.js | Already inside enrich-il-deals-detail-api.js (lines 113-118 of that file) | (same) |
scripts/pull-list.sh | Duplicates investorlift-daily-sync.sh orchestration | workspace/scripts/investorlift-daily-sync.sh |
scripts/cookie-refresh.sh | Manual runbook duplicates auto Playwright refresh on Mac | workspace/scripts/investorlift-refresh-cookies.js |
Retirement happens after Kimi confirms the workspace replacements work end-to-end. Until then v1 scripts remain in place but documented as deprecated.