Your feed algorithm should belong to you. Take it back in one sentence.
▶ Live demo · 繁體中文 · Product thesis
I used Threads to follow AI research. It was genuinely useful — and threaded through it, an endless drip of ragebait and brainrot. So I did the thing the product tells you to do. I tapped "I don't like this."
Then nothing happened. Or something did. I have no way to know. The same posts kept coming.
That is the part that actually bothers me. Not that the ranking is bad — that it is unfalsifiable. Billions of people hand feedback to a black box every day and not one of them can check the receipt. You cannot audit it. You cannot prove it ignored you. And you cannot walk away, because every alternative is built the same way.
Now scale that up. If one hidden dial decides what an entire society sees, then whoever holds the dial — a platform, an advertiser, a government — can turn it, and no user on earth can produce evidence that they did.
FeedKernel is the smallest working proof that feeds don't have to be built like this.
A feed you rewrite by talking to it.
Type: "keep strong disagreement, but cut the personal attacks and reward people who explain their reasoning."
FeedKernel shows you exactly which weights it is about to change, before it changes them. Then it reranks the same real posts and shows the actual arithmetic behind every result. Keep it, remix it, share it, roll it back.
Seven numbers. No model, no embeddings, no LLM call, nothing phoning home. The entire algorithm fits on one screen, and you own all of it.
- Pick a genuinely contested topic — AI in universities, free speech, climate policy.
- FeedKernel pulls up to 50 real public Bluesky posts. No login, no API key.
- Start from Raw engagement — the engagement-maximizing baseline, i.e. what you already live inside.
- Describe the change you want in one sentence, or grab a preset: Better debate, Evidence first, Fresh voices.
- Inspect the weight patch. Nothing has been applied yet. This is the receipt.
- Compare the top three, before and after.
- Open Why this? on any post to see every signal's real contribution to its score.
- Apply it, copy a link that imports the exact Recipe, or restore any earlier version.
Seven signals, deliberately few enough that a human can hold all of them in their head at once.
| Signal | Meaning | Ranking effect | Honest limitation |
|---|---|---|---|
| Likes | Public like count | Higher weight favors popular posts | Popularity is not quality |
| Replies | Public reply count | Preserves discussion and disagreement | Fighting also produces replies |
| Reposts | Public repost count | Rewards spread and shareability | Can reward the sensational |
| Recency | How new a post is | Higher weight favors current posts | Can bury older but important context |
| Account affinity | Relationship to the author | Neutral by default; "less from author" drops it instantly | No login or social graph yet |
| Conflict penalty | Attacks and high-conflict language | Higher weight subtracts more suspected ragebait | A text heuristic, not moderation |
| Evidence | Links, numbers, research terms, explanatory length | Higher weight favors sourced reasoning | A link does not guarantee truth |
score =
likes signal × likes weight
+ replies signal × replies weight
+ reposts signal × reposts weight
+ recency signal × recency weight
+ affinity signal × affinity weight
+ evidence signal × evidence weight
- conflict signal × conflict-penalty weight
Engagement counts are normalized within the current candidate set with log1p, then each signal is multiplied by its 0–100 weight.
"Why this?" prints the real contributions from that exact computation. It is not an AI-generated story about what the algorithm probably did — that would reproduce the original problem with better manners.
The compiler is deterministic intent rules. It recognizes increase/decrease language and negation for the supported signals, does not call an LLM, and never sends your sentence outside the browser.
| You say | The Recipe visibly does |
|---|---|
| "Reduce ragebait and personal attacks" | Raise conflict penalty, lower replies, raise evidence |
| "Keep debate and disagreement" | Raise replies |
| "More research, data, and reasoning" | Raise evidence |
| "Show popular and viral posts" | Raise likes and reposts |
| "Prioritize the newest posts" | Raise recency |
| "Show trusted and familiar accounts" | Raise affinity |
| "Give small accounts a chance" | Lower popularity and affinity, raise recency |
| "I don't want popular posts" | Lower likes and reposts instead of reversing the request |
This is not the final natural-language layer, and it is not trying to be. It exists to test the loop that matters: sentence → visible patch → ranking difference → you approve or reject. If that loop doesn't land, no amount of model quality saves it.
git clone https://github.com/poopro/FeedKernel.git
cd FeedKernel
npm ci
npm run devOpen http://localhost:3000. Node.js >=22.13.0. No .env, no API token.
Posts come from Bluesky's public app.bsky.feed.searchPosts through a server route that accepts only the four demo topics, times out slow upstream requests, merges top and latest, deduplicates, drops very short posts and explicitly labelled adult or graphic media, and returns at most 50 candidates with permalinks. If Bluesky or your network is unavailable, the UI falls back to a fixed dataset and labels every item Demo backup — it never passes backup content off as live.
npm run lint # ESLint
npm run typecheck # strict TypeScript
npm test # build + ranking, compiler, persistence, API, and HTML tests
npm run audit:prod # production dependency auditAnyone can claim transparency. Here is what this specifically is not:
- Not X's, Threads', or Bluesky's real recommender. "Engagement-heavy baseline" means likes, replies, reposts, and recency. It is not a reproduction of anyone's production system.
- Seven signals are not a theory of content quality. They are few on purpose, because a control you cannot understand is not a control.
- "Evidence" is a ranking heuristic, not fact-checking. "Conflict" is a risk signal, not moderation and not a political judgment. Both misclassify posts.
- No accounts, so affinity is mostly neutral. No login, no social graph, no cross-device tracking. Recipe history and account overrides live in your browser's
localStorage; a shared link contains only the seven visible weights. - Live public search results shift over time and can surface strong or offensive speech. This filter is not a trust-and-safety system.
- No formal user study yet. That this transparency is worth having is still a hypothesis — a testable one, which is more than the incumbents offer.
| Stage | Goal | Done when |
|---|---|---|
| Now | Prove people can follow intent → weights → ranking | A meaningful change made and explained in 60 seconds |
| Next | Small user study | People predict the direction of a change before applying it |
| Beta | Accounts, consented feedback history, cross-device sync | Versions replay safely across devices without daily tuning |
| Growth | Event streaming, offline eval, learned weights, more sources | Long-term satisfaction improves — not just clicks |
| Platform | Real social features, permitted platform integrations | Meets safety, privacy, scalability, and governance bars |
Deliberately not built yet: Kafka, model training, thousands of features, full behavioral histories, login, posting, DMs, official X/Threads integration, large-scale retrieval and online experimentation. None of that matters until the core interaction is proven.
Issues welcome — especially ranking controls that are easier to understand, additional signals that stay faithfully explainable, user-study designs, and safety or bias risks. Run npm run lint, npm run typecheck, npm test, and npm run audit:prod before submitting code.
Stack: React 19 · TypeScript · Next.js App Router · Vite · Cloudflare-compatible worker output
