What if the algorithm stopped hiding and started explaining itself?
Every day, social media algorithms decide what you see — and they never tell you why.
This project is a small act of rebellion: a browser extension + desktop agent (Clippy, naturally) that sits with you while you browse, watches what the algorithm shows you, tells you the truth — and then clicks "Not interested" on your behalf.
- Watches your feed — YouTube, X/Twitter, Facebook, Instagram, TikTok, LinkedIn, Reddit, Threads
- Classifies every post into one of 9 categories (politics, sports, tech, etc.)
- Asks you with floating 👍/👎 buttons: "Are you interested in this?"
- Learns your preferences and adjusts its weight per category
- Acts — when you press 👎, Clippy automatically clicks "Not interested" / "Hide post" for real
- Auto-dismisses posts from categories you consistently dislike (configurable threshold)
- Shows you exactly what it learned — dismissed count, category weights, sentiment badges
| Feature | Status |
|---|---|
| Feed observer (YouTube, X, Facebook, Instagram, TikTok) | ✅ Working |
| 9-category brain classifier | ✅ Working |
| Clippy desktop agent (Electron) | ✅ Working |
| Clippy Chrome extension | ✅ Working |
| Floating 👍/👎 feedback buttons | ✅ Working |
| Action Engine — clicks "Not interested" | ✅ Working |
| Dismiss counter (persisted, shown in popup) | ✅ Working |
| Popup with 5 tabs (overview/categories/history/insights/settings) | ✅ Working |
| Settings tab — auto-dismiss toggle | ✅ Working |
| Weight badges per category (❤️/😐/😒/🚫) | ✅ Working |
| Chrome extension icons | ✅ Present |
| Landing page | ✅ Working |
| AI-powered dialogue layer (click Clippy to chat) | ✅ Working |
| TikTok action adapter | ✅ Working |
| YouTube InnerTube API integration | ✅ Working |
| LinkedIn action adapter | ✅ Working (verified live 2026-07-28, fixed 2 broken selectors) |
| Reddit action adapter | |
| Threads action adapter | |
| Web text analyzer (9 categories, Hebrew/EN/RU) | ✅ Working |
| 37 unit tests (brain, classifier, state, questions) | ✅ Passing |
teshuva-algorithm/
├── brain/ # Core intelligence
│ ├── brain-api.js # Public API: observe, positive, negative, recordDismiss, getStats
│ ├── categories.js # 9 categories with Hebrew labels + colors
│ ├── classifier.js # Keyword-based text classification
│ ├── state.js # Persisted weights, allTime, dismissed counters
│ ├── questions.js # When + how to ask the user
│ ├── intent.js # "Why are you seeing this?" explanations
│ ├── explanations.js # Human-readable summaries
│ └── adapters/
│ ├── chrome-adapter.js # chrome.storage.local
│ ├── electron-adapter.js # In-memory store (desktop, via IPC)
│ └── react-native-adapter.js # AsyncStorage (mobile)
│
├── mascot/
│ ├── mascot-controller.js # Brain ↔ Mascot ↔ User bridge
│ └── animations.js # Mood → Clippy animation mapping
│
├── extension/
│ ├── manifest.json # MV3, host permissions for 5 platforms
│ ├── content/
│ │ ├── bundle-entry.js # Content script entry + wiring
│ │ ├── bundle.js # Built bundle (esbuild output)
│ │ ├── action-engine.js # Platform "Not interested" click logic
│ │ ├── feedback-ui.js # Floating 👍/👎 buttons
│ │ ├── feed-observer.js # MutationObserver for new posts
│ │ └── site-adapters.js # CSS selectors per platform
│ ├── popup/
│ │ ├── popup.html # 5-tab popup UI
│ │ ├── popup-entry.js # Popup logic
│ │ └── popup.js # Built bundle
│ ├── background-entry.js # Service worker: storage + settings relay
│ └── api.js # Content ↔ Background message protocol
│
├── desktop/
│ ├── main.js # Electron window (340×340, always-on-top)
│ └── renderer-entry.js # Desktop Clippy logic + IPC
│
├── shared/
│ └── constants.js # Storage keys, message types, timing
│
├── agent/
│ └── dialogue.js # Conversational AI stub
│
├── mobile/ # React Native app (Android + iOS, sideload-only)
│ ├── src/ # Screens, mascot, services (brain runs on-device)
│ └── android/ # FloatingService.java (overlay), FeedWatcherService.kt
│ # (AccessibilityService feed monitoring)
│
├── web/ # Landing page & marketing site (Netlify)
│ ├── index.html # Main landing page (HE/EN/RU, dark/light)
│ ├── features.html # Features page
│ ├── pricing.html # Pricing page
│ ├── faq.html # FAQ page
│ ├── support.html # Support page
│ └── downloads/ # Extension zip for manual install
└── package.json
When the user presses 👎 or when the brain weight drops below 0.4 (configurable), Clippy automatically:
| Platform | Action | DOM Strategy |
|---|---|---|
| YouTube | "Not interested" | Hover reveal → ytd-menu-renderer → option click |
| X / Twitter | "Not interested in this post" | [data-testid="caret"] → menu item |
| "Hide post" | [aria-label="More options"] → menu item |
|
| "Not interested" | Three-dot button → dialog button | |
| TikTok | "Not interested" | Direct button (newer layouts) → overflow menu fallback |
| "Not interested" / unfollow / hide | Control menu → option click (verified live 2026-07-28) | |
| "Not interested" / hide / block | Overflow menu → option click (best-effort — Reddit blocks automated verification) | |
| Threads | "Not interested" / hide / mute | More menu → option click (best-effort — only verified logged-out) |
import { createBrain } from './brain/brain-api.js'
import { createChromeAdapter } from './brain/adapters/chrome-adapter.js'
const brain = createBrain(createChromeAdapter())
await brain.load()
const categoryId = brain.observe('פוסט על פוליטיקה...') // → 'politics'
brain.positive('politics') // user liked it → weight +0.15
brain.negative('politics') // user disliked → weight -0.08
brain.recordDismiss('politics') // post was actually removed from feed
const { allTime, weights, dismissed, dismissedTotal } = brain.getStats()
// weights.politics < 0.4 → auto-dismiss threshold crossed- Run
npm install && npm run build - Open
chrome://extensions/ - Enable Developer mode
- Click Load unpacked → select the
extension/folder - Navigate to YouTube, X, Facebook, or Instagram
- Clippy appears bottom-right
npm install
npm start
# Or double-click: "הפעל קליפי.bat"| Tab | Content |
|---|---|
| סקירה | Visits, social, dismissed banner |
| קטגוריות | Category bars with ❤️/😐/😒/🚫 badges |
| היסטוריה | Hour-of-day chart, top domains |
| תובנות | Weekly insights |
| ⚙️ הגדרות | Auto-dismiss toggle, reset preferences |
Shipped:
- ✅ Improved YouTube selector (InnerTube API)
- ✅ TikTok action adapter
- ✅ AI dialogue via Claude API (ask Clippy "why?")
- ✅ Landing page in Hebrew/English/Russian — the extension popup itself is still Hebrew-only
- ✅ Mobile app (React Native, Android) — on-device brain, a real floating Clippy bubble over other apps, and real feed monitoring on Instagram/TikTok/Twitter. Sideload-only, not on Google Play (Accessibility API policy risk — see
CLAUDE.md)
Open:
- Real-device verification of mobile feed monitoring against live Instagram/TikTok/Twitter (so far only tested on a Play-Store-less emulator)
- Threads action-engine needs real-browser testing with a logged-in account (Reddit can't be tested this way at all — see Known Gaps)
- Category blocklist, export preferences, full multi-language extension popup — not started
- Decision pending: publish
mobile/to Google Play with the feed-monitoring service disabled
"האלגוריתם הזה לא מסתיר כלום ממך"
MIT License · GitHub


