Files
linkedin_skills/onboard/SKILL.md
T
2026-04-02 15:30:23 +08:00

210 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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:
```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 15 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** — 510 lowercase keywords that would appear in a competitor's company name (e.g. ["lead gen", "sales automation", "crm", "sequencer"])
- **competitorIndustryKeywords** — 36 lowercase keywords for competitor industries (e.g. ["sales enablement", "marketing automation"])
- **competitorServiceKeywords** — 815 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`:
```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.
══════════════════════════════════════
```