
# [Extension Name]

A Manifest V3 browser extension. Popup, options page, content script, background worker. TypeScript end to end.

## Source of truth
GitHub. Versioned zips uploaded to Chrome Web Store via `web-ext sign` (also works for Firefox). The current store version is the source of truth for what users have.

## Tech stack
Vite 6 (with `@crxjs/vite-plugin` for MV3 HMR) + TypeScript + React 19 (for the popup + options pages). Tailwind v4. Manifest V3. Storage via `chrome.storage.local`. Cross-browser polyfilled via `webextension-polyfill`.

## Deploy
1. `npm run build` -> outputs to `dist/`
2. `cd dist && zip -r ../extension.zip .`
3. Upload to Chrome Web Store Developer Dashboard
4. (Optional) `web-ext sign --api-key=$AMO_KEY --api-secret=$AMO_SECRET` for Firefox AMO

## File map
- `src/manifest.ts` declarative manifest (compiled to JSON by crxjs)
- `src/background.ts` MV3 service worker (event-driven, NOT persistent)
- `src/content/` content scripts injected per-site
- `src/popup/` React popup
- `src/options/` React options page
- `src/lib/storage.ts` typed `chrome.storage` wrapper
- `src/lib/messaging.ts` content <-> background message types
- `vite.config.ts` with `@crxjs/vite-plugin`
- `public/icons/` 16/32/48/128 PNG icons

## .env keys
None at runtime (MV3 has no env injection). Build-time variables can be passed via Vite `define`.

## Hard rules
- MV3 background is a service worker. It can be killed at any time. Persist anything via `chrome.storage`, not module-level variables.
- Content scripts run in an isolated world. They cannot read the page's JS scope without injecting a script tag.
- `host_permissions` should be the minimum needed. Users see them at install. Asking for "all sites" tanks adoption.
- All cross-context messaging is typed via `src/lib/messaging.ts`. No raw `chrome.runtime.sendMessage` calls.
- Store icons must be 16x16, 32x32, 48x48, 128x128 PNG. Inkscape -> PNG export.
- Privacy policy URL required for any extension that handles user data.

## Recent significant changes
- 2026-05-02: Scaffolded. Locked: Vite + crxjs (HMR matters), React for popup (consistency with rest of stack), webextension-polyfill for Firefox parity.

## Next session: start here
1. Edit `src/manifest.ts` name, description, host_permissions.
2. Generate icons (Figma export or `realfavicongenerator.net` adapted).
3. `npm run dev` -> Vite watches, crxjs hot-reloads the unpacked extension.
4. Load `dist/` as unpacked extension at `chrome://extensions`.
5. Test on real sites before submitting to store.
