Autonomous outbound pipeline — ingest contacts (CSV audiences or a HubSpot list), run signal intelligence (ERP technographics + the five ROAD triggers), route each contact to a persona agent that writes Value Global ERP Data Retirement copy, then enroll into an Email Bison email campaign (subject1-4/body1-4 custom variables) and a HeyReach LinkedIn campaign. Sells Value Global's ERP archiving/retirement service to the owners of aging Oracle ERP systems at US/Canada enterprises. Use to run or operate this pipeline.
Resources
1Install
npx skillscat add ameyadeshmukh10/sdr-console-value-global/sdr-pipeline Install via the SkillsCat registry.
SDR Pipeline — CSV/HubSpot → signal intel → persona agents → Email Bison + HeyReach
Operationalizes the ai-sdr engine end to end. Ingest contacts (CSV audiences are the primary
source — the client has no CRM) → signal intelligence researches each account (ERP
technographics, the five ROAD news triggers, hiring) → the human approves segments → each ICP
contact routes to a persona subagent that writes the copy → enroll into one Email Bison
campaign and one HeyReach campaign. Offer: Value Global ERP Data Retirement only. Audience:
US/Canada enterprise IT, ERP, database, and data-governance owners (buyer_group.py
enforces this; the account suppression list and the Fusion-only rule block do-not-contact
accounts at ingest, the segment gate, and enrollment).
Bison instance: send.everworker.ai (token in .env).
One-time setup
.env: setBISON_CAMPAIGN_IDto the client's Bison campaign (single-campaign routing;
optional per-persona/per-variant envs exist for later).HUBSPOT_LINKEDIN_PROPERTYdefaults
tohs_linkedin_url(HubSpot is dormant — no CRM for this engagement).- The Bison campaign must have 4 sequence steps whose subject/body reference the custom
variables{{subject1}}/{{body1}}…{{subject4}}/{{body4}}, plus the sender signature. - LinkedIn (HeyReach) is DEFERRED until the client's personal-profile senders are ready.
HEYREACH_CAMPAIGN_ID/…_ACCOUNT_IDare blank, so enrollment skips LinkedIn. To enable
later: set those, and the HeyReach campaign's message steps must reference custom fields{{li_connect}},{{li_msg1}},{{li_msg2}}. - Load the do-not-contact list before the first send (hard client requirement):
python3 .claude/skills/sdr-pipeline/scripts/suppression.py load --file data/outreach/suppression_seed.csv
(or the console's Do-not-contact panel on the Use view).
Run (autonomous)
- Ingest: upload a CSV audience in the console's Use view (gated: contacts wait at the
segment gate), orpython3 .claude/skills/sdr-pipeline/scripts/csv_audience.py ingest ….
Import flags surface missing LinkedIn URLs, non-US/CA rows, healthcare, and sub-1,000
headcount; hard suppression-list matches never enter the pipeline. - Generate copy per contact: for each approved contact, invoke the subagent named by its
persona(Task tool) with the contact fields. Save the agent's JSON todata/outreach/generated/<contact_id>.json. Persona → agent:erp-owner→ sdr-erp-ownerdba→ sdr-dbadata-governance→ sdr-data-governanceit-leadership→ sdr-it-leadership
(For large lists, run this fan-out as aWorkflowto pipeline contacts concurrently.
Messaging is uniform across personas by client decision; the persona routes reporting.)
- Enroll:
python3 .claude/skills/sdr-pipeline/scripts/enroll.py- Dry-run first: add
--dry-runto print the exact Bison + HeyReach payloads without sending. - Bison:
create_leadwithcustom_variablessubject1-4/body1-4→attach_leads_to_campaign(BISON_CAMPAIGN_ID). - HeyReach:
AddLeadsToCampaignV2(HEYREACH_CAMPAIGN_ID)withcustomUserFields {li_connect,li_msg1,li_msg2}
(skipped for contacts without a LinkedIn URL — email still sends). - Idempotent via the pipeline DB; re-runs skip already-enrolled contacts.
- Refuses to enroll email copy that fails the guardrail linter (
--no-lintto override), and
re-checks the suppression list + the Fusion-only rule as a backstop.
- Dry-run first: add
Generated-asset schema (data/outreach/generated/<contact_id>.json)
{
"contact_id": "csv-ab12cd34-1", "persona": "erp-owner", "signal": "role anchor - detected Oracle EBS",
"email": {"subject1":"…","body1":"…","subject2":"…","body2":"…",
"subject3":"…","body3":"…","subject4":"…","body4":"…"},
"linkedin": {"li_connect":"…","li_msg1":"…","li_msg2":"…"}
}Guardrails (enforced)
- Only ICP buyer-group titles are written/enrolled (
persona_for_titleinbuyer_group.py). - The account suppression list + the Fusion-only technographic rule block do-not-contact
accounts at ingest, the segment gate, and enrollment. - Email copy must pass
lint_sequence.py(35-110w, question opener, read-only ask in touch 1,
RE: subject chain, the VG ban list and claim discipline, breakup step 4, no pricing) —enroll.pyblocks failures. - All product claims trace to
ai-sdr/knowledge/offer.md; no fabricated signals/stats.
Batch mode (scale, parallel, low-token) — /sdr-batches
For the full list, use the SQLite-backed batch system instead of hand-dispatching:
- Slash command:
/sdr-batches [N|all] [enroll]— batches contacts (25/batch), dispatchessdr-batch-runnersub-agents in parallel to generate copy, then dry-runs (or live-runs) enrollment.
The recipe is encoded in.claude/commands/sdr-batches.md, so invoking it costs almost no thinking. - Terminal CLI (
scripts/sdr_batches.py, state indata/outreach/pipeline.db):init(contacts.jsonl → batches of 25) ·status·pending-batches·get-batch <id>·ingest <id>(lint + mark) ·enroll [--dry-run]·reset-batch <id>. sdr-batch-runneragent processes one batch of 25 end to end (write → save →ingest).
Statuses per contact: pending → generated → enrolled (or failed, with the lint reason).- New sub-agents/commands may need a Claude Code session reload before first use.
Components
- Clients:
scripts/hubspot_client.py,scripts/heyreach_client.py,email-bison/scripts/bison_client.py(create_lead,attach_leads_to_campaign). - Router:
ai-sdr/scripts/buyer_group.py(persona_for_title). - Suppression:
scripts/suppression.py(do-not-contact list + the Fusion-only rule). - Signal intelligence:
scripts/tech_signals.py(ERP technographics),scripts/news_signals.py
(the five ROAD triggers),scripts/hiring_signals.py. - Agents:
.claude/agents/sdr-*.md(one per persona).
Notes / current state
- Bison instance:
send.everworker.ai(EverWorker's sending infrastructure; token in.env). - HubSpot is dormant for this engagement (the client has no CRM); the CSV audience path is primary.
- LinkedIn (HeyReach) is deferred — email-only until the client's sender profiles are activated
with "archiving" positioning. - The suppression list in
data/outreach/suppression_seed.csvis the client's DRAFT — reload
the signed-off version before the first send.