Skip to content
Browser extensions

Chrome extension (Manifest V3)

Manifest V3 rules for service workers, messaging and minimal permissions, plus a skill that gets your extension through Chrome Web Store review.

Verified install Not agent-tested v1.0.0 MIT updated chromejavascripttypescript
Equips
  • 2 2 Rules
  • 1 1 Skills
  • – 0 MCP

Agents trained on years of Manifest V2 tutorials will happily write background pages, remote code and "<all_urls>" permissions — all of which either break in Manifest V3 or get you rejected from the Chrome Web Store. This loadout keeps your agent on MV3, keeps permissions tight, and walks through store submission so the review goes smoothly first time.

What's in it

  • Service worker lifecycle rules (no global state, use chrome.storage and alarms)
  • Least-privilege permissions with activeTab and optional host permissions
  • Clear message-passing pattern between content scripts, popup and service worker
  • Store-prep skill: permission justifications, privacy disclosures, zip packaging

You'll need

  • Tools: node, chrome
Level 1 · automated

Verification

Verified install

Checked at commit ad36e85 · 9 passed, 0 failed, 1 not applicable

CheckResultWhat we found
Listinglisting.yaml matches the schema and declares every file in the folder. Pass
Schema valid; 5 files declared, none missing or extra
  • tested.status: untested (agent tests are separate from Level 1)
Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. Pass All 5 files parse; front matter valid
AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. Pass
CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
  • CLAUDE.md: matches the generator
  • GEMINI.md: matches the generator
Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. Pass
Correct paths for all 5 agents; layouts re-discovered
  • Claude Code: 3 files, 1 skill in .claude/skills/
  • Codex CLI: 2 files, 1 skill in .agents/skills/
  • Cursor: 3 files, 1 skill in .agents/skills/, 1 rule
  • Gemini CLI: 3 files, 1 skill in .agents/skills/
  • GitHub Copilot: 2 files, 1 skill in .agents/skills/
MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. Not applicable No MCP servers in this loadout
Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. Pass
Clean: no credentials, risky shell or hidden text
  • Scanner intake-precheck/1: verdict clean; network no (listing says no)
ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. Pass No cross-file references to check
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
5 files, 7.0 KB total; largest AGENTS.md 3.2 KB
  • Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule
LicenceA recognised SPDX licence, with the licence text available. Pass MIT, by Agent Loadout; text in the repository LICENSE
Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. Pass
Manifest V3 extension in the loadout's layout type-checks against @types/chrome, builds, and passes the loadout's manifest and remote-code rules
  • Applied 6 loadout files at every agent's paths
  • ✓ install: npm ci --no-audit --no-fund
  • ✓ type-check and build: npm run build
  • ✓ manifest and package rules: node check-manifest.mjs
  • Covers: Service worker with top-level listeners, state in chrome.storage, typed and validated messages, async sendResponse (AGENTS.md)
  • Covers: Manifest rules from the Cursor rule: MV3, action, module service worker, permissions justified in PERMISSIONS.md, description ≤132 chars
  • Covers: No eval, new Function or remote scripts in the built package
  • Covers: Not covered: loading the extension in Chrome (branded Chrome no longer accepts --load-extension in CI)

What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.

Install

Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.

Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.

Download zip
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/chrome-extension-mv3/1.0.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/chrome-extension-mv3/1.0.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/extension-store-prep/SKILL.md https://loadout.jnw-it.com/raw/chrome-extension-mv3/1.0.0/skills/extension-store-prep/SKILL.md
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/extension-store-prep/SKILL.md.claude/skills/extension-store-prep/SKILL.md

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.

Files

Rules AGENTS.md Manifest V3 extension project rules. 51 lines
Download Raw
# AGENTS.md: Chrome extension (Manifest V3)

## Ground rules
- This is a **Manifest V3** extension (`"manifest_version": 3`). Do not use MV2 APIs: no `background.page`,
  no `background.persistent`, no `chrome.browserAction`/`pageAction` (use `chrome.action`), no blocking `webRequest` (use `declarativeNetRequest`).
- **No remotely hosted code.** Every script the extension runs ships in the package. No `eval`, no `new Function`,
  no `<script src="https://...">`, no loading JS from a CDN. Fetching *data* (JSON) is fine.

## Layout
```
manifest.json
src/background.ts    service worker
src/content/*.ts     content scripts (run in web pages, isolated world)
src/popup/           popup UI (popup.html + script)
src/options/         options page
icons/               16, 32, 48, 128 px PNGs
```

## Service worker lifecycle
- The service worker stops when idle (after about 30 seconds) and restarts on events. **Global variables are lost.**
  Persist state in `chrome.storage.local` (or `session` for per-browser-session data).
- Register all event listeners synchronously at the top level of the worker, not inside `await`s or callbacks,
  or they will be missed when the worker wakes.
- Use `chrome.alarms` instead of `setInterval`/`setTimeout` for anything longer than a few seconds.
- No DOM in the service worker (`document`, `window`, `localStorage` do not exist). Use an offscreen document if you truly need DOM APIs.

## Permissions (least privilege — reviewers check this)
- Prefer `activeTab` + `scripting` over broad host permissions: the extension gets access to the current tab only when the user clicks it.
- If host access is needed, list specific origins, and prefer `optional_host_permissions` requested at the moment of use
  with `chrome.permissions.request`.
- Never add `<all_urls>`, `tabs`, `history`, `cookies` or `webRequest` "just in case". Every permission needs a one-line reason in `PERMISSIONS.md`.

## Messaging
- Content script ↔ service worker: `chrome.runtime.sendMessage` / `chrome.runtime.onMessage`. Popup → tab: `chrome.tabs.sendMessage(tabId, ...)`.
- Messages are typed objects with a `type` field. Validate the shape on receipt; treat messages from content scripts as untrusted
  (web pages can influence them).
- To respond asynchronously from `onMessage`, `return true` from the listener and call `sendResponse` later.

## Content scripts
- Do not trust page data. Never insert page-controlled strings with `innerHTML`; use `textContent` or build elements.
- Scope `matches` as narrowly as possible. Avoid running on every page if the feature is for one site.
- Style injected UI in a Shadow DOM so page CSS cannot break it (and vice versa).

## Dev loop
- `npm run build` outputs to `dist/`. The human loads it at `chrome://extensions` → Developer mode → Load unpacked → `dist/`.
- After changing `manifest.json` or the service worker, the extension must be reloaded on that page. Remind the human.
- Debug the worker from `chrome://extensions` → "service worker" link; debug content scripts in the page's DevTools.

## Before you say "done"
`npm run build` passes, `manifest.json` is valid JSON with no new permissions you have not justified, and you have said what to reload and test.
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 10 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `extension-store-prep`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Chrome extension (Manifest V3)" v1.0.0 — https://loadout.jnw-it.com/loadouts/chrome-extension-mv3/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 10 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `extension-store-prep`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Chrome extension (Manifest V3)" v1.0.0 — https://loadout.jnw-it.com/loadouts/chrome-extension-mv3/ -->
Cursor rule .cursor/rules/manifest.mdc Rule applied when editing manifest.json. 15 lines
Download Raw
---
description: Manifest V3 manifest.json rules
globs: "**/manifest.json"
alwaysApply: false
---

- `"manifest_version": 3`. Background is `{ "service_worker": "background.js", "type": "module" }` — never `scripts` or `page`.
- Use `"action"` for the toolbar button, not `browser_action`/`page_action`.
- Adding any entry to `permissions` or `host_permissions` requires a justification line in `PERMISSIONS.md`. Prefer `activeTab`.
- Prefer `optional_host_permissions` for sites the user opts into.
- No remote URLs in `content_security_policy`. Do not loosen the default extension CSP.
- `web_accessible_resources` lists only files a page genuinely needs, with narrow `matches`.
- Bump `version` (dot-separated integers, e.g. `1.2.0`) on every store upload.
- Keep `description` under 132 characters; it is shown in the store.
Skill skills/extension-store-prep/SKILL.md Prepares a Chrome Web Store submission. 38 lines
Download Raw
---
name: extension-store-prep
description: Prepare a Manifest V3 Chrome extension for Chrome Web Store submission. Use when the user wants to publish, submit, package or release their extension.
---

# Chrome Web Store prep

## 1. Audit the manifest
- `manifest_version` is 3, `version` is bumped since the last upload, `name` and `description` (≤132 chars) are final.
- Icons: 16, 32, 48 and 128 px PNGs exist and are referenced.
- For each permission and host permission, write a one-sentence justification describing the user-facing feature that needs it.
  If you cannot, recommend removing it. `activeTab` is preferred over host permissions; broad host permissions slow review.

## 2. Check for common rejection reasons
- **Remote code:** search the build for `eval(`, `new Function(`, remote `<script src=`, and imports from `http`. Any hit is a blocker.
- **Single purpose:** the extension does one clearly described thing. Flag unrelated features.
- **Obfuscation:** minified is fine, obfuscated is not. Do not enable obfuscating build plugins.
- **Data use:** list every piece of user data the extension reads, stores or sends anywhere.

## 3. Write the listing material into `store/`
- `store/description.md`: what it does in the first sentence, then features, then a privacy line.
- `store/permissions.md`: each permission with its justification (pasted into the dashboard's Privacy tab).
- `store/privacy.md`: data collected, why, where it goes, retention. If nothing leaves the device, say so plainly.
  A privacy policy URL is required if the extension handles personal or sensitive data — the human must host it somewhere.
- Screenshot list: tell the human to capture at least one 1280×800 (or 640×400) screenshot, plus a 440×280 small promo tile.

## 4. Package
```sh
npm run build
cd dist && zip -r ../extension-$(node -p "require('./manifest.json').version").zip . -x "*.map" && cd ..
```
`manifest.json` must be at the root of the zip. Exclude source maps and dev files.

## 5. Hand over
Tell the human the zip path, then the dashboard steps they must do themselves: upload at the Chrome Web Store Developer
Dashboard, fill in Store listing and Privacy tabs from the `store/` files, choose visibility, submit for review.
A one-off developer registration fee applies to new accounts. Do not claim the extension has been submitted.

All files: source zip · Licence MIT · By Agent Loadout · First listed

Installing and testing

How do I install Chrome extension (Manifest V3) in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/extension-store-prep/SKILL.md at .claude/skills/extension-store-prep/SKILL.md. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/chrome-extension-mv3/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Chrome extension (Manifest V3) in Codex CLI?

From your project root, put AGENTS.md, skills/extension-store-prep/SKILL.md at .agents/skills/extension-store-prep/SKILL.md. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/chrome-extension-mv3/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Chrome extension (Manifest V3) in Cursor?

From your project root, put AGENTS.md, .cursor/rules/manifest.mdc, skills/extension-store-prep/SKILL.md at .agents/skills/extension-store-prep/SKILL.md. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/chrome-extension-mv3/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Chrome extension (Manifest V3) in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/extension-store-prep/SKILL.md at .agents/skills/extension-store-prep/SKILL.md. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/chrome-extension-mv3/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Chrome extension (Manifest V3) in GitHub Copilot?

From your project root, put AGENTS.md, skills/extension-store-prep/SKILL.md at .agents/skills/extension-store-prep/SKILL.md. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/chrome-extension-mv3/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

Has Chrome extension (Manifest V3) been tested?

It passed the Level 1 automated install checks on 2026-10-16: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.

More for Claude Code, Codex, Cursor, Gemini CLI and GitHub Copilot.