I scored my LinkedIn feed with Jev. It cost three tenths of a cent.
Abdumajid Rashidov · 21 September 2026 · 7 min readMy LinkedIn feed had reached the point where I could predict the next post before it loaded. A contrast hook, three one-sentence paragraphs, an emoji list, "Agree?". So I built a Chrome extension that scores every post and folds the ones that read like generated text. This is what worked, what didn't, and what it costs to run.
Rules first, because they're free
Version one was eleven pattern rules running in the content script: em-dash density, curly quotes (LinkedIn's composer produces straight ones, so curly quotes mean the text was pasted from somewhere), staccato paragraphs, corporate openers, engagement-bait closers, "It's not X. It's Y." Each hit adds weight; over a threshold, the post collapses into a card with the reasons listed.
Rules are fast, private and explainable. They are also blunt. On a 24-post calibration set I labelled by hand, half human and half generated, the rules reached 79 percent accuracy and 58 percent recall. The misses were the polished ones: generated posts with no em dashes and no emoji, just the shape.
A decision model instead of an LLM
The obvious upgrade is "ask an LLM". I didn't want a chat model in the loop: too slow for a feed that renders faster than you scroll, too expensive per post, and the output would need parsing.
Jev, released by TypeSafe AI on 15 September 2026, is a different kind of model. TypeSafe calls it a System One model: you give it a state (here, the post text) and yes/no questions with explicit criteria, and it returns a calibrated probability per question. It does not generate text at all. No prose, no parsing, nothing to hallucinate. I ask four questions per post: does this read as AI-written, is it engagement bait, is it a fabricated humblebrag story, is it recruiter or sales spam. Four numbers come back in one call.
Numbers from the same 24 posts, default threshold:
| Accuracy | Recall | False positives | |
|---|---|---|---|
| Rules only | 79% | 58% | 0 |
| Jev | 92% | 83% | 0 |
Human posts scored between 6 and 16 percent "AI-written". Generated ones scored 44 to 89. The gap is what makes a threshold possible. Twenty-four posts is a small set and I say so wherever I quote it; the point was to see whether a threshold existed, and it does. The set includes Russian and Uzbek posts, which the rules handle badly and the model handles fine.
What it costs
A LinkedIn post is about 940 input tokens with the four questions attached. At Jev's list price of $0.042 per million input tokens, that is roughly $0.00004 per post. My whole feed for 18 September, 69 posts, cost about $0.003: three tenths of a cent. On launch day, 20 September, the proxy scored 492 posts for a handful of installs, about two cents in total. Model latency is around 130 ms; with 100 ms of client-side batching, the badge lands well under a second after the post renders.
The proxy
The extension never holds an API key. It sends post text to a Cloudflare Worker with two caps: 400 posts per install per day, and a service-wide daily cap, both counters in KV. The Worker forwards to Jev, returns the four percentages, logs token counts and never the text. Total code, including tests, is a few hundred lines.
The rules still run on-device for everyone. Slop Score is opt-in behind a consent card, because "sends the text of what you read to a server" deserves an explicit yes.
Things that went wrong
- Two entry files named
index.ts. The bundler wired the content-script bundle into the service worker loader. Every message from the page failed with "Receiving end does not exist", and the extension quietly fell back to rules. Renaming the background entry fixed it; the automated tests never saw it because they test modules, not the built artefact. - "Illegal invocation". Storing
fetchin a variable and calling it later works in Node and fails in the Workers runtime. Call the global lazily. - A trailing newline in a secret. Piping the API key through the shell added a newline, and the upstream rejected the header. The client now trims.
- A badge that said 65% while the threshold was 65%. Scores are rounded for display and were compared raw. A post at 0.646 showed "65% AI" and stayed open. Thresholds now compare on the same rounded percentage the user sees.
- The spam question hated job posts. My first criteria text made an honest "we're hiring, salary in the listing" post score 92 percent spam. Rewriting the criteria to exempt concrete listings dropped it to 4 percent. Criteria wording is the whole game with this kind of model.
What I'd tell someone building the same thing
Start with rules; you'll want them as the offline path anyway. Put the model behind a proxy you control. Make the score a number the user can see, not a hidden verdict. And label your own feed for an afternoon before you trust any threshold.
Try it
The extension is NoSlop for LinkedIn: free, no account, rules on your device by default, Slop Score when you want the number. It hides posts written by AI, not posts about AI.
Further reading
- TypeSafe AI, 15 September 2026: Introducing System One models and Jev
- NoSlop: How to hide AI-generated posts on LinkedIn · LinkedIn AI detectors, feed blockers and the slop button, compared · what leaves your browser and what doesn't
Questions, the eval set, or a post the filter got wrong: hello@noslop.lol.