this post sux
sux README.md
4.0 kB
Markdown
at main

sux #

A firefox plugin to filter shit out of your bsky feed

Mostly, it was just an excuse to fuck with jev.

What follows is pure Kimi-lish, because I don't feel like doing better at the moment. It'll be rewritten at some point in the next week or two, probably after the userscript-based rewrite. The neuralese is pretty complete tho.

A feed filter for bsky.app (Firefox, Zen Twilight, and other Firefox-based browsers). Every post Bluesky's web app retrieves is judged by Jev (TypeSafe's System One model); posts that don't pass your rules are hidden.

Rules (set in the sidebar) #

  • Two words — Jev decides whether a post is more word 1 or word 2. A post is shown when Jev puts at least 50% probability on word 1.
  • One word + direction — Jev answers "is this post ${word}?" with a probability. Choose are mostly (shown when > 50%) or are NOT (shown when < 50%). Exactly 50% is hidden either way.
  • Both rules on — by default a post must pass all enabled rules (AND); switch to any (OR) in the sidebar.
  • The Filtering on checkbox fully disables the extension with one press. When off, the page is left completely untouched.

Posts stay hidden until judged (usually well under a second, slower under rate limits). Verdicts are cached by rule set + post text, so reposts and re-scrolls cost nothing. Image-only posts with no alt text are shown — there is nothing for Jev to judge.

Setup #

  1. Get a TypeSafe API key (https://typesafe.ai).
  2. Build: npx web-ext build → web-ext-artifacts/sux_jev_feed_filter-0.1.0.zip.
  3. Install (persists across restarts): quit the browser, copy the zip to <profile>/extensions/@sux.xpi, and put user_pref("xpinstall.signatures.required", false); in a user.js file in the profile dir (unsigned sideloads need it). Restart — Firefox registers the drop-in on startup.
  4. Open bsky.app, then the sux sidebar. If Firefox shows the Grant site access banner, click it (Firefox treats host permissions as opt-in) and reload bsky.app tabs.
  5. Paste your API key, press Test, enable a rule, flip Filtering on.

To update after code changes: rebuild the zip, copy it over @sux.xpi, restart.

Posts are read from the rendered feed DOM (permalink anchors + item text), not from network interception — bsky.app's API client uses a captured fetch reference that page-world wrappers cannot see, so DOM extraction is the reliable channel. A page-world interceptor still runs as a supplement.

Costs #

One Jev API call per unique post text per rule configuration. The sidebar shows judged / hidden / waiting counts and the last API error.

Notes & limitations #

  • The sidebar is styled with the Everforest dark palette by default and adopts your Firefox/Zen browser-theme colors automatically when the theme exposes them via the theme API (theme.js); it re-applies live when the theme changes.
  • The mapping from rendered feed items to posts uses Bluesky's permalink anchors (/profile/<author>/post/<rkey>), not CSS class names, but markup changes on bsky.app can still break it — if the feed stops filtering after an app update, this is the first place to look (content.js).
  • Quote-posts and reply-parents inside an item are not judged separately; the main post's verdict governs the whole item.
  • Only feed surfaces are intercepted: timeline, author feeds, custom feeds, search, and threads — not notifications.

Development #

node --test test/                        # unit tests (no key needed)
source typesafe_api_key.secret.sh && node scripts/live-check.mjs   # live API check
npx web-ext lint                         # manifest/API lint

Layout: shared.js (pure decision logic, unit-tested), interceptor.js (page-world fetch hook), background.js (queue + Jev client + cache), content.js (DOM), sidebar.* (settings UI).