Skip to content

ReneeBe/tab-sweep

Repository files navigation

TabSweep

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.

How it works

  1. The side panel queries chrome.tabs.query({}) across every window.
  2. Titles + URLs (no page contents) are sent to Claude Haiku with a triage system prompt.
  3. The model returns JSON groups; orphans get folded into "Uncategorized".
  4. 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.

Hosted demo — quota

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.

Run your own (no quota)

Two paths depending on how much glue you want to wire up.

Option A — point at your own AI directly

Cheapest path: skip MagicLink entirely and call your provider of choice straight from the extension.

  1. Fork this repo.
  2. Replace src/lib/magiclink.ts with a thin client for your provider. The public surface only needs callClaude(request) -> { response, usage } and a QuotaExhaustedError class. Anything that hits a chat-completion API and returns text will work — Anthropic, OpenAI, Gemini, local llama.cpp, whatever.
  3. Add your provider's domain to host_permissions in public/manifest.json.
  4. Store your API key with chrome.storage.local (re-add the storage permission first) or hardcode for a single-user build. Don't commit keys.
  5. npm run build, then load dist/ as an unpacked extension.

The triage prompt lives in src/lib/triage.ts. Tweak the labels, the group-size rules, or swap models there.

Option B — run your own MagicLink

Use this if you want the same quota / hashed-IP pattern for someone else who'll be using your fork.

  1. Fork magiclink and deploy it to Cloudflare Workers with your own Anthropic key in the secrets.
  2. Change MAGICLINK_BASE in src/lib/magiclink.ts to your worker URL.
  3. Change PROJECT_ID if you want a separate quota bucket.
  4. Update host_permissions in the manifest to your worker's domain.
  5. Build and load as above.

Local development

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).

Test data

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

Stack

  • 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

Permissions, and why

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.

About

A Chrome side-panel extension that uses Claude to triage your open tabs into intent-based groups.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors