linkedin-outreach
The LinkedIn Outreach skill generates personalized LinkedIn message sequences from qualified leads stored in Supabase, then exports them in a format compatible with the user's chosen LinkedIn tool (Dripify, Botdog, Expandi, PhantomBuster, or manual). Use this skill when you need to conduct LinkedIn outreach campaigns with multiple follow-up messages while maintaining a logged record of all interactions in Supabase.
git clone --depth 1 https://github.com/gooseworks-ai/goose-skills /tmp/linkedin-outreach && cp -r /tmp/linkedin-outreach/skills/capabilities/linkedin-outreach ~/.claude/skills/linkedin-outreachSKILL.md
# LinkedIn Outreach
The LinkedIn counterpart to `cold-email-outreach`. Takes qualified leads from Supabase, builds personalized LinkedIn message sequences, exports for the user's LinkedIn outreach tool, and logs everything back to Supabase.
**Tool-agnostic:** Asks the user which LinkedIn tool they use. All tools are CSV-import based — no API/MCP automation for LinkedIn tools (they're browser-based). Adapters handle column mapping and format differences per tool.
## When to Auto-Load
Load this skill when:
- User says "LinkedIn outreach", "connect with these leads on LinkedIn", "send LinkedIn messages", "set up a LinkedIn campaign"
- An upstream skill connects with "create LinkedIn campaign" or "passes: supabase-eligible-leads" and user specifies LinkedIn
- User completes `lead-qualification` and wants to reach out via LinkedIn
## Supported Outreach Tools
This skill does NOT assume a specific tool. It asks first, then adapts.
| Tool | Integration | How It Works |
|------|------------|--------------|
| **Dripify** | CSV import | Generate CSV matching Dripify's import format, user uploads manually |
| **Botdog** | CSV import | Generate CSV with Botdog-compatible columns |
| **Expandi** | CSV import | Generate CSV matching Expandi import format |
| **PhantomBuster** | CSV import | Generate CSV for PhantomBuster LinkedIn sequences |
| **Manual / Other** | CSV + instructions | Export leads + messages as generic CSV, provide setup instructions |
**Tool selection logic:**
1. Ask user in Phase 0: "Which LinkedIn outreach tool do you use?"
2. Generate tool-specific import CSV based on selection
3. If **Other or unknown** → generate generic CSV (`linkedin_url`, `first_name`, `last_name`, `company`, `title`, `connection_request`, `followup_1`, `followup_2`, `followup_3`, `inmail_subject`, `inmail_body`) and ask user for their tool's import requirements
## Prerequisites
### Supabase
People must be stored in Supabase with the schema from `tools/supabase/schema.sql`. The `people` and `outreach_log` tables must exist. Run `python3 tools/supabase/setup_database.py` if setting up fresh.
Environment variables in `.env`:
```
SUPABASE_URL=https://xxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...
```
### LinkedIn Tool
Just need CSV export — no API keys required. The user imports the CSV into their tool manually.
## Character Limits
LinkedIn enforces strict character limits. **All generated messages must respect these.**
| Message Type | Limit | Notes |
|-------------|-------|-------|
| Connection request note | 300 characters | Hard limit. Every character counts. |
| Regular message | 8,000 characters | Sent after connection accepted |
| InMail subject | 200 characters | Only for InMail (premium feature) |
| InMail body | 1,900 characters | Only for InMail |
**Enforcement:** After generating any message, count characters. If over the limit, rewrite — do not truncate. Truncated messages look broken.
## Phase 0: Intake
Ask all questions at once. Organize by category. Skip any already answered by an upstream skill.
### Campaign Goal
1. What's the objective? (book meetings, drive demo requests, get replies, build relationships, nurture)
2. What's the outreach angle or hook? (hiring signal, competitor displacement, event-based, pain-based, cold database, KOL engagement, mutual connection)
3. What should we name this campaign?
### Outreach Tool
4. Which LinkedIn outreach tool do you use? (Dripify / Botdog / Expandi / PhantomBuster / Other / Just give me a CSV)
### Lead Selection
5. Which leads should we target? Options:
- All leads for a specific `client_name`
- Specific `icp_segment`
- Title patterns (e.g., "VP Operations", "Director of Sales")
- Industry or location filters
- `qualification_score` above a threshold
- Specific `source` (crustdata, apollo, linkedin, etc.)
- Custom filter (describe what you want)
6. Any exclusions? (specific companies, recently contacted leads, certain titles)
7. Max campaign size? (default: 100 — LinkedIn tools have lower daily limits than email)
### Tone & Style
8. Which tone preset? Present these options:
- **Casual Professional** — Friendly, human, slightly informal. Like messaging a peer. (default)
- **Thought Leader** — Lead with insight or a contrarian take. Position sender as an expert.
- **Provocative** — Challenge assumptions, pattern-interrupt. Higher risk, higher reward.
- **Enterprise Formal** — Polished, structured. For regulated industries or C-suite targets.
- **Custom** — Paste reference messages that worked before, or describe the vibe.
9. Any reference messages that have worked well? (paste examples — these override tone presets)
### Sequence Structure
10. How many follow-ups after connection? (default: 3)
11. Timing between messages? (default: Day 0 connection / Day 3 FU1 / Day 7 FU2 / Day 14 FU3)
12. Include InMail as a separate step for leads who don't accept the connection? (default: yes)
### Personalization
13. What signal data is available for these leads? (comment text, post they engaged with, mutual connections, hiring signals, event attendance)
14. Any proof points or case studies to reference? (customer names, metrics, testimonials)
## Phase 1: Lead Selection from Supabase
### Connect
Use the shared Supabase client:
```python
import sys, os
sys.path.insert(0, os.path.join("tools", "supabase"))
from supabase_client import SupabaseClient
client = SupabaseClient(os.environ["SUPABASE_URL"], os.environ["SUPABASE_SERVICE_ROLE_KEY"])
```
### Build Filters
Map user criteria to PostgREST query parameters on the `people` table:
| User Says | PostgREST Filter |
|-----------|-----------------|
| "VP Operations" | `title=ilike.*VP Operations*` |
| Client "happy-robot" | `client_name=eq.happy-robot` |
| Score > 7 | `qualification_score=gte.7` |
| Has LinkedIn URL | `linkedin_url=neq.` (not empty) |
| Industry "logistics" | `industry=ilike.*logistics*` |
| Location "San Francisco" | `location=ilike.*S>
AI video conversations - create real-time video calls with AI personas
AI-powered web scraping - extract data using natural language prompts
Search Amazon products - find items, compare prices, read reviews
Test and document API endpoints - validate responses, check status, generate examples
>
>
Brand intelligence - logos, colors, fonts, styleguides, and company data from any domain