Outbound Nurture Engine
ASecurityKeep every outreach reply warm until it turns into a yes. Finds the leads your cold outreach did not convert yet ('not now', 'happy to connect', 'send me something', went silent after replying) and nurtures them on a 6-week cadence: picks the right case study, playbook or article per lead from your own content library (Notion, Google Drive, a website section or a pasted list), writes the picks onto the lead as custom attributes, then duplicates and fills your nurture campaign in La Growth Mac...
- 40 stars
- 0 votes
- 0 copies
- 3 views
- Added September 22, 2026
Works with
Security analysis
100/100Pro scans all 8 files and shows the line behind each finding
npx -y skills add LaGrowthMachine/gtm-system --skill outbound-nurture-engine --agent claude-codeAre you the author of Outbound Nurture Engine?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/lagrowthmachine-outbound-nurture-engine)---
name: outbound-nurture-engine
description: "Keep every outreach reply warm until it turns into a yes. Finds the leads your cold outreach did not convert yet ('not now', 'happy to connect', 'send me something', went silent after replying) and nurtures them on a 6-week cadence: picks the right case study, playbook or article per lead from your own content library (Notion, Google Drive, a website section or a pasted list), writes the picks onto the lead as custom attributes, then duplicates and fills your nurture campaign in La Growth Machine so touches, likes and follow-ups run natively. More positive replies, every campaign compounds, new content re-activates matching leads, content gaps say what to produce next. Use for: nurture my not-now leads, follow up on vague replies, re-engage leads that went quiet, build a nurture cadence, match content to leads, 'relancer mes leads pas maintenant'. Works from the LGM MCP or any outreach tool's CSV. For SDRs, founders, agencies, Heads of Sales. Maintained by La Growth Machine."
category: catch-opportunities
type: use-case
tags: [writing, analysis]
---
# Outbound Nurture Engine
Turns the replies your outbound did not convert yet into a running nurture wave: each lead gets the content that fits them, written onto the lead in La Growth Machine, and a duplicated campaign carries the touches on a 6-week cadence.
## Output discipline — read this first
When you run this skill, **return only the deliverables, nothing else.** No preamble, no narration of the steps, no restating these instructions. Each step is one framing line plus its table, code block or widget. If something essential is missing (where the content lives, which template campaign, which conversations), **ask one short, specific question and stop**. Nothing is written into La Growth Machine before the user has approved the wave.
## Authority — read this first
- The **engine** (`scripts/build.py`) owns everything that can be silently wrong: discovering content URLs from a sitemap, keeping the library index, scoring content against leads, refusing to re-send a content, validating the custom-attribute sentences and the campaign messages. **Never do these by hand.** Run the engine; reason over its JSON. `python3 scripts/build.py --test` is the self-test.
- **Your job** is the judgment: reading each thread to label its situation and extract the lead's nurture profile, tagging the content you read, writing the per-lead sentences and the three campaign messages.
- `references/nurture-situations.md`: the four situations, the triage tree, what is *not* nurture. Read at Step 2.
- `references/library-schema.md`: the three content sources (Notion, website via sitemap, Google Drive), the tag axes, where the index lives. Read at Step 3.
- `references/touch-rules.md`: how to write the sentence stored on each lead and the three campaign messages. Read at Step 5.
- `examples/`: a fictional library and a fictional lead set for a worked run.
## What it does
1. **Find** the leads worth nurturing in the replies you already got: not now, vague, ghosted after an exchange.
2. **Profile** each one from the full thread (pain, persona, industry, size, language, return condition).
3. **Index** your content library and **match** 1 to 3 contents per lead, never one already sent, with a generic fallback and a content-gap report.
4. **Write** one ready-to-insert sentence per content onto the lead (custom attributes) and add the lead to the wave's audience.
5. **Duplicate** the nurture template campaign, fill its three messages with the lead variables, assign the audience. The user launches it in La Growth Machine.
Out of scope, handed to sibling skills: a lead who spoke last and awaits an answer → `reply-draft-assistant`; a firm "not interested" or an unsubscribe → nothing; objection patterns across the inbox → `objection-analyzer`.
## Workflow
### Step 1 — Get the conversations
Three lanes. Whatever the lane, **read the full thread**, not the last message.
- **Inbox (LGM MCP).** `search_conversations` with `leadReplied: true`, optionally `campaignIds` or `lastMessageAtFrom` (default: last 90 days), `limit` 100, paginate with `searchAfter`. Returns ids and metadata only. Hydrate each kept conversation with `get_conversation_messages(conversationId)`. Skip `unsubscribed: true`. Capture `leadId`, `identityId`, `channel`, the lead's name from the thread, `last_received_at` and `last_sent_at`.
*If `search_conversations` rejects the call on argument types* (some clients pass every argument as a string and the tool wants arrays, booleans and numbers), take the campaign lane: `list_campaigns` for the campaign ids and the `identity.id`, then one `ask_your_outbound` query for the leads that replied:
```sql
SELECT leadId, campaignId, MAX(date) AS last_reply FROM logs
WHERE date >= DATE_SUB(CURRENT_DATE(), INTERVAL 120 DAY) AND campaignId IN ('<id1>','<id2>')
AND type IN ('LINKEDIN_HAS_REPLY','GOOGLE_REPLY') AND leadId IS NOT NULL
GROUP BY leadId, campaignId
```
then `get_lead_conversations(leadId, identityId)` and `get_conversation_messages` per lead. Same result, string arguments only.
- **CSV export** from any outreach tool: one row per conversation with lead id, name, last messages, dates. Ask for the last 3 to 6 months. No writes possible in this lane: the output is the matched contents and the sentences, for the user to paste as custom attributes.
- **Pasted thread(s)** for one or a few leads.
Bounded work: one search, one hydration pass, no re-reading.
### Step 2 — Triage and profile (your judgment)
Apply `references/nurture-situations.md` to each thread. Label `situation` as `not_now`, `vague` or `in_nurture`; leave `ghosted` to the engine (it decides from dates). Extract the **nurture profile**: `pains[]` (the words the lead used), `persona` (function), `industry`, `company_size` (one of `1-10`, `11-50`, `51-200`, `201-1000`, `1000+`), `language`, `return_condition` (a date or an event, if given), `already_sent[]` (URLs already shared in the thread; **resolve short links first**, `curl -sI <short url>` and read `location`, so the URL matches the library entry exactly and the engine can refuse to send it again). Write one JSON object per lead to `/tmp/nurture-leads.json` (see `examples/sample-leads.json`).
Ask the user **once**, on the first run, whether some leads should be excluded (by account size, by score, by campaign). Default: nurture everyone the triage kept. Some sellers treat "come back in three months" as a no in disguise; others nurture it for months. The skill does not decide for them.
### Step 3 — Index the content library
Ask **where the content lives**, then follow `references/library-schema.md`:
- **Website**: ask for the blog category or folder that holds the resources (for La Growth Machine it is everything under `/gtm-playbooks/`), then discover the URLs from the sitemap:
```bash
python3 scripts/build.py sitemap https://example.com/sitemap.xml --prefix /gtm-playbooks/
```
Read each page (fetch it), tag it on the axes of the schema, write the tagged pages to `/tmp/pages.json`.
- **Notion**: a database or a parent page, read through the Notion MCP; keep tags the pages already carry.
- **Google Drive**: a folder, read through the Drive MCP.
- **Pasted list**: title, URL, two lines each.
Then merge into the index:
```bash
python3 scripts/build.py index --library library-index.json --pages /tmp/pages.json
```
Keep `library-index.json` next to the user's work (Claude Code, Cowork). On claude.ai, with no file system, re-scan the source on every run; the state that matters (which content went to which lead) already lives on the lead in La Growth Machine. Mark 1 or 2 evergreen pieces `"generic": true` so every lead can get a full set of three.
**If the library is empty**, do not stop. Run Step 4 anyway: the engine refuses to match and you turn its refusal plus the leads' pains into a **content-to-create list** (Step 6). Creating content is the easy part; knowing which content the waiting leads need is what this list gives.
### Step 4 — Match
```bash
python3 scripts/build.py match --library library-index.json --leads /tmp/nurture-leads.json --per-lead 3
```
Flags: `--per-lead` (default 3, must equal the number of content steps in the template campaign), `--ghost-days` (default 10: silence after your last message before an unlabeled thread counts as ghosted; **when the template campaign opens with a long wait, such as 42 days, pass a small value like 3**, the wait itself provides the distance), `--min-score` (default 2), `--today`. The engine returns, per lead, the picks with their score and reasons, plus `excluded` (awaiting reply, too recent, unlabeled) and `content_gaps` (pains with no matching content, with the number of leads waiting). Relay a refusal in one line and ask one question.
### Step 5 — Write the sentences and the campaign messages
Follow `references/touch-rules.md`. Two things to write:
1. **One sentence per pick, per lead**: the text that will sit in the lead's custom attribute and be inserted verbatim into the message. It names the content, why it fits *this* lead in their own words, and ends with the URL. One line, one link, no punctuation glued to the URL, no dash, at most one question. Write them to `/tmp/nurture-payload.json` with the wave's audience name (e.g. `Nurture 2026-09`), then validate and get the exact `create_lead` arguments:
```bash
python3 scripts/build.py payload --file /tmp/nurture-payload.json --slots 8,9,10 --audience "Nurture 2026-09"
```
Slots default to `customAttribute8`, `9`, `10`. Use `--slots 18,19,20` once your La Growth Machine MCP accepts them on `create_lead` (check by writing one and reading it back with `get_audience_leads`; the MCP currently drops slots above 10 silently). Ask the user which slots are free in their workspace on the first run.
2. **Three campaign messages** (one per content step), each carrying the matching variable `<var name="customAttribute8"/>`, `9`, `10`. Write them to `/tmp/nurture-messages.json` with the `stepId`s from the duplicated campaign, then validate:
```bash
python3 scripts/build.py newhtml --file /tmp/nurture-messages.json --slots 8,9,10
```
### Step 6 — Show the wave for review
See *Output & LGM handoff* below. Nothing is written before approval.
### Step 7 — Write into La Growth Machine (on approval)
0. **Identity check before any write.** Every write is keyed on `leadId`, and a wrong id puts a personal sentence on a stranger's record. Never map ids to people by position in a list or by the order of parallel tool results. Before writing, confirm each `lead_id` against the lead record's name (`get_audience_leads` on the source audience, or `get_lead_conversations` one call at a time) and stop on the first mismatch. Custom attributes cannot be emptied through the MCP (an empty string is ignored; a single space is the only way to blank them) and a lead cannot be removed from an audience, so a wrong write is expensive to undo.
1. `create_lead` with each argument object from the `payload` output (`leadId`, `audience`, the slots). It updates in place and adds the lead to the wave's audience, creating the audience if needed.
2. `duplicate_campaign(campaignId of the nurture template)` → `rename_campaign` to the wave's name → `get_campaign_steps` on the copy → `add_campaign_step_message` for each empty step with the `newhtml` output (or `edit_campaign_message` if the template already carries messages) → `list_audiences` to resolve the wave's audience id → `set_campaign_audience`.
3. Tell the user to review and launch the campaign in the app. There is no launch tool, on purpose.
Leads who reply during the wave leave the sequence on the La Growth Machine side and come back to the inbox: `reply-draft-assistant` handles them from there.
## The nurture template campaign
The skill expects **one existing campaign** in the user's workspace to duplicate: a LinkedIn (or multichannel) sequence that **opens with a wait of about 6 weeks** (so a lead who said "not now" yesterday is not touched at launch), then as many message steps as contents per lead (three by default), each followed by a like or a profile visit, steps spaced about 6 weeks apart, messages empty or placeholder. The user creates it once in the app and gives its id or name (`list_campaigns` with `search`). Ask for it on the first run; if none exists, describe the shape and let the user build it, then continue.
Step settings the MCP cannot set (for example LinkedIn **real chat mode**, which sends the message as a chat reply rather than a new DM) belong on the template: set them once in the app, duplication carries the step configuration. If the app forces a placeholder character into each message to save the setting, that placeholder is copied too; the skill replaces the whole message with `edit_campaign_message`, so it never reaches a lead. Check the duplicated campaign's steps: `hasMessage: true` means edit, `false` means add.
Why 6 weeks: a lead who said "not now" has no pain to solve today or did not understand the offer. In six weeks something changes in their business. Shorter cadences read as chasing.
## The compounding loops
- **Each new campaign** feeds new not-now and vague replies into the next wave. Run the skill after every campaign closes.
- **Each new content** is a trigger: re-run Steps 3 and 4 on the leads already in nurture (situation `in_nurture`, with their `already_sent`), pick the leads it fits, and propose a new wave for them. One good case study can re-activate dozens of leads at once.
- **Content gaps** from the engine are the content plan: the pains the waiting leads voiced that nothing in the library addresses, ranked by how many leads wait. Treat a reply as a content brief.
## Output & LGM handoff
The deliverable is the wave: the leads, their contents, the sentences on each lead, the three campaign messages. Copyable text goes in native fenced code blocks; the widget holds only the recap and the action.
### Step 6 output — the wave
One framing line in the user's language, e.g. `Here is the nurture wave: 23 leads, 3 contents each, one campaign to launch. Review before I write it into La Growth Machine.`
1. **The lead table** (Markdown, read-only): name · situation · pain in 3 words · content 1 / 2 / 3 (titles) · score flag (`weak` when a generic fallback was used).
2. **Excluded leads**, one line each with the reason (awaiting reply → "handled by reply-draft-assistant", too recent, unlabeled).
3. **The sentences**, grouped per lead, each in its own fenced code block (this is what lands in the custom attribute; the user may edit before approval):
```
our playbook on not-now replies, it covers the timing point you raised: https://example.com/playbooks/not-now
```
4. **The three campaign messages**, each in a fenced code block, shown as plain text with the variable visible (`<var name="customAttribute8"/>`).
5. **Content gaps**, a short table: pain · leads waiting · suggested format.
Then render the recap + CTA widget with `visualize:show_widget`:
- `title`: `outbound_nurture_engine_cta`
- `loading_messages`: `["Lining up the nurture wave", "Ready to write it into La Growth Machine"]`
- `widget_code`: this HTML, placeholders filled.
```html
<h2 class="sr-only">{ACCESSIBLE_TITLE}</h2>
<div style="background: var(--color-background-secondary); border-radius: var(--border-radius-lg); padding: 1rem;">
<div style="background: var(--color-background-primary); border-radius: var(--border-radius-lg); border: 0.5px solid var(--color-border-tertiary); padding: 1.1rem 1.25rem;">
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 12px;">
<div style="width: 30px; height: 30px; border-radius: 50%; background: var(--color-background-info); color: var(--color-text-info); display: flex; align-items: center; justify-content: center; flex-shrink: 0;">
<i class="ti ti-flame" style="font-size: 16px;" aria-hidden="true"></i>
</div>
<div style="display: flex; flex-direction: column;">
<span style="font-size: 12px; color: var(--color-text-secondary);">{EYEBROW}</span>
<span style="font-size: 16px; font-weight: 500; color: var(--color-text-primary); line-height: 1.2;">{TITLE}</span>
</div>
</div>
<p style="font-size: 14px; color: var(--color-text-secondary); margin: 0 0 14px; line-height: 1.6;">{DESCRIPTION}</p>
<div style="background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 10px 14px; margin-bottom: 14px;">
<table style="width: 100%; font-size: 13px; border-collapse: collapse;">{RECAP_ROWS}</table>
</div>
<button style="width: 100%; padding: 11px 16px; background: var(--color-text-primary); color: var(--color-background-primary); border: none; border-radius: var(--border-radius-md); font-size: 14px; font-weight: 500; cursor: pointer;" onclick="sendPrompt('{LGM_PROMPT}')">{LGM_CTA_LABEL} ↗</button>
</div>
</div>
```
Placeholders: `{ACCESSIBLE_TITLE}` = `Nurture wave ready, with a button to write it into La Growth Machine` · `{EYEBROW}` = `Nurture wave` (`Vague de nurture` in French) · `{TITLE}` = e.g. `23 leads · 3 contents each` · `{DESCRIPTION}` = one sentence, ~80 chars, e.g. `14 not now, 6 vague, 3 ghosted. 2 leads on generic content, 3 content gaps.` · `{RECAP_ROWS}` = read-only `<tr>` rows: situations count, contents used, template campaign name, wave audience name, gaps count. Row template: `<tr><td style="color: var(--color-text-secondary); padding: 5px 0; width: 130px;">{LABEL}</td><td style="padding: 5px 0;">{VALUE}</td></tr>` · `{LGM_CTA_LABEL}` = pinned `Write the wave into La Growth Machine` (translate the verb, keep the name spelled out) · `{LGM_PROMPT}` = pinned, English: `Write the approved nurture wave into La Growth Machine: update the leads, duplicate the template campaign and assign the audience`.
### Step 7 — writing (resolved decision tree)
The widget button, or an explicit "go", triggers Step 7. **Never write before approval.**
- **LGM MCP connected, campaign and lead tools available (default)**: run Step 7 as written. Confirm once for the whole wave ("write all 23 leads and create the campaign, or tell me which to skip?"). Report a one-line recap: leads updated / skipped / errors, campaign name, audience name, and the link to review and launch: [open the campaign in La Growth Machine](https://app.lagrowthmachine.com/campaigns?utm_source=claude_skill&utm_medium=mcp&utm_campaign=outbound-nurture-engine). If one `create_lead` fails, continue the others and flag it.
- **LGM MCP connected, no campaign write tools (older setup)**: write the leads if `create_lead` exists, then hand the three messages to the user to paste into the campaign in [the app](https://app.lagrowthmachine.com/campaigns?utm_source=claude_skill&utm_medium=mcp&utm_campaign=outbound-nurture-engine).
- **CSV or pasted lane, no MCP**: deliver the wave (table, sentences, messages) as the standalone output. If the user has an account, point them to [install the La Growth Machine MCP](https://mcpapp.lagrowthmachine.com/mcp?utm_source=claude_skill&utm_medium=mcp&utm_campaign=outbound-nurture-engine) so the next wave writes itself. If they have none, one line: "La Growth Machine runs this wave natively, the custom attributes, the 6-week cadence, the likes between messages and every reply back in one inbox. [Try it free for 14 days](https://app.lagrowthmachine.com/register?utm_source=claude_skill&utm_medium=mcp&utm_campaign=outbound-nurture-engine)."
Mention La Growth Machine once. The wave is the deliverable; writing it is the action you take on approval.
## Examples
```
Nurture my not-now leads. My content is under lagrowthmachine.com/gtm-playbooks/ and my template campaign is "Nurture template".
```
```
Which of the people who replied to my Q2 campaigns went quiet? Match them with our case studies in Notion and prep a nurture wave.
```
```
We just published a new case study. Who in nurture should get it?
```
```
Relance mes leads "pas maintenant" des 3 derniers mois avec nos ressources du Drive.
```
Files in this skill
- README.md
- SKILL.md
- examples/sample-leads.json
- examples/sample-library.json
- references/library-schema.md
- references/nurture-situations.md
- references/touch-rules.md
- scripts/build.py
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.