TabCrew: review Chrome tab groups before applying
TabCrew turns open Chrome tabs into an editable group plan. The user reviews every move before a fresh snapshot check allows Chrome to change.
Open live product01Context
Problem
Chrome's native tab groups can make a crowded browser readable, but creating and naming them by hand is slow. A model can propose the first arrangement, but its output must not change Chrome directly or require a reusable provider key inside the extension.
Constraints
- A Chrome extension distributed to users cannot keep a permanent provider secret from a determined caller.
- Tab titles and URL paths can expose work context even when page contents are never read.
- Tabs can open, close, move between windows, or change title or URL while the provider runs or the user reviews a plan.
- Valid JSON can still omit, repeat, or invent tab assignments.
02System
Review before Apply
- Read
The service worker takes a snapshot of open tabs. Chrome and extension pages are excluded. Other non-HTTP(S) tabs stay local in a Needs Review group.
- Plan
The extension sends minimized HTTP(S) tab fields and browser locale. The gateway owns the fixed instruction, configured model, response shape, and request limits.
- Review
The board lets the user move tabs, rename groups, and choose Chrome colors. Saving an edited plan rechecks complete coverage and the live snapshot.
- Apply
Apply re-reads the tab set and compares each tab's ID, window, title, and minimized URL with the reviewed plan. Only a full match reaches Chrome's grouping APIs.
Architecture
Manifest V3 popup and organizer board
Service worker for tab snapshots and Chrome mutations
IndexedDB-backed, non-extractable P-256 installation key
Turnstile activation page and one-time code exchange
Node.js capability gateway with built-in HTTP and SQLite
Server-owned OpenRouter request and strict plan validator
Reference mapping, editable review board, and fresh snapshot gate
Extension-to-gateway trust boundary
- The extension holds no provider key. The gateway exposes a tab-plan endpoint, not a generic chat proxy; extra prompt, model, or tool fields are rejected before provider work.
- Each stored installation private key is non-extractable. The activation callback must match the exact gateway origin, pending random state, and activation tab before the one-time code is exchanged.
- Later requests combine a short-lived token scoped to tab planning with an ECDSA signature over the method, path, body hash, timestamp, and nonce. Reusing a nonce is rejected.
- Origin checks reduce browser misuse but are not authentication. A public activation protocol can be reproduced, so per-installation, network, and global limits plus one active plan per installation bound abuse without claiming official-extension proof.
Data sent for a plan
- The configured provider receives the fixed TabCrew instruction, browser interface locale, and each eligible tab's Chrome title plus URL scheme, host, and path.
- The extension removes query strings and fragments, length-limits titles and URLs, and replaces Chrome tab IDs with sequential references before the request.
- Page contents, DOM data, cookies, local files, data URLs, Chrome pages, and extension pages do not enter the provider request. Other non-HTTP(S) tabs remain local.
- This is a smaller data boundary, not a privacy guarantee. Titles and paths can still identify work, and the provider must read them to propose a plan. The product site carries the current retention terms.
My role
Designed and built the Manifest V3 extension, review and Apply flow, activation and signed-request protocol, Node.js and SQLite gateway, validation and abuse controls, release packager, product site, and automated and live checks.
Decisions
- Kept proposal and mutation as separate operations. Only a current plan in an applyable mode can reach Apply, and an applied plan is consumed.
- Sent sequential references from 1 to N instead of raw Chrome tab IDs. The extension maps accepted references back to live tabs after complete-coverage validation.
- Kept the instruction, provider model, tools, response shape, and limits on the gateway. The browser can request one plan but cannot turn the service into a general model proxy.
- Built the release from an explicit file allowlist. The published package removes native messaging and forces the managed gateway route, while the unpacked development build can still use the local .NET router.
03Validation
Failures and fixes
- The first hosted activation used Chrome's OAuth-oriented Identity redirect flow. It was removed in favor of a normal gateway tab whose one-time result is bound to origin, random state, and tab ID.
- The activation page initially used a no-referrer policy. In the tested Chrome activation path, the same-origin form POST then arrived with Origin set to null, so the gateway rejected it. A same-origin referrer policy preserved the real Origin without allowing cross-origin referrers.
- The extension initially woke the organizer before closing the completed activation tab. That page could enter the new tab snapshot. Closing it before resuming the organizer removed it from the plan input.
- One signed 72-tab synthetic request to the private-test gateway produced an invalid provider plan; the identical later request completed. The validator rejected the first response before review or Apply. Two requests show failure containment, not grouping quality or model reliability.
Tests and checks
- At source commit a98b3ce, Node.js 24.19.0 passed 28 tests. They cover the fixed request and response contracts, origin-state-tab callback binding, one-time code exchange, nonce replay rejection, the per-installation quota, Turnstile checks, complete assignment coverage, and provider error classification.
- Source inspection confirms that edited plans must cover the original tab set and that Apply compares the complete live snapshot before calling Chrome. Those service-worker paths are not currently isolated in automated tests.
- The release packager copies an explicit allowlist and fails if the published manifest retains native messaging or Identity, accepts the wrong activation origin, or can fall back to development mode.
- The private-test handoff records an accepted 72-tab retry with every tab assigned once. It does not measure usefulness against a labelled dataset or repeated-run reliability.
04Outcome
Result
The private beta can activate an installation, request one managed tab-group plan, let the user correct every assignment, and apply native Chrome groups only after explicit confirmation and a fresh snapshot match. The model has no direct path to Chrome's tab APIs.
Limits
- TabCrew is a private beta. The product page is live, but the extension is not yet published in the Chrome Web Store.
- The public activation and signing protocol limits abuse but cannot prove that every caller is the official extension. Stronger identity would require user authentication or platform attestation.
- The configured provider sees tab titles and sanitized paths, and the current private beta does not require OpenRouter's zero-data-retention route. The privacy policy, OpenRouter settings, and downstream provider policy still matter.
- There is no labelled grouping-quality dataset or user study. The 72-tab integration check must not be read as a quality benchmark.
- The managed gateway uses SQLite and one replica. It is not a multi-replica or high-availability design. A deterministic offline grouping option remains available when no provider request is wanted.
What I would change today
Extract the snapshot validator from the service worker so it can be tested without Chrome, add one bounded retry only for an invalid provider plan, and move gateway state to PostgreSQL before running more than one replica.