LinkedIn

get-post

linkedin.com · Cowork
Download for Coworkthe skill folder, zipped
How to use it in Coworkonce per skill
Download the skill (.zip)

One .zip per skill. Inside: SKILL.md with the intent and the frontmatter, and the code that runs in the page.

Open Skills in Cowork

Settings → Personalize → Skills. This is Cowork's own skill library, shared across every chat.

Add → pick the .zip

Click Add and choose the file you just downloaded. Cowork installs it once; no CLAUDE.md, no per-project setup.

Ask in plain language

The skill stays available in every session. Cowork runs it in your own Chrome, riding the session you are already signed into.

Side effectread
Authsession
Needsnavigate · evaluate
Summary

Fetch ONE LinkedIn post with its full context (post + visible comments) from its urn (urn:li:activity:NNN) or its permalink url.

Params
{"urn":"string (urn:li:activity:NNN, a /feed/update/ url, or a /posts/<slug>-activity-NNN-<code> permalink)","reactors":"bool optional (default true)","comments":"bool optional (default true)","maxPeople":"int optional (default 100, max 100, LinkedIn's per-call ceiling)"}
Returns
{"urn":"string","shareUrn":"string|null","url":"url","author":"string","authorSlug":"string","authorHeadline":"string|null","text":"string|null","time":"string|null","reactions":"int","comments":"int","reactionTypes":"object { LIKE:int, PRAISE:int, ... }","isRepost":"bool","commenters":"array of { name, slug, headline, text }","reactors":"array of { name, slug, type, degree, headline }"}
SKILL.md58 lines

linkedin-get-post

Fetches one post with everyone around it: reactors and commenters each come back with a slug you can feed to linkedin-get-profile or linkedin-connect. A people-discovery path, not just a post reader.

Resolves in a single bridge call: the urn drives three same-origin fetches (feed/updates/{urn} for the post, feed/comments for the commenters, feed/reactions for the reactors), so it works from any page and never touches the DOM. The payload is asserted to mention the requested activity id, if it does not, the call throws rather than returning a different post's data. In v1 this skill was a DOM scraper whose urn param was pure echo: called from the wrong page it happily returned another post's author, text and counts stamped with the urn you asked for.

The extractor lives as text in the site's localStorage (key linkedin-get-post) and is rebuilt on each call with synchronous eval. It is stored once and then persists across navigation and browser restarts, so on every run except the first it is already there.

Reactor ceiling. feed/reactions returns at most 100 per call and this skill does not paginate, so a post with more than 100 reactions comes back with the first 100, compare reactors.length against reactions to detect the truncation.

Default action: just call (step 1). The call itself reports NEEDS_STORE when the extractor is missing or out of date, only then do you store it (step 2) and call again.

Versioning. The stored extractor is gated by VER (must match the version in the frontmatter above). Both snippets carry VER = "2", keep them in sync with the frontmatter. When evaluate.js changes, bump version and VER in both snippets: the next call sees the mismatch, returns NEEDS_STORE, and re-stores automatically. Storage stays at two keys (linkedin-get-post and linkedin-get-post:ver), overwritten each store, versions never accumulate.

1. Call (do this every run, params only, single bridge call)

await (() => {
  const KEY = "linkedin-get-post", VER = "2";
  const s = localStorage.getItem(KEY);
  if (!s || localStorage.getItem(KEY + ":ver") !== VER) return 'NEEDS_STORE';
  const fn = eval('(' + s + ')');
  return fn(document, { urn: "urn:li:activity:7280000000000000000" });
})()

Returns the post plus its reactors and commenters. If it returns the string 'NEEDS_STORE', the extractor is missing or stale in this browser → do step 2 once, then run this exact call again.

Run this snippet verbatim. Never add an await before the eval, only the outer await is allowed; a pre-eval await trips LinkedIn's CSP and the call fails.

2. Store (only when step 1 returned NEEDS_STORE; persists until localStorage is cleared)

While logged in at https://www.linkedin.com/feed/ (the JSESSIONID cookie must be present), evaluate the following with the bridge, replacing <FN> with the contents of evaluate.js (the ( async (root, params) => { ... } ) function). Keep VER equal to the call snippet's:

(() => {
  const KEY = "linkedin-get-post", VER = "2";
  const fn = (<FN>);
  localStorage.setItem(KEY, String(fn));
  localStorage.setItem(KEY + ":ver", VER);
  return 'stored';
})()

Returns "stored". The extractor passes through the model only here, once. Then go back to step 1.

Errors

  • NEEDS_STORE → extractor missing or version-mismatched in this browser; run step 2 once, then retry step 1.
  • tool-broken: could not resolve → the urn is wrong, or the post is private/deleted.
  • re-auth / no JSESSIONID → no LinkedIn session in this browser; log in once.
  • tool-broken → LinkedIn changed the API shape; recapture the extractor.

Success assertion

{ "type": "json", "jsonPath": "post" }
get-post: the LinkedIn skill in Cowork · browser-memory