Skip to content

Leads: project-scoped lead generation and cold outreach - #122

Merged
ralyodio merged 2 commits into
masterfrom
feat/leads-outreach
Jul 26, 2026
Merged

ralyodio merged 2 commits into
masterfrom
feat/leads-outreach

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Adds a Leads tab to every project: find businesses, scan their sites, and pitch the fix — grounded in what the scan actually found.

Where it is

/projects/<id>/leads — tab row, between Uptime and Autoblog. Not in the top nav (project-scoped by design).

What it does

discover → scan → research → draft → send → follow up, drivable three ways off one code path: the Leads UI, an MCP toolset (7 tools), and a 15-minute cron tick.

Lead sources cost nothing by default (DuckDuckGo → Mojeek, plus the prospect's own pages); ValueSERP is used when its key is set. No purchased contact data.

Guardrails

  • Dry run by default everywhere that contacts anyone
  • auto_send defaults false — a new campaign builds and drafts, then stops
  • Global do-not-contact list; one-click unsubscribe (address or whole domain)
  • CAN-SPAM postal address required before any live send
  • Drafts are rejected if they cite a score/report that doesn't exist or imply a prior relationship
  • Sites that already score well are skipped rather than pitched a rescue
  • Reddit: live subreddit rules are a hard stop, public replies preferred, one cold DM per person ever, disclosure required

Also

Drops the "under 24 hours" turnaround promise from /hire — engagements now run 2–3 weeks at $100/hour.

State

  • Migration already applied to production (4 tables, RLS on, no policies)
  • 628 tests pass, typecheck clean, build green

Before it fully works

  1. Set OUTREACH_POSTAL_ADDRESS on Railway — live sending is refused without it (dry runs work)
  2. No pg_cron job for /api/cron/outreach yet, so campaigns won't self-run until one is scheduled
  3. Reconnect Reddit at Settings → Social (OAuth scopes widened to read + privatemessages)

🤖 Generated with Claude Code

ralyodio and others added 2 commits July 26, 2026 15:44
Finds businesses, scans their sites, and pitches the fix — grounded in what
the scan actually found rather than in a merge field.

Modelled on two paid MCP servers, neither of which is the design. Velvet
Forge is seven LLM prompt wrappers whose "personalisation" never looks at
the prospect's website. Signal Found sells thousands of Reddit DMs a day
through a browser extension replaying your session or a farm of managed
accounts, which is against Reddit's User Agreement and ends with the domain
banned sitewide. CrawlProof already runs the scanner, so it can open with a
defect verifiably on their site, linked to a report they can check.

The funnel — discover, scan, research, draft, send, follow up — runs
unattended from a 15-minute cron tick, or step by step from the Leads tab
or the MCP toolset. All three share one code path so the guardrails cannot
differ between what the robot does and what the button does.

Leads belong to a project: the same agency runs different outreach for
different clients. Send caps stay per person — one operator with five
projects still has one sending reputation.

Guardrails, which are the design and not a bolt-on:
  - dry run by default everywhere that touches the outside world
  - auto_send defaults false; a new campaign builds and drafts, then stops
  - global do-not-contact list; one-click unsubscribe scoped to an address
    or a whole domain, with its own token so a cold recipient is never
    enrolled in the newsletter to be given an opt-out
  - CAN-SPAM postal address required before any live send
  - generated drafts are rejected if they cite a score or report that does
    not exist, or imply a prior relationship
  - sites that already score well are skipped rather than pitched a rescue
  - Reddit: live subreddit rules are a hard stop, public replies preferred,
    one cold DM per person ever, disclosure required

Lead sources cost nothing by default (DuckDuckGo, Mojeek, the prospect's own
pages) and use ValueSERP when its key is set. No purchased contact data.

Tests cover the decisions that carry risk: suppression ordering, contact
discovery and ranking, grounding checks, thread scoring, reply validation.
Three bugs they caught are fixed here — logo@2x.png passing as an address,
shared inboxes outranking named humans, and phone extraction returning
dates and postal codes.

Migration applied to production.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Engagements are now ~$12k and run two to three weeks at $100/hour, so
"< 24h turnaround" and "live the same business day" were promises the
delivery model can no longer keep. A timeline claim a buyer discovers is
false during onboarding costs more than the urgency it bought.

Replaces it with what is actually true: work is scoped from the findings in
their own report, billed at $100/hour, typically two to three weeks. That
also matches lib/audit/quote.ts, which already prices remediation at
$100/hour and caps at 120 hours before asking for manual scoping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ralyodio
ralyodio merged commit bfbbdf7 into master Jul 26, 2026
6 checks passed
@ralyodio
ralyodio deleted the feat/leads-outreach branch July 26, 2026 16:27
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant