Your algorithm, across platforms.
Browser extension that intercepts your social media feeds, scores content against your personal ML preference model, and reranks in real-time. The model learns from your behavior on every platform you use.
Status: Archived proof-of-concept. Works on Twitter/X but is not actively maintained. The architecture is designed to support any platform — adding a new one is just writing an adapter.
cd server
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# First run downloads ~90MB sentence-transformer model
uvicorn app.main:app --reload --port 8000Verify: http://localhost:8000/health → {"status": "ok"}
cd extension
npm install
npm run build- Go to
chrome://extensions - Enable "Developer mode" (top right)
- Click "Load unpacked"
- Select the
extension/dist/directory
- Navigate to https://x.com
- Open DevTools console (F12)
- You should see:
[OmniFeed] API hooks installed
[OmniFeed] Bridge initialized for twitter
[OmniFeed] Feed observer attached
- Scroll your feed — as tweets load:
[OmniFeed] Extracted 25 items from twitter
[OmniFeed] Scored 25 items in 47ms
[OmniFeed] Reranked 22 tweets
- Popup: Click the OmniFeed extension icon → shows server status + interaction count
- Stats: http://localhost:8000/api/v1/user/dev_user/stats
- Training log: http://localhost:8000/api/v1/debug/training-log
- Cache: http://localhost:8000/api/v1/debug/embedding-cache
x.com (or any supported platform)
│
│ Twitter GraphQL API response lands in browser
│
▼
loader.ts (MAIN world)
│ Patches XHR/fetch, captures timeline responses
│ Fires CustomEvent with raw JSON
│
▼
bridge.ts (Isolated world)
│ Receives event, runs Twitter adapter
│ Adapter extracts tweets → CanonicalItem[]
│ Processor converts → WireItem[] (with author hash, bucketed metrics)
│ Sends to server for scoring
│
▼
Server (FastAPI, localhost:8000)
│ Embeds text via sentence-transformers (384-dim)
│ Scores against user's preference vectors:
│ core + temporal(time-of-day) + platform + author_affinity + type + freshness
│ Returns ranked scores
│
▼
bridge.ts
│ Receives scores, calls adapter.reorderDom()
│ Tweets physically reorder in the DOM
│
▼
Tracker (IntersectionObserver + click delegation)
│ Monitors dwell time, likes, replies, shares
│ Every 15s, flushes interaction signals to server
│
▼
Server: PreferenceEngine.update()
│ Computes reward from signals (relative to user's baseline)
│ Nudges preference vectors toward engaged content
│ Logs full training record for future model improvements
- Create
extension/src/content/adapters/{platform}.ts - Implement the
PlatformAdapterinterface (seeshared/types.ts) - Map platform-specific fields →
CanonicalItem(same shape for everyone) - Add URL patterns to
loader.ts - Add host permissions to
manifest.json - Register adapter in
bridge.ts
Everything downstream (processor, server, ML) works unchanged.
omnifeed/
├── extension/
│ ├── manifest.json # Chrome Manifest V3
│ ├── package.json # Vite + CRXJS
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── src/
│ ├── content/
│ │ ├── loader.ts # MAIN world: XHR/fetch interception
│ │ ├── bridge.ts # Orchestration: adapter → server → rerank
│ │ ├── adapters/
│ │ │ └── twitter.ts # Twitter/X GraphQL → CanonicalItem
│ │ └── core/
│ │ ├── processor.ts # CanonicalItem → WireItem
│ │ └── tracker.ts # Dwell + interaction tracking
│ ├── shared/
│ │ └── types.ts # All types + PlatformAdapter interface
│ ├── popup/
│ │ └── index.html # Extension popup
│ └── background/
│ └── index.ts # Service worker (minimal)
└── server/
├── requirements.txt
└── app/
└── main.py # FastAPI + Embedder + PreferenceEngine
MIT