samber/cc-skillsMIT14 files

Chrome Extension

Build Chrome extensions with Manifest V3. Use this skill whenever the user mentions Chrome extension, browser extension, manifest.json, content script, service worker (in extension context), popup, side panel, chrome.runtime, chrome.tabs, chrome.storage, chrome.scripting, or any Chrome extension API. Also trigger when the user wants to inject scripts into web pages, communicate between page and background, bypass CSP from a content script, build an RPC layer over chrome messaging, or publish to the Chrome Web Store. Covers both new extension projects and adding features to existing ones. Do NOT use for CRXJS/Vite-based builds with HMR — use samber/cc-skills@crxjs instead.

Specification
Skill ID
samber/cc-skills/chrome-extension
Publisher
samber
Repository
cc-skills
Installs
0
Files
14
License
MIT
Requires
Designed for Claude Code, Codex or similar harness. Requires git, node.
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

samber/cc-skills/chrome-extensionInstalls these files
  • SKILL.md
  • references/content-scripts.md
  • references/debugging-mistakes.md
  • references/execution-contexts.md
  • references/manifest-v3.md
  • references/messaging-rpc.md
  • references/network-csp.md
  • references/permissions.md
  • references/publishing.md
  • references/service-worker.md
  • references/storage.md
  • references/typescript-build.md
  • references/ui-surfaces.md
  • references/web-accessible-resources.md

What this skill tells the agent

Chrome Extension Development (Manifest V3)

This skill covers everything needed to build, debug, and publish Chrome extensions with MV3. It is organized as a routing document: read this file first to understand the architecture and decision points, then load the relevant reference file for implementation details.

Reference files

Read only the reference files relevant to the current task. Each file is self-contained.

FileWhen to read
references/manifest-v3.mdSetting up or modifying manifest.json, configuring icons, versioning
references/service-worker.mdBackground logic, lifecycle, state persistence, alarms, events
references/content-scripts.mdInjecting code into pages, isolated/main world, dynamic injection, SPA handling, orphaning
references/messaging-rpc.mdCommunication between any contexts, typed protocols, RPC layer, async handler patterns
references/ui-surfaces.mdPopup, options page, side panel, context menus, commands, notifications, omnibox, devtools panel
references/storage.mdchrome.storage (local/sync/session), quotas, reactive patterns, framework hooks
references/network-csp.mdHTTP requests from content scripts, CSP bypass relay, declarativeNetRequest, offscreen docs, CORS
references/permissions.mdRequired/optional permissions, host permissions, activeTab, runtime request flow
references/web-accessible-resources.mdExposing extension files to web pages, security implications
references/typescript-build.mdTypeScript setup, project structure, build tools comparison, bundling
references/publishing.mdChrome Web Store submission, review process, rejection reasons, updates, privacy policy
references/execution-contexts.mdCommunication flow diagrams, per-context capabilities/limits, choosing the right messaging method
references/debugging-mistakes.mdDevTools for extensions, testing SW termination, common gotchas, error patterns

Architecture overview

A Chrome extension has up to 5 execution contexts that communicate via message passing:

┌──────────────────────────────────────────────────────────┐
│ Extension Process                                        │
│  ┌─────────────────┐  ┌───────┐  ┌─────────┐  ┌──────┐ │
│  │ Service Worker   │  │ Popup │  │ Options │  │ Side │ │
│  │ (background)     │  │       │  │  Page   │  │Panel │ │
│  │ - No DOM         │  │ Full  │  │  Full   │  │ Full │ │
│  │ - Ephemeral      │  │ DOM   │  │  DOM    │  │ DOM  │ │
│  │ - All chrome.*   │  │ All   │  │  All    │  │ All  │ │
│  │   APIs           │  │ APIs  │  │  APIs   │  │ APIs │ │
│  └────────┬─────────┘  └───┬───┘  └────┬────┘  └──┬───┘ │
│           │ chrome.runtime.sendMessage / connect   │     │
└───────────┼────────────────┼───────────┼──────────┼──────┘
            │                │           │          │
    chrome.tabs.sendMessage  │           │          │
            │                │           │          │
┌───────────┼────────────────┼───────────┼──────────┼──────┐
│ Web Page  ▼                                              │
│  ┌──────────────────┐    ┌──────────────────┐            │
│  │ Content Script    │    │ Main World Script │            │
│  │ (isolated world)  │◄──►│ (page context)    │            │
│  │ - Shared DOM      │    │ - Shared DOM      │            │
│  │ - Own JS scope    │    │ - Page JS scope   │            │
│  │ - chrome.runtime  │    │ - No chrome.* API │            │
│  │ - chrome.storage  │    │ - Full page access│            │
│  │ - Subject to CSP  │    │ - Subject to CSP  │            │
│  │   (network only)  │    │   (fully)         │            │
│  └──────────────────┘    └──────────────────┘            │
│           ▲ window.postMessage                           │
│           │ (through shared DOM)                         │
└──────────────────────────────────────────────────────────┘

Communication flows (labeled channels)

┌───────────────────────────────────────────────────────────────────────────┐
│ Extension Process                                                         │
│                                                                           │
│  ┌─────────────────┐  chrome.runtime   ┌───────┐  ┌─────────┐  ┌──────┐ │
│  │ Service Worker   │◄─.sendMessage()──│ Popup │  │ Options │  │ Side │ │
│  │ (background)     │◄─.connect()──────│       │  │  Page   │  │Panel │ │
│  │                  │                  └───────┘  └─────────┘  └──────┘ │
│  │ - No DOM         │  ┌────────────────────────────────────────────┐   │
│  │ - Ephemeral 30s  │  │ SW cannot push to these pages.             │   │
│  │ - All chrome.*   │  │ Use: ports (.connect) or storage.onChanged │   │
│  └────────┬─────────┘  └────────────────────────────────────────────┘   │
│           │                                                              │
│  chrome.storage.onChanged ◄── fires across ALL contexts simultaneously  │
│                                                                           │
└───────────┼──────────────────────────────────────────────────────────────┘
            │ chrome.tabs.sendMessage(tabId, ...) [SW must know tabId]
            │
┌───────────┼──────────────────────────────────────────────────────────────┐
│ Web Page  ▼                                                              │
│  ┌──────────────────┐  window.postMessage  ┌──────────────────┐         │
│  │ Content Script    │◄───────────────────►│ Main World Script │         │
│  │ (isolated world)  │  Custom DOM events  │ (page context)    │         │
│  │                   │                     │                   │         │
│  │ chrome.runtime ───┼── to/from SW        │ No chrome.* APIs  │         │
│  │ chrome.storage    │                     │ Full page JS      │         │
│  │ Shared DOM        │                     │ Shared DOM        │         │
│  │ Page CSP (network)│                     │ Page CSP (full)   │         │
│  └──────────────────┘                     └──────────────────┘         │
└──────────────────────────────────────────────────────────────────────────┘

For detailed flow diagrams (three-layer bridge, cross-extension, storage broadcast) and a per-context breakdown of permissions, limits, and workarounds: → Read references/execution-contexts.md

Communication methods at a glance

MethodDirectionBest for
chrome.runtime.sendMessageAny ext context → SWOne-shot request/response (90% of cases)
chrome.tabs.sendMessageSW → content script (by tabId)Pushing data to a specific tab
chrome.runtime.connect (Port)BidirectionalStreaming, progress, SW ↔ popup
window.postMessageBetween worlds on same pagePage JS ↔ content script bridge
chrome.storage.onChangedBroadcast to all contextsSettings sync, no messaging needed

→ Full matrix with limits and edge cases: references/execution-contexts.md → Implementation patterns, typed protocols, RPC layer: references/messaging-rpc.md

Key architectural rules

  1. Service worker is ephemeral. It terminates after 30s of inactivity. All state must be persisted to chrome.storage. All event listeners must be registered synchronously at the top level. Never use setTimeout/setInterval for anything beyond a few seconds. → Read references/service-worker.md
  1. Content scripts run in the page's origin. Network requests from content scripts are subject to the page's CSP and CORS. To bypass, relay through the service worker. → Read references/network-csp.md
  1. Messaging is the backbone. Every cross-context interaction uses chrome.runtime messaging. The #1 bug: forgetting to return true from async message listeners. → Read references/messaging-rpc.md

Use this skill in a project

Open any RiverX project, search the Skills panel for samber/cc-skills/chrome-extension, and install it in one click.

Use this skill