Leadspicker Outreach (MCP)
Creates outreach sequences in Leadspicker projects through the Leadspicker MCP server. The
entire sequence is built in one mcp__leadspicker__create_sequence call — never chain
multiple create_sequence_step calls when constructing a new sequence.
Three sequence types:
- Email — cold email + follow-ups in the same thread.
- LinkedIn — connection check → messages, or connection request → messages / InMail.
- Multi-channel — emails + LinkedIn together.
MCP tools used
| MCP tool |
Purpose |
mcp__leadspicker__list_projects |
Look up project by name (search_query) or list recent (order_by="last_active") |
mcp__leadspicker__get_project |
Fetch project + headers_data to find boolean column IDs (info_type="detail") |
mcp__leadspicker__list_contacts |
Page contacts (page=1, page_size=5) to see what variables exist |
mcp__leadspicker__list_sequence |
List steps in an existing sequence (project_id) |
mcp__leadspicker__delete_sequence |
Delete the entire sequence for a project (pass project_id, no sequence_id) |
mcp__leadspicker__create_sequence |
Create the whole sequence in one call (project_id, sequence_messages) |
mcp__leadspicker__update_sequence_step |
Patch a single existing step (legacy; only for edits to an already-saved sequence) |
mcp__leadspicker__get_sequence_settings |
Read / update sending hours, timezone, daily limits |
Step types — use EXACTLY these values
| Step |
outreach_step_type |
Notes |
| Boolean condition gate |
"magic_column_condition" |
Filters by a boolean magic column. Uses condition: [header_id]. |
| Email |
"" (empty string) |
NOT "email" — empty string |
| Delay / wait |
"delay" |
NOT "wait". Uses delay_days (and optionally delay_hours). |
| Check 1st-degree connection |
"first_degree_connection" |
Branching: yes (connected) / no (not connected). |
| Send connection request |
"connect" |
NOT "connection_request". |
| Wait for acceptance |
"after_connection" |
Branching: yes (accepted) / no (not accepted). Uses delay_days for max wait. |
| LinkedIn message (DM) |
"message" |
Only works with connected contacts. |
| InMail |
"inmail_message" |
NOT "inmail". Premium LinkedIn only — ask the user. |
Boolean condition gate (magic_column_condition)
Add condition gates as the first steps of the sequence when the project has boolean magic
columns. Each condition is a separate step with condition: [header_id] (one ID per step).
Chain them with relation_type: "yes".
Find boolean column header IDs by calling mcp__leadspicker__get_project(project_id=X)
and looking in headers_data for entries with is_boolean: true — use the id field.
Parent references
Inside sequence_messages, steps reference parents by named string keys (or numeric IDs of
already-saved steps):
"parents": ["delay-step"] // simple chain
"parents": [{"parent": "wait-accept", "relation_type": "yes"}] // YES branch
"parents": [{"parent": 4567, "relation_type": ""}] // existing step ID
relation_type: "" (sequential), "yes" (positive branch), "no" (negative branch)
- Root steps have no
parents field.
- Position is auto-calculated.
Sequence type 1 — Email
EMAIL 1 (root, is_reply=false) — new thread
→ DELAY (3 days)
→ EMAIL 2 (is_reply=true) — same thread
→ DELAY (3 days)
→ EMAIL 3 (is_reply=true) — same thread
{
"sequence_messages": {
"email-1": {
"subject": "{subject_line}",
"message": "<div>{email_body_html}</div>",
"outreach_step_type": "",
"is_reply": false
},
"delay-1": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["email-1"] },
"email-2": {
"subject": "Re: {subject_line}",
"message": "<div>{follow_up_body_html}</div>",
"outreach_step_type": "",
"is_reply": true,
"parents": ["delay-1"]
},
"delay-2": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["email-2"] },
"email-3": {
"subject": "Re: {subject_line}",
"message": "<div>{final_follow_up_body_html}</div>",
"outreach_step_type": "",
"is_reply": true,
"parents": ["delay-2"]
}
}
}
| Field |
Value |
Notes |
outreach_step_type |
"" |
Empty string for email |
subject |
"Subject" (first email) / "Re: ..." (follow-ups) |
Only first email gets a subject |
message |
"<div>HTML</div>" |
HTML format |
is_reply |
false (new thread) / true (same thread) |
|
Sequence type 2 — LinkedIn
CONNECT (root) — send connection request
→ AFTER_CONNECTION (wait up to 7 days)
├── YES (accepted): MESSAGE 1 → DELAY → MESSAGE 2
└── NO (not accepted): INMAIL (premium) → DELAY → INMAIL 2
{
"sequence_messages": {
"connect": {
"message": "{connection_request_text}",
"outreach_step_type": "connect"
},
"wait-accept": {
"outreach_step_type": "after_connection",
"delay_days": 7,
"parents": ["connect"]
},
"accepted-msg-1": {
"message": "{message_body_1}",
"outreach_step_type": "message",
"parents": [{ "parent": "wait-accept", "relation_type": "yes" }]
},
"accepted-delay": { "outreach_step_type": "delay", "delay_days": 5, "parents": ["accepted-msg-1"] },
"accepted-msg-2": {
"message": "{follow_up_body}",
"outreach_step_type": "message",
"parents": ["accepted-delay"]
},
"not-accepted-inmail-1": {
"subject": "{inmail_subject}",
"message": "{inmail_body}",
"outreach_step_type": "inmail_message",
"parents": [{ "parent": "wait-accept", "relation_type": "no" }]
},
"not-accepted-delay": { "outreach_step_type": "delay", "delay_days": 5, "parents": ["not-accepted-inmail-1"] },
"not-accepted-inmail-2": {
"subject": "{inmail_subject_2}",
"message": "{inmail_follow_up_body}",
"outreach_step_type": "inmail_message",
"parents": ["not-accepted-delay"]
}
}
}
| Field |
Value |
Notes |
message |
"text" |
LinkedIn message body — plain text, NOT HTML |
subject |
"text" |
Required only for InMail |
InMail — premium only. Always ask the user about LinkedIn Premium before adding
inmail_message steps. Non-premium → skip InMail entirely.
Sequence type 3 — Multi-channel (email + LinkedIn)
⚠️ MANDATORY: always check first_degree_connection
NEVER skip the first_degree_connection step in multi-channel sequences. It MUST come
before any LinkedIn connect / message step.
CONDITIONS (optional) — filter by boolean columns
→ EMAIL 1 → DELAY → FOLLOW-UP EMAIL → DELAY
→ FIRST_DEGREE_CONNECTION
├── YES (already connected): MESSAGE 1 → DELAY → MESSAGE 2
└── NO (not connected): CONNECT → AFTER_CONNECTION (7 days)
├── YES (accepted): MESSAGE 1 → DELAY → MESSAGE 2
└── NO (not accepted): INMAIL (premium) → DELAY → FINAL EMAIL
Premium vs. non-premium
- Premium: include InMail in NO-not-accepted branch.
- Non-premium: skip InMail, jump straight to the final email.
Full payload (with conditions + InMail — 18 steps)
{
"sequence_messages": {
"check-icp": {
"outreach_step_type": "magic_column_condition",
"condition": [387407]
},
"check-language": {
"outreach_step_type": "magic_column_condition",
"condition": [387411],
"parents": [{ "parent": "check-icp", "relation_type": "yes" }]
},
"first-email": {
"subject": "{subject_line}",
"message": "<div>{email_body_html}</div>",
"outreach_step_type": "",
"is_reply": false,
"parents": [{ "parent": "check-language", "relation_type": "yes" }]
},
"delay-after-email-1": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["first-email"] },
"followup-email": {
"subject": "Re: {subject_line}",
"message": "<div>{follow_up_html}</div>",
"outreach_step_type": "",
"is_reply": true,
"parents": ["delay-after-email-1"]
},
"delay-after-email-2": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["followup-email"] },
"check-connected": {
"outreach_step_type": "first_degree_connection",
"parents": ["delay-after-email-2"]
},
"already-connected-msg": {
"message": "{li_message_for_connected}",
"outreach_step_type": "message",
"parents": [{ "parent": "check-connected", "relation_type": "yes" }]
},
"already-connected-delay": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["already-connected-msg"] },
"already-connected-msg-2": {
"message": "{li_followup_for_connected}",
"outreach_step_type": "message",
"parents": ["already-connected-delay"]
},
"not-connected-request": {
"message": "{connection_request_text}",
"outreach_step_type": "connect",
"parents": [{ "parent": "check-connected", "relation_type": "no" }]
},
"wait-accept": {
"outreach_step_type": "after_connection",
"delay_days": 7,
"parents": ["not-connected-request"]
},
"accepted-msg": {
"message": "{li_message_after_accept}",
"outreach_step_type": "message",
"parents": [{ "parent": "wait-accept", "relation_type": "yes" }]
},
"accepted-delay": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["accepted-msg"] },
"accepted-msg-2": {
"message": "{li_followup_after_accept}",
"outreach_step_type": "message",
"parents": ["accepted-delay"]
},
"not-accepted-inmail": {
"subject": "{inmail_subject}",
"message": "{inmail_body}",
"outreach_step_type": "inmail_message",
"parents": [{ "parent": "wait-accept", "relation_type": "no" }]
},
"not-accepted-delay": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["not-accepted-inmail"] },
"final-email": {
"subject": "{final_subject}",
"message": "<div>{final_email_html}</div>",
"outreach_step_type": "",
"is_reply": false,
"parents": ["not-accepted-delay"]
}
}
}
Message generation — BASHO framework
Philosophy
Short, relevant, trigger-led messages that read like a real person wrote them. Tied to a
specific reason for reaching out. Never generic templates.
Core principles:
- Relevance beats personalization. Tie the message to why now, not "Congrats on…".
- One idea per email/message. Don't stack problems, features, and asks.
- Mobile-first. Short lines, white space, fast to understand.
- Write like you talk. Simple words, short sentences.
- No cheesy openers. NEVER use "I hope you're doing well", "I hope this finds you well", or any throat-clearing phrases.
Pre-generation checklist
Before generating any messages, complete these in order:
- What is the user selling / offering? Product, service, value prop, ICP, problem solved.
- Preferred language? Default English. If non-English, all messages in that language.
- LinkedIn Premium? Determines connection request text (blank vs ≤200 chars) and InMail availability.
- (LinkedIn / multi-channel only) Sender name? LinkedIn has no auto-signature — ask the user for the exact name to sign with (e.g.
"Tomáš Blaťák"). Do NOT use recipient variables.
- Fetch available variables. Call
mcp__leadspicker__list_contacts(project_id=X, page=1, page_size=5) to see all columns. Look for:
- Standard:
{{first_name}}, {{last_name}}, {{full_name}}, {{position}}, {{company_name}}
- Enriched:
{{linkedin_company_description}}, {{website_text_summary}}, {{linkedin_about_me}}, {{present_experiences}}
- Personalization (from mcp-personalizer):
{{website_hook}}, {{company_hook}}, {{experience_hook}}, {{icebreaker}}, {{salutation}}, etc.
- Any custom AI columns from mcp-classification / mcp-personalizer
BASHO message structure
Every message follows this 4-part structure:
1) Opener — "Reason I'm reaching out" (1–2 lines)
- Sales trigger (funding, hiring, new product, leadership change, expansion)
- Observation (something specific on their site, pricing, messaging, reviews, job posts)
- Peer signal (competitor / adjacent brand doing X)
- Or use a personalization variable:
{{website_hook}}, {{icebreaker}}
- Goal: establish "this isn't a template" immediately.
2) Reframe — make them think (1–2 lines)
- Pattern interrupt question: "Curious if you're seeing X…"
- Simple outcome statement: "Teams use us to reduce X / improve Y without Z."
- Goal: create curiosity without pitching features.
3) Proof — "Others like you succeeded" (1 line)
- "Teams like [type] are seeing…"
- "We helped a similar [industry] team…"
- "Commonly we see X within Y weeks…"
- 1 line max — no case-study essays.
4) CTA — low-friction next step (1 line)
- NOT "book a demo". Instead:
- "Worth a 10-min chat to compare notes?"
- "Open to me sending over a quick teardown?"
- "Should I speak with you or someone else on this?"
- One clear CTA only.
Word counts
| Step |
Word count |
Notes |
Initial email (is_reply=false) |
150–200 |
Full BASHO |
Second email follow-up (is_reply=true) |
100–150 |
Adds one new insight / proof |
Final email follow-up (is_reply=true) |
50–100 |
Breakup, close-the-loop |
LinkedIn DM (message) |
150–200 |
Full BASHO |
| LinkedIn follow-up DM |
100–150 |
Adds new value, shorter |
| Connection request — non-premium |
BLANK |
Non-premium gets only 5 messages/month; leave empty |
| Connection request — premium |
≤ 200 chars |
Trigger + relevance only |
InMail (inmail_message) |
150–200 |
Full BASHO, subject required |
| Email fallback (multi-channel last branch) |
50–100 |
Breakup, references previous outreach |
Follow-up rules
- Second follow-up: NOT "bumping this". Add something NEW — a sharper insight, a tiny teardown, a relevant example. Reference the prior message briefly, then pivot to new value.
- Final follow-up / breakup: Polite close-the-loop. "If the timing isn't right, no worries — just wanted to close the loop." Give them an easy out, leave the door open. Can include one final micro-value or observation.
Spintax
Use spintax {option1 | option2 | option3} for text rotation. Required spintax locations:
- Greeting — always:
{Hi | Hey | Hello}, or in target language: {Dobrý den | Zdravím}.
- Closing — always:
{Best | Cheers | Kind regards | Thanks}, or in target language: {S pozdravem | Díky | Přeji hezký den}.
Plus 2–4 additional locations per message:
- Opener:
{I noticed | I saw | Caught my eye that}
- Reframe:
{Curious if | Wondering whether | Quick question —}
- Proof intro:
{Teams like yours | Similar companies | Others in your space}
- CTA:
{Worth a quick chat? | Open to connecting? | Would 10 minutes make sense?}
- Transitions:
{That said | With that in mind | On that note}
Total: at least 4–6 spintax locations per message (2 required + 2–4 additional).
Subject lines
- Spintax for rotation, short (3–8 words), curiosity-driven, no clickbait.
- Only the first email (
is_reply=false) has a subject. Follow-ups (is_reply=true) have empty subject (same thread).
Examples:
{Quick question | Thought about this | Noticed something} about {{company_name}}
{{{first_name}} | Quick thought} — {{company_name}}
{Idea for | Question about | Observation on} {{company_name}}
LinkedIn premium rules
- Non-premium: connection request
message = blank (empty string). No InMail step. Total: LinkedIn-only sequence has 9 steps; multi-channel has 16 steps.
- Premium: connection request
message ≤ 200 chars (e.g. "Hi {{first_name}}, {{website_hook}} — would love to connect and share thoughts."). InMail available with subject + 150–200-word body. Total: LinkedIn-only 10 steps; multi-channel 18 steps.
Variable priority for openers
{{icebreaker}} — LinkedIn posts icebreaker (most personal)
{{website_hook}} — website-specific
{{company_hook}} — company LinkedIn-specific
{{experience_hook}} — person-specific
- Manual trigger from
{{position}} + {{company_name}} (fallback)
Hard rules
- ≈150–200 words for initial messages, shorter for follow-ups.
- No "hope you're well" / no throat-clearing / no cheesy openers.
- No feature dump — talk outcomes and the problem you solve.
- Specificity wins — numbers, timeframes, scope (when you can).
- One clear CTA (not multiple questions).
- Avoid spam signals — too many links, heavy formatting, buzzwords, exclamation marks.
- Write like you talk — simple words, short sentences.
- Skimmable — 1–2 lines per paragraph, 3–6 short paragraphs.
- Mobile-first — short lines that look good on phone screens.
- Each follow-up adds something new — never just "bumping this".
- Final follow-up = breakup style, close the loop politely.
- Emails: NO sender name / signature. Leadspicker auto-appends the email signature; adding one in the body would duplicate.
- LinkedIn: ALWAYS include the sender's real name at the end of every LinkedIn message. LinkedIn has no auto-signature. Use the exact name the user provided in the pre-generation checklist — never
{{first_name}} (that's the recipient).
Multi-language
- Default English; ask before generating.
- Spintax in the target language (greetings, closings, transitions).
- If a
{{salutation}} column exists (from mcp-personalizer), use it instead of generic greeting spintax.
- Messages should read naturally, not like translations.
Email body format
HTML in the message field. Use <div> and <br>.
<div>
{Hi | Hey | Hello} {{first_name}},<br /><br />
{{website_hook}}<br /><br />
{Curious if | Wondering whether} you're seeing similar challenges with [problem].<br /><br />
{Teams like yours | Similar companies in {{industry}}} are seeing [outcome] within [timeframe].<br /><br />
{Worth a quick 10-min chat? | Open to comparing notes?}
</div>
⚠️ Do NOT include sender name or signature — Leadspicker auto-appends it.
LinkedIn message format
Plain text in the message field (NOT HTML). Always sign with the user's actual name.
{Hi | Hey | Hello} {{first_name}},
{{website_hook}}
{Curious if | Wondering whether} you're exploring [topic] — {teams like yours | others in your space} are seeing [outcome].
{Worth connecting to share notes? | Open to a quick chat?}
{Best | Cheers},
{user's actual name}
Workflow
- Resolve the project — display as
{name} (#{id}).
- User named it →
mcp__leadspicker__list_projects(search_query="{name}", limit=5).
- Otherwise →
mcp__leadspicker__list_projects(order_by="last_active", limit=20) and ask the user to pick.
Then ask the user which sequence type to build (email / LinkedIn / multi-channel).
- Check existing sequence —
mcp__leadspicker__list_sequence(project_id=X). Warn if a sequence already exists.
- Pre-generation checklist — what they're selling, preferred language, LinkedIn Premium, sender name (LI/multi-channel).
- Fetch variables —
mcp__leadspicker__list_contacts(project_id=X, page=1, page_size=5) to see all columns including hooks / icebreakers / salutations.
- Find boolean columns —
mcp__leadspicker__get_project(project_id=X, info_type="detail") → look in headers_data for entries with is_boolean: true and pick their id. If any boolean columns exist, ALWAYS add them as magic_column_condition steps at the root (chained via relation_type: "yes"). Skip only if no boolean columns exist.
- Generate messages — apply BASHO, word limits, spintax, and use the available variables. Emails: no sender name. LinkedIn: sign with the user's actual name.
- Show all messages to the user for approval before building.
- Delete existing sequence if any —
mcp__leadspicker__delete_sequence(project_id=X).
- Build the sequence in ONE call —
mcp__leadspicker__create_sequence(project_id=X, sequence_messages=...). Never chain multiple create_sequence_step calls when constructing a new sequence.
- Verify —
mcp__leadspicker__list_sequence(project_id=X) to show the resulting tree.
Deleting a sequence
mcp__leadspicker__delete_sequence(project_id=X) removes ALL steps. There is no API to
delete individual steps — only the entire sequence.
Common errors
| Error |
Cause |
Fix |
sequence_graph_invalid |
Payload references an unknown parent key, has a cycle, or a branch without a root |
Re-check parents references and ensure exactly one root. |
"Field required" for parent |
Used parent_id instead of parent |
Use the parent field name inside parents objects. |
| "Input should be '', 'yes' or 'no'" |
Invalid relation_type |
Use "", "yes", or "no" only. |
| Step created but wrong type in UI |
Wrong outreach_step_type value |
See step types table — e.g. "" for email, NOT "email". |
Natural language matching
| User says (EN) |
User says (CZ) |
Action |
| "create email sequence" |
"vytvoř emailovou sekvenci" |
Email sequence (ask offer / ICP first) |
| "create LinkedIn sequence" |
"vytvoř LinkedIn sekvenci" |
LinkedIn sequence (ask offer / ICP + Premium) |
| "create multi-channel sequence" |
"vytvoř multi-channel sekvenci" |
Multi-channel (ask offer / ICP + Premium) |
| "3 emails with 3 day delays" |
"3 emaily s 3denními pauzami" |
Email: 3 emails + 2 delays of 3 days |
| "LinkedIn outreach with InMail" |
"LinkedIn oslovení s InMailem" |
LinkedIn with InMail (ask Premium) |
| "write outreach messages" |
"napiš oslovení" |
Generate BASHO messages for the picked sequence |
| "create campaign for [product]" |
"vytvoř kampaň pro [produkt]" |
Full sequence + messages (ask language + Premium) |
| "delete sequence" |
"smaž sekvenci" |
mcp__leadspicker__delete_sequence(project_id=X) |
| "show sequence" |
"ukaž sekvenci" |
mcp__leadspicker__list_sequence(project_id=X) |
1---2name: mcp-outreach3description: Creates outreach sequences (email, LinkedIn, or multi-channel) for Leadspicker projects through the Leadspicker MCP server. Triggers on: "sequence", "outreach", "campaign", "email sequence", "LinkedIn sequence", "multi-channel", "follow-up", "sekvence", "kampaň", "oslovení", "cold email", "connection request", "inmail", "message sequence". Builds the whole sequence graph in a single MCP `create_sequence` call (never chains step-by-step).4---56# Leadspicker Outreach (MCP)78Creates outreach sequences in Leadspicker projects through the Leadspicker MCP server. The9entire sequence is built in **one** `mcp__leadspicker__create_sequence` call — never chain10multiple `create_sequence_step` calls when constructing a new sequence.1112**Three sequence types:**13141. **Email** — cold email + follow-ups in the same thread.152. **LinkedIn** — connection check → messages, or connection request → messages / InMail.163. **Multi-channel** — emails + LinkedIn together.1718---1920## MCP tools used2122| MCP tool | Purpose |23| ----------------------------------------- | ---------------------------------------------------------------------------------- |24| `mcp__leadspicker__list_projects` | Look up project by name (`search_query`) or list recent (`order_by="last_active"`) |25| `mcp__leadspicker__get_project` | Fetch project + `headers_data` to find boolean column IDs (`info_type="detail"`) |26| `mcp__leadspicker__list_contacts` | Page contacts (`page=1, page_size=5`) to see what variables exist |27| `mcp__leadspicker__list_sequence` | List steps in an existing sequence (`project_id`) |28| `mcp__leadspicker__delete_sequence` | Delete the entire sequence for a project (pass `project_id`, no `sequence_id`) |29| `mcp__leadspicker__create_sequence` | **Create the whole sequence in one call** (`project_id`, `sequence_messages`) |30| `mcp__leadspicker__update_sequence_step` | Patch a single existing step (legacy; only for edits to an already-saved sequence) |31| `mcp__leadspicker__get_sequence_settings` | Read / update sending hours, timezone, daily limits |3233---3435## Step types — use EXACTLY these values3637| Step | `outreach_step_type` | Notes |38| --------------------------- | --------------------------- | ---------------------------------------------------------------------------------- |39| Boolean condition gate | `"magic_column_condition"` | Filters by a boolean magic column. Uses `condition: [header_id]`. |40| Email | `""` (empty string) | NOT `"email"` — empty string |41| Delay / wait | `"delay"` | NOT `"wait"`. Uses `delay_days` (and optionally `delay_hours`). |42| Check 1st-degree connection | `"first_degree_connection"` | Branching: `yes` (connected) / `no` (not connected). |43| Send connection request | `"connect"` | NOT `"connection_request"`. |44| Wait for acceptance | `"after_connection"` | Branching: `yes` (accepted) / `no` (not accepted). Uses `delay_days` for max wait. |45| LinkedIn message (DM) | `"message"` | Only works with connected contacts. |46| InMail | `"inmail_message"` | NOT `"inmail"`. Premium LinkedIn only — ask the user. |4748### Boolean condition gate (`magic_column_condition`)4950Add condition gates as the first steps of the sequence when the project has boolean magic51columns. Each condition is a separate step with `condition: [header_id]` (one ID per step).52Chain them with `relation_type: "yes"`.5354**Find boolean column header IDs** by calling `mcp__leadspicker__get_project(project_id=X)`55and looking in `headers_data` for entries with `is_boolean: true` — use the `id` field.5657### Parent references5859Inside `sequence_messages`, steps reference parents by named string keys (or numeric IDs of60already-saved steps):6162```json63"parents": ["delay-step"] // simple chain64"parents": [{"parent": "wait-accept", "relation_type": "yes"}] // YES branch65"parents": [{"parent": 4567, "relation_type": ""}] // existing step ID66```6768- `relation_type`: `""` (sequential), `"yes"` (positive branch), `"no"` (negative branch)69- Root steps have no `parents` field.70- Position is auto-calculated.7172---7374## Sequence type 1 — Email7576```77EMAIL 1 (root, is_reply=false) — new thread78 → DELAY (3 days)79 → EMAIL 2 (is_reply=true) — same thread80 → DELAY (3 days)81 → EMAIL 3 (is_reply=true) — same thread82```8384```json85{86 "sequence_messages": {87 "email-1": {88 "subject": "{subject_line}",89 "message": "<div>{email_body_html}</div>",90 "outreach_step_type": "",91 "is_reply": false92 },93 "delay-1": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["email-1"] },94 "email-2": {95 "subject": "Re: {subject_line}",96 "message": "<div>{follow_up_body_html}</div>",97 "outreach_step_type": "",98 "is_reply": true,99 "parents": ["delay-1"]100 },101 "delay-2": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["email-2"] },102 "email-3": {103 "subject": "Re: {subject_line}",104 "message": "<div>{final_follow_up_body_html}</div>",105 "outreach_step_type": "",106 "is_reply": true,107 "parents": ["delay-2"]108 }109 }110}111```112113| Field | Value | Notes |114| -------------------- | ---------------------------------------------------- | ------------------------------- |115| `outreach_step_type` | `""` | Empty string for email |116| `subject` | `"Subject"` (first email) / `"Re: ..."` (follow-ups) | Only first email gets a subject |117| `message` | `"<div>HTML</div>"` | HTML format |118| `is_reply` | `false` (new thread) / `true` (same thread) | |119120---121122## Sequence type 2 — LinkedIn123124```125CONNECT (root) — send connection request126 → AFTER_CONNECTION (wait up to 7 days)127 ├── YES (accepted): MESSAGE 1 → DELAY → MESSAGE 2128 └── NO (not accepted): INMAIL (premium) → DELAY → INMAIL 2129```130131```json132{133 "sequence_messages": {134 "connect": {135 "message": "{connection_request_text}",136 "outreach_step_type": "connect"137 },138 "wait-accept": {139 "outreach_step_type": "after_connection",140 "delay_days": 7,141 "parents": ["connect"]142 },143 "accepted-msg-1": {144 "message": "{message_body_1}",145 "outreach_step_type": "message",146 "parents": [{ "parent": "wait-accept", "relation_type": "yes" }]147 },148 "accepted-delay": { "outreach_step_type": "delay", "delay_days": 5, "parents": ["accepted-msg-1"] },149 "accepted-msg-2": {150 "message": "{follow_up_body}",151 "outreach_step_type": "message",152 "parents": ["accepted-delay"]153 },154 "not-accepted-inmail-1": {155 "subject": "{inmail_subject}",156 "message": "{inmail_body}",157 "outreach_step_type": "inmail_message",158 "parents": [{ "parent": "wait-accept", "relation_type": "no" }]159 },160 "not-accepted-delay": { "outreach_step_type": "delay", "delay_days": 5, "parents": ["not-accepted-inmail-1"] },161 "not-accepted-inmail-2": {162 "subject": "{inmail_subject_2}",163 "message": "{inmail_follow_up_body}",164 "outreach_step_type": "inmail_message",165 "parents": ["not-accepted-delay"]166 }167 }168}169```170171| Field | Value | Notes |172| --------- | -------- | -------------------------------------------- |173| `message` | `"text"` | LinkedIn message body — plain text, NOT HTML |174| `subject` | `"text"` | Required only for InMail |175176**InMail — premium only.** Always ask the user about LinkedIn Premium before adding177`inmail_message` steps. Non-premium → skip InMail entirely.178179---180181## Sequence type 3 — Multi-channel (email + LinkedIn)182183### ⚠️ MANDATORY: always check `first_degree_connection`184185NEVER skip the `first_degree_connection` step in multi-channel sequences. It MUST come186before any LinkedIn `connect` / `message` step.187188```189CONDITIONS (optional) — filter by boolean columns190 → EMAIL 1 → DELAY → FOLLOW-UP EMAIL → DELAY191 → FIRST_DEGREE_CONNECTION192 ├── YES (already connected): MESSAGE 1 → DELAY → MESSAGE 2193 └── NO (not connected): CONNECT → AFTER_CONNECTION (7 days)194 ├── YES (accepted): MESSAGE 1 → DELAY → MESSAGE 2195 └── NO (not accepted): INMAIL (premium) → DELAY → FINAL EMAIL196```197198### Premium vs. non-premium199200- **Premium:** include InMail in NO-not-accepted branch.201- **Non-premium:** skip InMail, jump straight to the final email.202203### Full payload (with conditions + InMail — 18 steps)204205```json206{207 "sequence_messages": {208 "check-icp": {209 "outreach_step_type": "magic_column_condition",210 "condition": [387407]211 },212 "check-language": {213 "outreach_step_type": "magic_column_condition",214 "condition": [387411],215 "parents": [{ "parent": "check-icp", "relation_type": "yes" }]216 },217 "first-email": {218 "subject": "{subject_line}",219 "message": "<div>{email_body_html}</div>",220 "outreach_step_type": "",221 "is_reply": false,222 "parents": [{ "parent": "check-language", "relation_type": "yes" }]223 },224 "delay-after-email-1": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["first-email"] },225 "followup-email": {226 "subject": "Re: {subject_line}",227 "message": "<div>{follow_up_html}</div>",228 "outreach_step_type": "",229 "is_reply": true,230 "parents": ["delay-after-email-1"]231 },232 "delay-after-email-2": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["followup-email"] },233 "check-connected": {234 "outreach_step_type": "first_degree_connection",235 "parents": ["delay-after-email-2"]236 },237 "already-connected-msg": {238 "message": "{li_message_for_connected}",239 "outreach_step_type": "message",240 "parents": [{ "parent": "check-connected", "relation_type": "yes" }]241 },242 "already-connected-delay": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["already-connected-msg"] },243 "already-connected-msg-2": {244 "message": "{li_followup_for_connected}",245 "outreach_step_type": "message",246 "parents": ["already-connected-delay"]247 },248 "not-connected-request": {249 "message": "{connection_request_text}",250 "outreach_step_type": "connect",251 "parents": [{ "parent": "check-connected", "relation_type": "no" }]252 },253 "wait-accept": {254 "outreach_step_type": "after_connection",255 "delay_days": 7,256 "parents": ["not-connected-request"]257 },258 "accepted-msg": {259 "message": "{li_message_after_accept}",260 "outreach_step_type": "message",261 "parents": [{ "parent": "wait-accept", "relation_type": "yes" }]262 },263 "accepted-delay": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["accepted-msg"] },264 "accepted-msg-2": {265 "message": "{li_followup_after_accept}",266 "outreach_step_type": "message",267 "parents": ["accepted-delay"]268 },269 "not-accepted-inmail": {270 "subject": "{inmail_subject}",271 "message": "{inmail_body}",272 "outreach_step_type": "inmail_message",273 "parents": [{ "parent": "wait-accept", "relation_type": "no" }]274 },275 "not-accepted-delay": { "outreach_step_type": "delay", "delay_days": 3, "parents": ["not-accepted-inmail"] },276 "final-email": {277 "subject": "{final_subject}",278 "message": "<div>{final_email_html}</div>",279 "outreach_step_type": "",280 "is_reply": false,281 "parents": ["not-accepted-delay"]282 }283 }284}285```286287---288289## Message generation — BASHO framework290291### Philosophy292293Short, relevant, trigger-led messages that read like a real person wrote them. Tied to a294specific reason for reaching out. Never generic templates.295296**Core principles:**297298- **Relevance beats personalization.** Tie the message to _why now_, not "Congrats on…".299- **One idea per email/message.** Don't stack problems, features, and asks.300- **Mobile-first.** Short lines, white space, fast to understand.301- **Write like you talk.** Simple words, short sentences.302- **No cheesy openers.** NEVER use "I hope you're doing well", "I hope this finds you well", or any throat-clearing phrases.303304### Pre-generation checklist305306Before generating any messages, complete these in order:3073081. **What is the user selling / offering?** Product, service, value prop, ICP, problem solved.3092. **Preferred language?** Default English. If non-English, all messages in that language.3103. **LinkedIn Premium?** Determines connection request text (blank vs ≤200 chars) and InMail availability.3114. **(LinkedIn / multi-channel only) Sender name?** LinkedIn has no auto-signature — ask the user for the exact name to sign with (e.g. `"Tomáš Blaťák"`). Do NOT use recipient variables.3125. **Fetch available variables.** Call `mcp__leadspicker__list_contacts(project_id=X, page=1, page_size=5)` to see all columns. Look for:313 - Standard: `{{first_name}}`, `{{last_name}}`, `{{full_name}}`, `{{position}}`, `{{company_name}}`314 - Enriched: `{{linkedin_company_description}}`, `{{website_text_summary}}`, `{{linkedin_about_me}}`, `{{present_experiences}}`315 - **Personalization** (from mcp-personalizer): `{{website_hook}}`, `{{company_hook}}`, `{{experience_hook}}`, `{{icebreaker}}`, `{{salutation}}`, etc.316 - Any custom AI columns from mcp-classification / mcp-personalizer317318### BASHO message structure319320Every message follows this 4-part structure:321322**1) Opener — "Reason I'm reaching out"** (1–2 lines)323324- Sales trigger (funding, hiring, new product, leadership change, expansion)325- Observation (something specific on their site, pricing, messaging, reviews, job posts)326- Peer signal (competitor / adjacent brand doing X)327- Or use a personalization variable: `{{website_hook}}`, `{{icebreaker}}`328- Goal: establish "this isn't a template" immediately.329330**2) Reframe — make them think** (1–2 lines)331332- Pattern interrupt question: "Curious if you're seeing X…"333- Simple outcome statement: "Teams use us to reduce X / improve Y without Z."334- Goal: create curiosity without pitching features.335336**3) Proof — "Others like you succeeded"** (1 line)337338- "Teams like [type] are seeing…"339- "We helped a similar [industry] team…"340- "Commonly we see X within Y weeks…"341- 1 line max — no case-study essays.342343**4) CTA — low-friction next step** (1 line)344345- NOT "book a demo". Instead:346 - "Worth a 10-min chat to compare notes?"347 - "Open to me sending over a quick teardown?"348 - "Should I speak with you or someone else on this?"349- One clear CTA only.350351### Word counts352353| Step | Word count | Notes |354| ------------------------------------------ | ----------- | --------------------------------------------------- |355| Initial email (`is_reply=false`) | 150–200 | Full BASHO |356| Second email follow-up (`is_reply=true`) | 100–150 | Adds one new insight / proof |357| Final email follow-up (`is_reply=true`) | 50–100 | Breakup, close-the-loop |358| LinkedIn DM (`message`) | 150–200 | Full BASHO |359| LinkedIn follow-up DM | 100–150 | Adds new value, shorter |360| **Connection request — non-premium** | **BLANK** | Non-premium gets only 5 messages/month; leave empty |361| Connection request — premium | ≤ 200 chars | Trigger + relevance only |362| InMail (`inmail_message`) | 150–200 | Full BASHO, subject required |363| Email fallback (multi-channel last branch) | 50–100 | Breakup, references previous outreach |364365### Follow-up rules366367- **Second follow-up:** NOT "bumping this". Add something NEW — a sharper insight, a tiny teardown, a relevant example. Reference the prior message briefly, then pivot to new value.368- **Final follow-up / breakup:** Polite close-the-loop. "If the timing isn't right, no worries — just wanted to close the loop." Give them an easy out, leave the door open. Can include one final micro-value or observation.369370### Spintax371372Use spintax `{option1 | option2 | option3}` for text rotation. Required spintax locations:3733741. **Greeting** — always: `{Hi | Hey | Hello}`, or in target language: `{Dobrý den | Zdravím}`.3752. **Closing** — always: `{Best | Cheers | Kind regards | Thanks}`, or in target language: `{S pozdravem | Díky | Přeji hezký den}`.376377Plus 2–4 additional locations per message:378379- Opener: `{I noticed | I saw | Caught my eye that}`380- Reframe: `{Curious if | Wondering whether | Quick question —}`381- Proof intro: `{Teams like yours | Similar companies | Others in your space}`382- CTA: `{Worth a quick chat? | Open to connecting? | Would 10 minutes make sense?}`383- Transitions: `{That said | With that in mind | On that note}`384385**Total: at least 4–6 spintax locations per message** (2 required + 2–4 additional).386387### Subject lines388389- Spintax for rotation, short (3–8 words), curiosity-driven, no clickbait.390- Only the **first email** (`is_reply=false`) has a subject. Follow-ups (`is_reply=true`) have empty subject (same thread).391392Examples:393394```395{Quick question | Thought about this | Noticed something} about {{company_name}}396{{{first_name}} | Quick thought} — {{company_name}}397{Idea for | Question about | Observation on} {{company_name}}398```399400### LinkedIn premium rules401402- **Non-premium:** connection request `message` = **blank** (empty string). No InMail step. Total: LinkedIn-only sequence has 9 steps; multi-channel has 16 steps.403- **Premium:** connection request `message` ≤ 200 chars (e.g. `"Hi {{first_name}}, {{website_hook}} — would love to connect and share thoughts."`). InMail available with subject + 150–200-word body. Total: LinkedIn-only 10 steps; multi-channel 18 steps.404405### Variable priority for openers4064071. `{{icebreaker}}` — LinkedIn posts icebreaker (most personal)4082. `{{website_hook}}` — website-specific4093. `{{company_hook}}` — company LinkedIn-specific4104. `{{experience_hook}}` — person-specific4115. Manual trigger from `{{position}}` + `{{company_name}}` (fallback)412413### Hard rules4144151. ≈150–200 words for initial messages, shorter for follow-ups.4162. **No "hope you're well" / no throat-clearing / no cheesy openers.**4173. No feature dump — talk outcomes and the problem you solve.4184. Specificity wins — numbers, timeframes, scope (when you can).4195. **One clear CTA** (not multiple questions).4206. Avoid spam signals — too many links, heavy formatting, buzzwords, exclamation marks.4217. Write like you talk — simple words, short sentences.4228. Skimmable — 1–2 lines per paragraph, 3–6 short paragraphs.4239. Mobile-first — short lines that look good on phone screens.42410. Each follow-up adds something new — never just "bumping this".42511. Final follow-up = breakup style, close the loop politely.42612. **Emails: NO sender name / signature.** Leadspicker auto-appends the email signature; adding one in the body would duplicate.42713. **LinkedIn: ALWAYS include the sender's real name** at the end of every LinkedIn message. LinkedIn has no auto-signature. Use the exact name the user provided in the pre-generation checklist — never `{{first_name}}` (that's the recipient).428429### Multi-language430431- Default English; ask before generating.432- Spintax in the target language (greetings, closings, transitions).433- If a `{{salutation}}` column exists (from mcp-personalizer), use it instead of generic greeting spintax.434- Messages should read naturally, not like translations.435436### Email body format437438HTML in the `message` field. Use `<div>` and `<br>`.439440```html441<div>442 {Hi | Hey | Hello} {{first_name}},<br /><br />443 {{website_hook}}<br /><br />444 {Curious if | Wondering whether} you're seeing similar challenges with [problem].<br /><br />445 {Teams like yours | Similar companies in {{industry}}} are seeing [outcome] within [timeframe].<br /><br />446 {Worth a quick 10-min chat? | Open to comparing notes?}447</div>448```449450⚠️ Do NOT include sender name or signature — Leadspicker auto-appends it.451452### LinkedIn message format453454Plain text in the `message` field (NOT HTML). Always sign with the user's actual name.455456```457{Hi | Hey | Hello} {{first_name}},458459{{website_hook}}460461{Curious if | Wondering whether} you're exploring [topic] — {teams like yours | others in your space} are seeing [outcome].462463{Worth connecting to share notes? | Open to a quick chat?}464465{Best | Cheers},466{user's actual name}467```468469---470471## Workflow4724731. **Resolve the project** — display as **`{name} (#{id})`**.474 - User named it → `mcp__leadspicker__list_projects(search_query="{name}", limit=5)`.475 - Otherwise → `mcp__leadspicker__list_projects(order_by="last_active", limit=20)` and ask the user to pick.476 Then ask the user which sequence type to build (email / LinkedIn / multi-channel).4772. **Check existing sequence** — `mcp__leadspicker__list_sequence(project_id=X)`. Warn if a sequence already exists.4783. **Pre-generation checklist** — what they're selling, preferred language, LinkedIn Premium, sender name (LI/multi-channel).4794. **Fetch variables** — `mcp__leadspicker__list_contacts(project_id=X, page=1, page_size=5)` to see all columns including hooks / icebreakers / salutations.4805. **Find boolean columns** — `mcp__leadspicker__get_project(project_id=X, info_type="detail")` → look in `headers_data` for entries with `is_boolean: true` and pick their `id`. **If any boolean columns exist, ALWAYS add them as `magic_column_condition` steps at the root** (chained via `relation_type: "yes"`). Skip only if no boolean columns exist.4816. **Generate messages** — apply BASHO, word limits, spintax, and use the available variables. Emails: no sender name. LinkedIn: sign with the user's actual name.4827. **Show all messages to the user for approval** before building.4838. **Delete existing sequence if any** — `mcp__leadspicker__delete_sequence(project_id=X)`.4849. **Build the sequence in ONE call** — `mcp__leadspicker__create_sequence(project_id=X, sequence_messages=...)`. Never chain multiple `create_sequence_step` calls when constructing a new sequence.48510. **Verify** — `mcp__leadspicker__list_sequence(project_id=X)` to show the resulting tree.486487### Deleting a sequence488489`mcp__leadspicker__delete_sequence(project_id=X)` removes ALL steps. There is no API to490delete individual steps — only the entire sequence.491492---493494## Common errors495496| Error | Cause | Fix |497| ----------------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------- |498| `sequence_graph_invalid` | Payload references an unknown parent key, has a cycle, or a branch without a root | Re-check `parents` references and ensure exactly one root. |499| "Field required" for `parent` | Used `parent_id` instead of `parent` | Use the `parent` field name inside `parents` objects. |500| "Input should be '', 'yes' or 'no'" | Invalid `relation_type` | Use `""`, `"yes"`, or `"no"` only. |501| Step created but wrong type in UI | Wrong `outreach_step_type` value | See step types table — e.g. `""` for email, NOT `"email"`. |502503---504505## Natural language matching506507| User says (EN) | User says (CZ) | Action |508| ------------------------------- | ------------------------------- | ------------------------------------------------- |509| "create email sequence" | "vytvoř emailovou sekvenci" | Email sequence (ask offer / ICP first) |510| "create LinkedIn sequence" | "vytvoř LinkedIn sekvenci" | LinkedIn sequence (ask offer / ICP + Premium) |511| "create multi-channel sequence" | "vytvoř multi-channel sekvenci" | Multi-channel (ask offer / ICP + Premium) |512| "3 emails with 3 day delays" | "3 emaily s 3denními pauzami" | Email: 3 emails + 2 delays of 3 days |513| "LinkedIn outreach with InMail" | "LinkedIn oslovení s InMailem" | LinkedIn with InMail (ask Premium) |514| "write outreach messages" | "napiš oslovení" | Generate BASHO messages for the picked sequence |515| "create campaign for [product]" | "vytvoř kampaň pro [produkt]" | Full sequence + messages (ask language + Premium) |516| "delete sequence" | "smaž sekvenci" | `mcp__leadspicker__delete_sequence(project_id=X)` |517| "show sequence" | "ukaž sekvenci" | `mcp__leadspicker__list_sequence(project_id=X)` |