Pure-reference catalog of the Manifest V3 test surface for Firefox + Chromium browser extensions. Maps each manifest field that changed from MV2 (manifest_version, background.service_worker vs background.scripts, action vs browser_action / page_action, host_permissions split, web_accessible_resources object-form, content_security_policy object-form), the runtime restrictions service workers impose (no DOM, no XMLHttpRequest, no localStorage, ephemeral lifecycle, synchronous listener registration, alarms instead of setTimeout), and the Firefox-vs-Chrome key matrix (browser_specific_settings.gecko, externally_connectable / offline_enabled gaps, MV2-only user_scripts manifest key); references/ carry Mozilla's web-ext CLI (lint via addons-linter, run on firefox-desktop / firefox-android / chromium targets, deterministic build, AMO sign). Use as the manifest-surface reference when authoring extension tests across both browsers, or when driving Firefox runs / AMO signing with web-ext.
69
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Companion reference for manifest-v3-test-surface-reference. Consult when
the extension targets Firefox (signing is mandatory for distribution) or when
cross-browser test runs need a single CLI that drives both Firefox and
Chromium against the same source tree.
web-ext is Mozilla's reference CLI for WebExtension development. Per the
mozilla/web-ext README it bundles run, lint, sign,
build, and docs; v8 added dump-config and reworked signing to use the
AMO submission API by default (per the web-ext command reference).
--source-dir / -s is a global option; --artifacts-dir (default
./web-ext-artifacts) controls where build / sign write zips.
npm install --save-dev web-ext # per-project, preferred for CI determinismMozilla recommends the current Node LTS (per we-readme). A
web-ext-config.cjs file pins flags per run; web-ext dump-config (v8, per
we-cmd) prints the resolved configuration as JSON for diffing.
web-ext lint wraps mozilla/addons-linter and emits
AMO-compatible warnings. CI-friendly invocation:
web-ext lint \
--source-dir ./dist \
--output json \
--pretty \
--warnings-as-errors > lint-report.json--warnings-as-errors / -w is the right CI default - per we-cmd it
escalates lint warnings (unsupported manifest fields, MV2-only APIs flagged
for MV3) into a non-zero exit code. Other flags: --metadata,
--self-hosted (disables AMO-related messages - never on AMO-bound builds),
--boring.
Output shape: { "count", "summary": { "errors", "notices", "warnings" }, "metadata", "errors": [{ "code", "message", "file", "line", "column" }], ... }
(per addons-linter; spot-check its changelog before pinning a parser). Parse
with jq '.summary.errors + .summary.warnings'.
web-ext run builds the extension, installs it into a fresh temporary
Firefox profile, then watches the source directory and reloads on edit (per
we-cmd):
web-ext run \
--source-dir ./dist \
--firefox=firefox \
--start-url 'about:debugging#/runtime/this-firefox'--firefox aliases (per we-cmd): firefox, beta, nightly,
deved / firefoxdeveloperedition, or a binary path. To pin a profile:
--firefox-profile=qa-profile --profile-create-if-missing --keep-profile-changes (the last persists profile modifications across
runs per we-cmd).
Targets (per we-cmd --target): firefox-desktop, firefox-android
(wired via the --adb-* flag family), and chromium:
web-ext run --source-dir ./dist --target chromium --chromium-binary "$(which chromium)"The chromium target is the lowest-effort parity smoke-test; deep Chromium
test surface lives in playwright-extension-fixtures.
web-ext build -s ./dist -a ./build/artifacts --overwrite-dest \
--filename 'my-extension-{version}.zip'Per we-cmd, --filename defaults to {name}-{version}.zip;
--overwrite-dest is required when the artefact path already exists. Build
runs lint first and exits non-zero on lint failure.
Per we-cmd, web-ext sign v8 uses the AMO submission API by default and
--channel is required:
export WEB_EXT_API_KEY='user:12345:1'
export WEB_EXT_API_SECRET='abcdef...'
web-ext sign -s ./dist --channel listed \
--amo-metadata ./amo-metadata.json \
--upload-source-code ./source.tar.gzChannel semantics (quoted from we-cmd): with listed the extension "gets
submitted for public listing"; with unlisted it "gets submitted for signing
for self-distribution." Key flags: --api-key / --api-secret (JWT for the
AMO API), --amo-metadata (required for a first listed version),
--timeout (default 300000 ms), --approval-timeout (default 900000 ms,
v8) - AMO can take longer in queue, requiring follow-up polling. Update
submissions require an extension ID in the manifest
(browser_specific_settings.gecko.id) per we-cmd. The signed .xpi lands
in --artifacts-dir.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
web-ext sign without --channel | v8 requires it per we-cmd; command refuses to run | Always specify listed or unlisted |
Re-using a profile without --keep-profile-changes | Profile changes lost between runs; tests appear non-deterministic | Add the flag per we-cmd |
web-ext lint without -w in CI | Warnings silently pass; AMO submission still rejects | --warnings-as-errors |
| Signing without an extension ID in the manifest | Update submission fails per we-cmd | Add browser_specific_settings.gecko.id (see SKILL.md matrix) |
Committing web-ext-artifacts/ | Repo bloats with binaries | .gitignore + CI artefact upload |
web-ext lint catches manifest issues and AMO
policy violations; it does not exercise behaviour - pair with
playwright-extension-fixtures.web-ext lint does not warn when a key
is MV3-supported in Chrome but not Firefox (or vice versa);
cross-reference the SKILL.md matrix manually.web-ext README - we-readme.web-ext v8 command reference (every flag on every
subcommand) - we-cmd.addons-linter (what web-ext lint wraps) -
https://github.com/mozilla/addons-linter