# Browser Extensions

> Use when building or shipping a browser extension as a fourth kind of client. Cross-browser MV3 baseline, web-to-extension session handoff, isolated worlds and the service worker, per-site adapters, packaging one source for N environments in CI, store submission, self-distribution with release channels, and why there is no mobile extension.

- Skill: `konradcinkusz/browser-extensions` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add konradcinkusz/browser-extensions`
- Raw SKILL.md: https://api.skillmd.com/api/skills/konradcinkusz/browser-extensions/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: konradcinkusz (https://skillmd.com/u/konradcinkusz)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/konradcinkusz/browser-extensions

---


# Browser extensions: build, session handoff, packaging, stores

**Read [`references/BROWSER-EXTENSIONS.md`](references/BROWSER-EXTENSIONS.md) before applying any of this.**
That file is the standard; everything below it is a summary to help you decide
whether this skill applies and to check your work afterwards.

## What this standard covers

- Cross-browser baseline
- Session handoff
- Isolated worlds and the service worker
- Per-site adapters
- Packaging: one source, N environments
- Store submission
- Distributing builds yourself
- Mobile: there is no mobile extension

## Failure modes

| Symptom | Cause |
|---|---|
| Session handoff works in Chrome, silently fails in Firefox | No content-script fallback; Firefox lacks `externally_connectable` |
| Token expiry nonsense after idle | Stored relative `expiresIn` instead of an absolute timestamp |
| Page never sees the extension's result | Isolated-world write to `window`; use DOM dataset + re-fired CustomEvent |
| First message after idle returns `undefined` | Service worker asleep; retry with delay |
| Extension works for the dev, not for users | Production zip carries dev config, or store build points at localhost hosts |
| Reviewer rejects over permissions | Localhost entries left in `host_permissions`, or broad permissions without written justification |
| Published extension's API calls fail | Extension id never added to backend CORS allowlist |
| One site's integration silently breaks | Third-party DOM changed; no selector fallback, no manual smoke pass |
| "Which version are you on?" unanswerable | No version echo header on the distribution endpoint |

## Checklist

- [ ] API shim at the top of every script; one manifest with the `gecko` block
- [ ] Both handoff paths (external message + content-script fallback); payload validated; absolute expiry in `storage.local`
- [ ] Runtime sender-origin allowlist redundant with the manifest
- [ ] Isolated-world signaling via DOM dataset + re-fired CustomEvent; service-worker wake-up retry
- [ ] Site integrations as adapter tables with ordered selector fallbacks
- [ ] CI writes config + patches manifest (hosts, version from tag); localhost-permission removal decided and recorded
- [ ] Store assets/policy prepared to spec; privacy policy covers extension data; permissions justified in writing
- [ ] Post-approval loop: extension id → store URL variable → backend CORS allowlist
- [ ] Publication automated from CI
- [ ] Self-distribution: semver blobs, channel ladder, PR-label pinning, version echo header, empty-zip degradation
- [ ] Mobile requests answered with a feasibility study, not a mobile extension

---

Generated from [`docs/guides/BROWSER-EXTENSIONS.md`](https://github.com/konradcinkusz/architecture-standards/blob/main/docs/guides/BROWSER-EXTENSIONS.md) by `scripts/build-marketplace.mjs`. Do not edit this file: change the source document, or its entry in `catalog/marketplace.catalog.json`, and re-run the generator.

