A Chrome extension that uses an LLM to triage your open tabs into intent-based groups ("Active work", "Reference / docs", "Shopping", etc.) so you can close, focus, or natively group them in Chrome in bulk. Lives in the side panel — open it from the extension icon.
Install from the Chrome Web Store →
Day 25 of a 50-day portfolio challenge.
- The side panel queries
chrome.tabs.query({})across every window. - Titles + URLs (no page contents) are sent to Claude Haiku with a triage system prompt.
- The model returns JSON groups; orphans get folded into "Uncategorized".
- You can close a group, focus a tab, or push the group into a native Chrome tab group.
Internal pages (chrome://, chrome-extension://, devtools://, etc.) are filtered out before the model ever sees them — they're noise you can't act on from here.
The hosted install talks to my own MagicLink worker, which proxies Claude with a small per-visitor daily quota (tracked by hashed IP, no account). It's a portfolio demo, not a production service. If you hit the cap, fork and run your own.
Two paths depending on how much glue you want to wire up.
Cheapest path: skip MagicLink entirely and call your provider of choice straight from the extension.
- Fork this repo.
- Replace
src/lib/magiclink.tswith a thin client for your provider. The public surface only needscallClaude(request) -> { response, usage }and aQuotaExhaustedErrorclass. Anything that hits a chat-completion API and returns text will work — Anthropic, OpenAI, Gemini, local llama.cpp, whatever. - Add your provider's domain to
host_permissionsinpublic/manifest.json. - Store your API key with
chrome.storage.local(re-add thestoragepermission first) or hardcode for a single-user build. Don't commit keys. npm run build, then loaddist/as an unpacked extension.
The triage prompt lives in src/lib/triage.ts. Tweak the labels, the group-size rules, or swap models there.
Use this if you want the same quota / hashed-IP pattern for someone else who'll be using your fork.
- Fork magiclink and deploy it to Cloudflare Workers with your own Anthropic key in the secrets.
- Change
MAGICLINK_BASEinsrc/lib/magiclink.tsto your worker URL. - Change
PROJECT_IDif you want a separate quota bucket. - Update
host_permissionsin the manifest to your worker's domain. - Build and load as above.
npm install
npm run build # one-shot build → dist/
npm run dev # watch mode
node scripts/gen-icons.mjs # regenerate PNG icons from icon.svg
Load dist/ as an unpacked extension at chrome://extensions (toggle Developer mode on).
Quick way to populate a fresh Chrome window with a varied mix of tabs (including a few duplicates) for testing the triage and the duplicates panel:
./scripts/open-test-tabs.sh
- Manifest V3, side panel API, native tab groups
- React 19 + TypeScript + Vite + Tailwind v4
- Claude Haiku 4.5 for triage
- MagicLink (Cloudflare Worker) as the auth-less AI proxy
| Permission | Used for |
|---|---|
sidePanel |
Open the triage UI in Chrome's side panel |
tabs |
Read titles + URLs across all windows, focus tabs, close tabs |
tabGroups |
Push a triage group into a native Chrome tab group |
host_permissions: magiclink.reneebe.workers.dev |
Send tab titles/URLs to the AI proxy |
No content scripts, no page-content access, no storage, no remote code.