skills/linkedin-voyager/SKILL.md
Read LinkedIn profile data (bio, headline, experience, education, skills, contacts) via the unofficial Voyager API. Uses your browser session cookies — NO password. Sibling to the official-API `linkedin` skill. Use when user wants to see or export their own (or a public) profile content not available in the official API.
npx skillsauth add RonanCodes/ronan-skills linkedin-voyagerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Read-side sibling to ro:linkedin. Hits LinkedIn's internal Voyager API (same API the linkedin.com web app uses) via the linkedin-api Python library (tomquirk). Gives access to profile sections the official OAuth API doesn't expose: About, Headline, Experience, Education, Skills, Certifications, Contact info, Connections, etc.
This skill uses an undocumented internal API and authenticates with your session cookies. Per LinkedIn's User Agreement §8.2, automated access that is not through their public API is prohibited. Aggressive or high-volume usage has resulted in account restrictions or bans. Use sparingly:
/ro:linkedin (official API) for anything it covers./ro:linkedin (official API) when possible./ro:linkedin-voyager profile ronanconnolly # your own profile (bio/headline/experience/skills)
/ro:linkedin-voyager profile satyanadella # any public profile slug
/ro:linkedin-voyager contact ronanconnolly # email/phone/twitter if the viewer can see them
/ro:linkedin-voyager search "staff engineer" # people search (limited)
/ro:linkedin-voyager connections # the viewer's own 1st-degree connections
On every run, scripts/voyager.py extracts li_at + JSESSIONID from the browser set by ROBROWSER in ~/.config/ro/defaults.env (or --browser <name>), using browser_cookie3. No password is ever prompted or stored. Cookies stay in memory.
If the library rejects the cookies (LinkedIn sometimes requires challenges), log into linkedin.com once in the browser and retry.
Profile output (default — compact human-readable):
# <Full Name> — <Headline>
<location> · <industry>
linkedin.com/in/<slug>
## About
<bio text>
## Experience
- <Title> @ <Company> (<start> – <end or Present>) <location>
<description if any>
- ...
## Education
- <School> — <Degree> <Field> (<years>)
## Skills
skill1, skill2, skill3, ...
Add --json for raw Voyager JSON (huge — useful for wiki ingest or diffs).
| Arg | Function |
|-----|----------|
| profile <slug> | get_profile(public_id=slug) + pretty-printer |
| contact <slug> | get_profile_contact_info(public_id=slug) |
| search <terms> | search_people(keywords=terms, limit=10) |
| connections | get_profile_connections(<viewer>) |
uv run --with 'linkedin-api>=2.3' --with browser-cookie3 python3 \
/path/to/skills/linkedin-voyager/scripts/voyager.py <cmd> <args...>
uv provisions the deps on first run; subsequent runs are fast.
profileFullProfile-138 which returns the top card only: name, headline, summary (About/bio), location, profile picture./identity/dash/profilePositions?viewee=<urn>&...). Not yet wired. Add as a second call chained after the top card if the caller wants the full profile.get_profile() hits /identity/profiles/<slug>/profileView which returns 410 Gone as of 2026-Q1. Don't use it — this skill's cmd_profile calls the dash endpoint directly.linkedin-api is usually patched within weeks. uv auto-picks the latest compatible version per run.Set-Cookie: li_at=delete me + infinite 302 loops to the same URL, LinkedIn has invalidated the session server-side. Log back into the browser and wait ~30 min before retrying..www.linkedin.com and quoted JSESSIONID values like "ajax:...". requests' cookiejar won't send .www.linkedin.com-scoped cookies to host www.linkedin.com, and the quoted JSESSIONID won't match the csrf-token header (which is set unquoted). Both caused 403 "CSRF check failed" until get_cookies() rebuilt the jar with .linkedin.com domain + stripped JSESSIONID quotes./ro:linkedin — official OAuth API: posts + draft-mode profile edits. Start there./ro:linkedin-scan — light scraping of the public-facing HTML (even safer, less structured)./ro:browser-cookies — the underlying cookie path this skill uses.development
--- name: worktree description: Coordinate multiple agents on one repo via a worktree-lock pool, so two agents never clobber each other's working tree. Acquire the first free slot (main, then beta/gamma… worktrees, created on demand), work there on your own branch, release when you've pushed. Use before modifying any repo that might be in use by another agent (factory, dataforce, etc.), or whenever you're told a repo is being worked on. Backed by `ro worktree`. category: development argument-hin
testing
--- name: ship description: Ship a feature branch the local-CI-first way — run the full local gate, push, open a PR, squash-merge, then deploy, without waiting on GitHub Actions. Use when a branch is ready for main and you want it merged and deployed now. Reads CI policy from `ro ci` (default skips remote CI because GitHub Actions billing keeps hitting limits). Sibling to /ro:gh-ship (waits on GitHub checks) and /ro:cf-ship (the deploy half). Triggers on "ship it", "ship this", "merge and deploy
testing
--- name: setup-logging description: Set up (or audit) the observability stack in a TanStack Start + Cloudflare Workers app so it is "diagnosable by default" — structured logging (logtape) with a request context carrying trace_id + userId + tenant/orgId, a trace_id propagated FE→BE→logs→Sentry→PostHog, Cloudflare Workers observability enabled, and Sentry + PostHog wired. Two modes: `setup` (wire it into an app) and `audit` (check an existing app + report gaps). Use when scaffolding a new app, wh
development
Manage credentials INSIDE the active ~/.claude/.env file — read which token/account to use for a given app (Simplicity vs Dataforce vs Ronan-personal), add or update a secret WITHOUT it passing through the chat (an interactive Terminal window prompts for it), and track secrets that were exposed in a transcript so they get rotated. Sibling to /ro:context (which switches WHICH env file is active). Use when the user wants to add an API key/token/secret, asks "which credential do I use for X", needs the env organized/labelled, or a secret was pasted into the chat and should be rotated.