AgentStack
SKILL verified MIT Self-run

Linkedin Outreach

skill-bomx-linkedin-outreach-skill-linkedin-outreach-skill · by Bomx

Local LinkedIn lead scouting and outreach automation for a user's own personal account on their own Mac/IP. Use when the user wants to log in to LinkedIn through a visible local browser, save the local LinkedIn session/cookies, scout warm high-intent leads from LinkedIn search or post commenters, queue reviewed leads, send connection requests or first-degree DMs only after explicit execution, and…

No reviews yet
0 installs
10 views
0.0% view→install

Install

$ agentstack add skill-bomx-linkedin-outreach-skill-linkedin-outreach-skill

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Linkedin Outreach? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

LinkedIn Outreach

Use this skill for personal-account LinkedIn workflows that run on the user's own machine/IP. It is intentionally separate from any VPS, rented account, proxy, database, or systemd setup.

Operating Rules

  1. Run everything on the user's local machine with their normal internet connection. Do not use proxies, rented accounts, VPS sessions, CAPTCHA solvers, stealth patches, or credential-based auto-login.
  2. Keep the browser visible for first login. The user signs in manually in the Chromium/Chrome window opened by the script.
  3. Treat discovery and sending as separate phases. Scout first, review/queue leads second, send only queued leads third.
  4. Dry-run is the default for connection requests and DMs. Use --execute only when the user explicitly asks to send.
  5. Keep daily limits low. Prefer 3-5 connection requests and 3-10 DMs per run unless the user intentionally changes the cap.
  6. Stop if LinkedIn shows a checkpoint, CAPTCHA, restricted-account warning, or any unusual security prompt. Ask the user to handle it manually.
  7. Log every material event to the local JSON database so the next agent can resume without guessing.
  8. If LinkedIn shows CAPTCHA, checkpoint, identity verification, restriction, or unusual-activity text, the script records a 24-hour safety cooldown in ~/.linkedin-outreach/db/safety_state.json. Do not bypass this unless the user has manually resolved LinkedIn in their normal browser and explicitly accepts the risk.

For the detailed safety and database rules, read references/operating_rules.md and references/database_schema.md when changing the workflow or interpreting stored records.

Script

All workflow actions go through:

python3 scripts/linkedin_outreach.py 

The script prints one final RESULT: {...} JSON line. Parse that line as the canonical result.

Install dependencies once:

python3 -m pip install -r requirements.txt
python3 -m playwright install chromium

Optional: use the user's installed Chrome instead of Playwright Chromium:

export LINKEDIN_BROWSER_CHANNEL=chrome

Optional: store data somewhere other than ~/.linkedin-outreach:

export LINKEDIN_OUTREACH_DATA_DIR=/absolute/path/to/linkedin-outreach-data

Workflow

1. Doctor

Check dependencies and show where state will be stored:

python3 scripts/linkedin_outreach.py doctor

2. Login

Open a visible local browser. The user signs into LinkedIn manually in that browser. The script saves the persistent browser profile and a storage_state.json snapshot.

python3 scripts/linkedin_outreach.py login --timeout 600

If a session already works, the command exits quickly.

3. Scout Leads And Signals

Scout high-intent original posts and target the post author:

python3 scripts/linkedin_outreach.py scout-search \
  --query "looking for SEO consultant" \
  --intent buyer_intent \
  --limit 25

Scout people commenting on a competitor/person/company activity feed:

python3 scripts/linkedin_outreach.py scout-activity \
  --target-url "https://www.linkedin.com/in/cyriaclefort/" \
  --signal-name "competitor-ceo-cyriac-lefort-engagers" \
  --source-label "Engaged with Cyriac Lefort" \
  --max-posts 5 \
  --limit 30

Scout comment authors who mention a keyword under searched posts:

python3 scripts/linkedin_outreach.py scout-comment-keyword \
  --query "technical SEO" \
  --keyword "technical SEO" \
  --signal-name "comments-technical-seo" \
  --limit 30

Scout commenters from a warm post:

python3 scripts/linkedin_outreach.py scout-post \
  --post-url "https://www.linkedin.com/feed/update/urn:li:activity:..." \
  --limit 30

All scout commands upsert leads into the JSON database and keep source evidence. If the same person appears in multiple signals, their source_history accumulates those signals.

Every scout run can also run a post-scout connection-attempt phase against newly changed leads. It queues eligible leads and dry-runs up to 5 connection requests by default:

python3 scripts/linkedin_outreach.py scout-search \
  --query "looking for SEO consultant" \
  --intent buyer_intent \
  --connection-limit 5 \
  --connection-intent buyer_intent

Actually send those post-scout connection requests only when the user explicitly asks. These send without notes by default:

python3 scripts/linkedin_outreach.py scout-search \
  --query "looking for SEO consultant" \
  --intent buyer_intent \
  --connection-limit 5 \
  --connection-intent buyer_intent \
  --connection-new-only \
  --connection-navigation-mode random \
  --execute-connections

In live post-scout runs, --connection-limit is the target number of successful new invitations. If a selected lead is already pending or connected on LinkedIn, it does not count toward that target and the runner continues through the eligible candidate pool. Use --connection-new-only when the run should only auto-connect leads inserted during the current scout. Use --connection-navigation-mode random to mix direct profile URL loads with LinkedIn click-through attempts. Use --no-connect to scout without the connection-attempt phase.

For a "full pipeline", prefer safe chunks instead of one long browser-heavy session:

python3 scripts/linkedin_outreach.py sync-connections --contacted --limit 12
python3 scripts/linkedin_outreach.py dm --lead-id li_reviewed --execute --limit 3
python3 scripts/linkedin_outreach.py connect --queued --limit 3 --execute --no-note --navigation-mode random

Do not run fresh scouting immediately after a sync + DM batch unless the user explicitly requests it and there is no active safety cooldown. Prefer already stored, reviewed leads before opening more LinkedIn search pages.

If using a note, queue and review first, then send one lead at a time with a final AI-written, fully personalized note. Do not use placeholders or raw source labels in connection notes:

python3 scripts/linkedin_outreach.py connect \
  --lead-id li_abc123 \
  --message "Hi Alex, your post about rebuilding your technical SEO stack caught my eye. Thought it would be useful to connect." \
  --execute

Save reusable radar definitions:

python3 scripts/linkedin_outreach.py signal-add \
  --name "seo-buyer-intent-posts" \
  --type post_intent \
  --query "looking for SEO consultant" \
  --intent buyer_intent \
  --source-label "SEO buyer intent post"

python3 scripts/linkedin_outreach.py signal-add \
  --name "active-seo-agency-owners" \
  --type post_intent \
  --query "SEO agency founder" \
  --source-label "Active SEO agency owner" \
  --limit 50 \
  --scrolls 6

python3 scripts/linkedin_outreach.py signal-list
python3 scripts/linkedin_outreach.py signal-run --name "seo-buyer-intent-posts" --limit 5

4. Review And Queue

List spotted and queued leads:

python3 scripts/linkedin_outreach.py review --list --limit 30

Queue specific leads after review:

python3 scripts/linkedin_outreach.py review --queue li_abc123 li_def456

Queue top-scored leads:

python3 scripts/linkedin_outreach.py review --queue-top 5 --min-score 0.65

Reject leads that should not be contacted:

python3 scripts/linkedin_outreach.py review --reject li_bad123

5. Send Connection Requests

Dry-run queued connection requests:

python3 scripts/linkedin_outreach.py connect --queued --limit 3

Actually send:

python3 scripts/linkedin_outreach.py connect --queued --limit 3 --execute

Connection requests send without a note by default. Use --message "..." only for a final AI-written, fully personalized note for one selected lead. Do not use placeholders or raw source labels in connection notes.

6. Send DMs

Before sending DMs, sync contacted leads so accepted connection requests are marked as connected in the local database:

python3 scripts/linkedin_outreach.py sync-connections --contacted --limit 12

Dry-run first-degree DMs:

python3 scripts/linkedin_outreach.py dm --lead-id li_abc123

Before executing any DM batch, review each selected lead's headline and stored source evidence against the exact DM text. Only send if the CTA is coherent for that person's business and role. Skip or reject leads that are merely tangential, competitors, product operators, investors, recruiters, or generic engagers. Never rely on a broad signal label alone as proof that the message fits.

Actually send:

python3 scripts/linkedin_outreach.py dm --lead-id li_abc123 --execute

The default DM template lives in ~/.linkedin-outreach/db/templates.json.

7. Inspect Or Export

python3 scripts/linkedin_outreach.py status
python3 scripts/linkedin_outreach.py export

Data Model

Default local state:

~/.linkedin-outreach/
  session/profile/             persistent local browser profile
  session/storage_state.json    Playwright cookie/session snapshot
  session/session_meta.json     last login metadata
  db/leads.json                 local lead database
  db/signals.json               reusable radar definitions
  db/safety_state.json          stop-condition cooldown state
  db/suppressions.json          never-contact profiles, e.g. competitors
  db/actions.jsonl              append-only action/event log
  db/runs.jsonl                 append-only run log
  db/templates.json             editable DM template; connection_note is blank by default
  exports/                      CSV exports
  screenshots/                  debug screenshots on failures

Never commit these files. They contain personal account/session data and outreach history.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.