← all systems
OUTBOUNDSIGNAL DETECTIONAI AGENT

Growth Signal Icebreaker

Growth signal fires. The right person gets a relevant message. Nobody touched it.

49 nodes4 workflowsn8n · Pronto · Airtable · Claude · LaGrowthMachine▶ watch walkthrough

The Problem

I got tired of watching the same cycle: reps get a list of 500 companies, write the same intro email with a name swapped in, and call it "personalized." Meanwhile the companies actually showing growth signals get the same generic outreach as everyone else. I built this to flip the order: detect the signal first, find the decision-maker second, validate the email third, then spend LLM budget on an icebreaker that's actually relevant to what's happening at their company right now. If the email can't be verified, Claude never fires. No budget burned on a message that bounces.

Stack

⚙️
n8n
Orchestrates all 4 decoupled async workflows
🔍
Pronto
Hiring + growth signal detection, lead search, and bulk enrichment
📋
Airtable
Shared state store — companies, contacts, settings, and mid-flight inspection
🧠
Claude
3-layer icebreaker generation: lead context + company signal + knowledge base
🚀
LaGrowthMachine
Outbound sequence enrollment via API

Walkthrough

How It Works

The execution path

01Signal Detected
02Company Enriched
03Lead Qualified
04Icebreaker Sent
Execution flow
WF1 fires Monday 9amhiring + growth signals
Pronto detects signal companiesasync
WF2 receives companies → enriches → saves to Airtable
Submit lead search with airtable_company_id
WF3 receives leads → filters ICP → saves to Airtable
Bulk enrich: airtable_lead_id + airtable_company_id in custom field
WF4 receives enriched contact → Pronto echoes IDs back
Merge 3 layers → Claude writes icebreaker → LGM enrolls
The hardest part wasn't the AI — it was the data thread. Pronto has no concept of your internal records. When the final workflow receives an enriched contact via webhook callback, it needs to find the exact company and lead records in Airtable. The solve: pass internal IDs through Pronto's custom field. Pronto echoes them back. Four async workflows, zero shared memory, and the records always resolve.
WF1 — Signal Trigger (Monday 9:00am)

Reads targeting config from Airtable Settings and fires TWO parallel async calls to Pronto simultaneously — hiring signal and growth signal. Both are fire-and-forget.

  • ·Read targeting config from Airtable Settings
  • ·Fire async: companies posting sales/revenue roles (hiring signal)
  • ·Fire async: companies growing headcount above threshold (growth signal)
  • → Both calls deliver results to WF2 via webhook
WF2 — Company Reception + Enrichment (webhook)

Receives company batches and processes one at a time with a 30-second rate limit. Saves each to Airtable, gets the record ID, then submits an async lead search — passing the Airtable ID forward.

  • ·Parse and normalize company payload
  • ·Loop one company at a time (30s rate limit)
  • ·Enrich via Pronto: LinkedIn URL, headcount, industry
  • ·Save to Airtable Companies → receive record ID
  • ·Look up persona UUID from Airtable Personas table
  • ·Submit async lead search scoped to company domain + persona
  • → Pass airtable_company_id with the search request
WF3 — Lead Reception + Enrichment (webhook)

Filters leads by ICP title before spending enrichment credits. The critical move: passes both airtable_lead_id and airtable_company_id through Pronto's custom field so WF4 can find the right records.

  • ·Parse leads array
  • ·Filter: CTO, Chief Technology Officer, VP Engineering only
  • ·Save qualified leads to Airtable Contacts (linked to company)
  • ·Aggregate into bulk enrichment request
  • ·Pass airtable_lead_id + airtable_company_id via Pronto custom field
  • → Pronto echoes custom field back in enrichment webhook
WF4 — Icebreaker Generation + Enrollment (webhook)

Merges 3 data layers — lead context, company signal, and product knowledge base — before Claude writes. Email is a hard gate: if no deliverable email, Claude never fires. Zero wasted LLM spend.

  • ·Receive enriched contact + custom IDs from Pronto
  • ·Fetch lead details from Airtable using airtable_lead_id
  • ·Fetch company details from Airtable using airtable_company_id
  • ·Fetch knowledge base + LGM audience ID from Airtable Settings
  • ·Merge: lead context + company signal + knowledge base
  • ·Claude writes icebreaker (1–2 sentences, never starts with "I" or lead name)
  • ·Update Airtable: icebreaker saved, Enrichment Status = "Enriched"
  • ·POST to LaGrowthMachine: enroll in outbound sequence
  • ·Update Airtable: LGM Status = "Enrolled", LGM Enrolled At = today

Key Design Decisions

🧵
The Data Thread
airtable_company_id travels through Pronto's custom field across all 4 workflows. WF4 finds the exact right records every time with no shared state.
🎯
3-Layer AI Context
Lead + company signal + knowledge base, all merged before Claude writes. Every icebreaker is unique. None are templates.
🚪
Email as Hard Gate
Claude only fires when a deliverable email exists. Zero wasted LLM spend on unverified contacts.
🔍
Airtable as Inspection Layer
Every company, lead, icebreaker, and status is visible mid-flight. Any stage can be re-triggered independently.

By The Numbers

49
Nodes
4
Workflows
0
LLM calls on unverified emails
3
Context layers per icebreaker
← back to all systemsmatthew batterson · gtm engineer