| name | onboard |
| version | 1.0.0 |
| description | First-run onboarding. Analyzes the user's landing page to suggest an ICP,
asks for confirmation and any additions, then collects timezone + cadence.
Saves everything to state/linkedin-settings.json and marks firstRunCompleted: true.
Run this once before using any other skill.
|
| allowed-tools | ["Read","Write","AskUserQuestion","Bash"] |
Voice
Clear and helpful. You're doing the heavy lifting ā the user just confirms.
Never dump a blank form. Always propose first, then ask for corrections.
Completion Status Protocol
- DONE ā Settings saved, firstRunCompleted set to true.
- BLOCKED ā Cannot proceed. State what failed and what was tried.
- NEEDS_CONTEXT ā Missing required input. State exactly what you need.
Step 0: Check if already set up
Read state/linkedin-settings.json.
If firstRunCompleted is true, say:
Setup already complete. Your ICP is loaded in state/linkedin-settings.json.
To re-run setup, set "firstRunCompleted": false in that file and run /onboard again.
Then stop.
If the file doesn't exist, copy defaults from config/default-settings.json and continue.
Step 1: Get the landing page URL
Ask:
Context: First-time setup for LinkedIn outreach.
What is your product or service landing page URL?
(e.g. https://yourcompany.com ā I'll analyze it to suggest your ICP)
Step 2: Analyze the landing page
Call the proxy with bash:
curl -s -X POST https://landing-page-analysis-proxy.vercel.app/api/crawl \
-H "Content-Type: application/json" \
-d "{\"url\": \"<URL_FROM_STEP_1>\"}"
Parse the returned markdown content.
From the content, extract and infer:
- industries ā what industries does this product serve?
- seniority ā what job levels are likely buyers? (look for "for teams", "for founders", "for managers", etc.)
- companySizes ā any signals about company size? (e.g. "enterprise", "startups", "SMBs")
- geographies ā any regional focus mentioned?
- alwaysExcludeRoles ā any roles clearly not the target?
- offer summary ā one sentence: what does this product do and who is it for?
- disqualifyCategories ā always include
competitors and non_decision_makers. Then derive 1ā5 additional categories from the product analysis. Each should be a short snake_case label with a plain-English description. Only add categories that genuinely follow from what the product does and who it serves ā do not pad. Examples:
- A B2B SaaS tool ā
b2c_focused (companies selling to consumers, not businesses)
- An outbound sales tool ā
no_outbound_intent (companies with no sales motion)
- A hiring tool ā
no_hiring_activity (companies not actively hiring)
- A compliance tool ā
non_regulated_industries (industries without compliance requirements)
- A developer tool ā
non_technical_teams (teams with no engineering function)
- A PLG product ā
no_self_serve_motion (companies that only buy through procurement)
Also infer the competitor profile ā who would be disqualified from outreach because they are competitors or would never buy:
- competitorDescription ā one sentence: what kind of company is a competitor? (e.g. "Companies that offer similar outreach automation or lead generation tools")
- competitorCompanyKeywords ā 5ā10 lowercase keywords that would appear in a competitor's company name (e.g. ["lead gen", "sales automation", "crm", "sequencer"])
- competitorIndustryKeywords ā 3ā6 lowercase keywords for competitor industries (e.g. ["sales enablement", "marketing automation"])
- competitorServiceKeywords ā 8ā15 lowercase phrases describing the specific services a competitor would offer, grounded in what this product does (e.g. if the product automates LinkedIn outreach, then: ["linkedin outreach", "automated prospecting", "cold outreach", "outbound sequences", "sales cadence", "prospect automation"]). These will be matched against a lead's company description or bio, so phrases should reflect how competing services describe themselves.
If the proxy call fails, say:
BLOCKED: Could not fetch the landing page.
Error: [error message]
Please check the URL and try again, or provide your ICP manually.
Then ask the user to provide ICP fields manually and skip to Step 4.
Step 3: Present suggested ICP for confirmation
Show the extracted ICP and competitor profile in this format:
Based on your landing page, here's your suggested ICP:
Offer: [one-sentence summary]
Industries: [list]
Seniority: [list]
Company size: [list or "not specified"]
Geographies: [list or "not specified"]
Exclude roles: [list]
Disqualify ā leads in these buckets will be filtered out:
[for each category: "- category_label: plain English description"]
And here's the inferred competitor profile (used to auto-filter leads):
Competitors: [competitorDescription]
Co. keywords: [competitorCompanyKeywords joined with ", "]
Industries: [competitorIndustryKeywords joined with ", "]
Services: [competitorServiceKeywords joined with ", "]
Does this look right?
A) Yes, looks good
B) Some changes needed ā tell me what to adjust
C) Ignore this, I'll fill in everything myself
If B: apply the user's corrections to both the ICP and the competitor profile before continuing.
If C: ask for each ICP field individually, then ask for competitor description and keywords.
Step 4: Collect conversion goal
The user already provided a landing page URL in Step 1. Use it as the default. Ask:
What do you want an interested prospect to do?
A) Visit your landing page ā [URL from Step 1]
B) Book a call ā paste a Calendly or booking link
C) Fill out a form ā paste the form URL
D) Receive a lead magnet ā paste the link
E) Subscribe to a newsletter ā paste the link
F) Other ā describe it
Wait for the user to reply before continuing. Do not assume A.
If user confirms A: set outreach.conversionGoal.type to landing_page and outreach.conversionGoal.link to the URL from Step 1.
Otherwise: save their choice as type and their link as the URL. If no link given, leave link as null. Do not block progress.
Step 5: Save settings
Write the confirmed ICP + preferences into state/linkedin-settings.json:
targetMarket.industries
targetMarket.seniority
targetMarket.companySizes
targetMarket.geographies
targetMarket.alwaysExcludeRoles
qualification.disqualifyCategories ā array of snake_case labels derived in Step 2 (e.g. ["competitors", "non_decision_makers", "b2c_focused"])
outreach.conversionGoal.type
outreach.conversionGoal.link (may be null)
firstRunCompleted ā true
Also write the competitor profile to state/competitor-profile.json:
{
"generatedAt": "<ISO timestamp>",
"sourceUrl": "<landing page URL>",
"description": "<competitorDescription>",
"companyKeywords": ["<keyword1>", "<keyword2>", "..."],
"industryKeywords": ["<keyword1>", "<keyword2>", "..."],
"serviceKeywords": ["<phrase1>", "<phrase2>", "..."]
}
Step 6: Confirm and hand off
Output:
SETUP COMPLETE
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Offer: [summary]
Industries: [list]
Seniority: [list]
Company size: [list]
Geographies: [list]
Goal: [conversionGoal.type] ā [conversionGoal.link or "no link set"]
Settings saved to: state/linkedin-settings.json
Competitor profile: state/competitor-profile.json
What's next:
Step 1 ā /calibrate-voice Build your voice profile so every message sounds like you, not a bot.
Step 2 ā /linkedin-lead-filter Filter your CSV leads against your ICP.
Step 3 ā /draft-outreach Draft personalized first-touch messages for qualified leads.
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā