
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.
- Installs
- 4.6K
- Last 24h
- +102
- Trending rank
- #1981
- Security
- Warn
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/samber/cc-skills --skill chrome-extension- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads chrome-extension automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
Security audits
Independent scans of the skill's instructions and bundled files.
SKILL.md
The instructions your agent reads when the skill is triggered.
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.
| File | When to read |
|---|---|
references/manifest-v3.md | Setting up or modifying manifest.json, configuring icons, versioning |
references/service-worker.md | Background logic, lifecycle, state persistence, alarms, events |
references/content-scripts.md | Injecting code into pages, isolated/main world, dynamic injection, SPA handling, orphaning |
references/messaging-rpc.md | Communication between any contexts, typed protocols, RPC layer, async handler patterns |
references/ui-surfaces.md | Popup, options page, side panel, context menus, commands, notifications, omnibox, devtools panel |
references/storage.md | chrome.storage (local/sync/session), quotas, reactive patterns, framework hooks |
references/network-csp.md | HTTP requests from content scripts, CSP bypass relay, declarativeNetRequest, offscreen docs, CORS |
references/permissions.md | Required/optional permissions, host permissions, activeTab, runtime request flow |
references/web-accessible-resources.md | Exposing extension files to web pages, security implications |
references/typescript-build.md | TypeScript setup, project structure, build tools comparison, bundling |
references/publishing.md | Chrome Web Store submission, review process, rejection reasons, updates, privacy policy |
references/execution-contexts.md | Communication flow diagrams, per-context capabilities/limits, choosing the right messaging method |
references/debugging-mistakes.md | DevTools 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
| Method | Direction | Best for |
|---|---|---|
chrome.runtime.sendMessage | Any ext context → SW | One-shot request/response (90% of cases) |
chrome.tabs.sendMessage | SW → content script (by tabId) | Pushing data to a specific tab |
chrome.runtime.connect (Port) | Bidirectional | Streaming, progress, SW ↔ popup |
window.postMessage | Between worlds on same page | Page JS ↔ content script bridge |
chrome.storage.onChanged | Broadcast to all contexts | Settings 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
-
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 -
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 -
Messaging is the backbone. Every cross-context interaction uses chrome.runtime messaging. The #1 bug: forgetting to
return truefrom async message listeners. → Readreferences/messaging-rpc.md -
Permissions determine CWS review speed. Broad host_permissions trigger manual review (weeks). activeTab + optional permissions = fast automated review. → Read
references/permissions.md -
Popup is destroyed on blur. Side panel persists. Choose based on interaction duration. → Read
references/ui-surfaces.md
Decision tree: which context handles what?
"I need to run code when the user visits a page"
→ Content script. Static (manifest) for known URL patterns, dynamic (chrome.scripting) for user-triggered injection. Default to isolated world unless you need page JS access. → Read references/content-scripts.md
"I need to make an HTTP request to my API"
- From popup/options/side panel: direct fetch() works (extension origin, no CSP issues)
- From content script on a page with restrictive CSP: relay through service worker
- From service worker: direct fetch() works (requires host_permissions for the target domain) → Read
references/network-csp.md
"I need to store user settings"
- Settings that sync across devices: chrome.storage.sync (100KB limit)
- Large data or caches: chrome.storage.local (10MB, or unlimited with permission)
- Ephemeral state surviving SW restarts: chrome.storage.session → Read
references/storage.md
"I need to modify HTTP headers or block requests"
→ declarativeNetRequest (NOT webRequest, which lost blocking in MV3) → Read references/network-csp.md
"I need the page's JavaScript to talk to my extension"
→ Three-layer bridge: page (window.postMessage) → content script → service worker → Read references/messaging-rpc.md
"I need to understand what each context can and cannot do"
→ Read references/execution-contexts.md — per-context cards listing chrome.* access, DOM, network, storage, lifetime, hard limits, and practical workarounds.
"I need periodic background tasks"
→ chrome.alarms (minimum 30s interval). NOT setTimeout. → Read references/service-worker.md
"I need DOM APIs in the background" (DOMParser, Canvas, Audio)
→ Offscreen document. One per extension, only chrome.runtime available. → Read references/network-csp.md
"I need to authenticate with OAuth"
→ chrome.identity.launchWebAuthFlow() or chrome.identity.getAuthToken() (Google only) → Read references/service-worker.md (identity section)
Workflow: new extension from scratch
-
Define the manifest with minimum permissions. Start with
activeTab+scripting. → Readreferences/manifest-v3.md -
Set up TypeScript and build tooling (or use CRXJS for Vite-based dev). → Read
references/typescript-build.md -
Implement the service worker with all event listeners at the top level. → Read
references/service-worker.md -
Add content scripts if you need page interaction. → Read
references/content-scripts.md -
Build UI surfaces (popup, options, side panel) as needed. → Read
references/ui-surfaces.md -
Wire up messaging between all contexts. → Read
references/messaging-rpc.md -
Test with DevTools, specifically test service worker termination. → Read
references/debugging-mistakes.md -
Publish to Chrome Web Store. → Read
references/publishing.md
Workflow: adding a feature to an existing extension
- Identify which context the feature belongs to (see decision tree above).
- Read the relevant reference file(s) for that context.
- Check if new permissions are needed. Prefer optional_permissions for new capabilities. → Read
references/permissions.md - Update the manifest if adding new content scripts, UI surfaces, or permissions.
- Handle extension updates gracefully (content script orphaning). → Read
references/content-scripts.md(orphaning section)
Minimal manifest.json template
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"description": "What it does in one sentence",
"permissions": ["storage", "activeTab", "scripting"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
},
"background": {
"service_worker": "background.js",
"type": "module"
},
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
→ For the full manifest reference with all fields: references/manifest-v3.md
Code patterns quick reference
Async message handler (the safe pattern)
// Wrap async handlers to avoid the return-true trap
function asyncHandler(
fn: (msg: any, sender: chrome.runtime.MessageSender) => Promise<any>,
) {
return (
message: any,
sender: chrome.runtime.MessageSender,
sendResponse: (r: any) => void,
) => {
fn(message, sender)
.then(sendResponse)
.catch((e) => sendResponse({ __error: true, message: e.message }));
return true; // literal true, not Promise<true>
};
}
chrome.runtime.onMessage.addListener(
asyncHandler(async (msg, sender) => {
if (msg.type === "FETCH") {
const res = await fetch(msg.url);
return { ok: res.ok, data: await res.text() };
}
}),
);
CSP bypass relay (content script → service worker → API)
// content-script.ts
async function apiCall(endpoint: string, options?: RequestInit) {
return chrome.runtime.sendMessage({ type: "API_RELAY", endpoint, options });
}
// background.ts
const ALLOWED_ENDPOINTS = ["https://api.example.com"];
chrome.runtime.onMessage.addListener(
asyncHandler(async (msg) => {
if (msg.type !== "API_RELAY") return;
if (!ALLOWED_ENDPOINTS.some((e) => msg.endpoint.startsWith(e))) {
throw new Error("Blocked endpoint");
}
const res = await fetch(msg.endpoint, msg.options);
return { ok: res.ok, status: res.status, data: await res.text() };
}),
);
Persist state across SW restarts
// Use chrome.storage.session for ephemeral state
chrome.storage.session.setAccessLevel({
accessLevel: "TRUSTED_AND_UNTRUSTED_CONTEXTS",
});
async function getState<T>(key: string, fallback: T): Promise<T> {
const result = await chrome.storage.session.get(key);
return result[key] ?? fallback;
}
async function setState<T>(key: string, value: T): Promise<void> {
await chrome.storage.session.set({ [key]: value });
}
Orphaned content script detection
function isExtensionContextValid(): boolean {
try {
return !!chrome.runtime?.id;
} catch {
return false;
}
}
// Before any chrome.runtime call
if (!isExtensionContextValid()) {
showRefreshBanner();
return;
}
What NOT to do
- Do NOT use
eval(),new Function(), or load remote scripts. MV3 forbids it. - Do NOT use
setTimeout/setIntervalfor anything > 5s in service workers. - Do NOT register event listeners inside callbacks or async functions.
- Do NOT use
<all_urls>host permission unless absolutely necessary. - Do NOT rely on DevTools keeping the service worker alive during testing.
- Do NOT forget
return truein async message listeners. - Do NOT use
localStorageorsessionStoragein service workers (they don't exist there). - Do NOT assume content scripts survive extension updates.
- Do NOT use
webRequestblocking (removed in MV3). UsedeclarativeNetRequest. - Do NOT use
chrome.extension.getBackgroundPage()(removed in MV3).
FAQ
What does the chrome-extension skill do?
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.
How do I install chrome-extension?
Run npx skills add https://github.com/samber/cc-skills --skill chrome-extension in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/chrome-extension/ (personal) or .claude/skills/chrome-extension/ (project).
Which AI agents can use chrome-extension?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is chrome-extension safe to install?
Security partners have reviewed it: Gen Agent Trust Hub passed; Socket flagged items to review; Snyk passed; ZeroLeaks passed. As with any skill, read the SKILL.md and bundled scripts before installing.
Who maintains chrome-extension?
It is published by samber in samber/cc-skills. It has 4,556 recorded installs.
More from samber/cc-skills
copywriting-hooks
samber/cc-skills
Writes opening hooks and post titles for long-form articles in EN or FR — blog posts, Substack/Medium/dev.to, LinkedIn long-form, newsletters, essays. Trigger whenever the user asks for a hook, opening, lede, intro, first sentence/paragraph, opener, accroche, attaque, phrase d'accroche, or première phrase — including punching up a flat intro or draft opening — or for a post title, titre d'article, or headline. Do NOT trigger for social posts (LinkedIn feed, Twitter/X, TikTok, Bluesky), READMEs, taglines, email subjects, ad copy, landing-page headlines, press releases, SEO meta, or body rewrites. Do NOT use for end-of-article CTAs — use samber/cc-skills@copywriting-cta instead.
linkedin-ghostwriting
samber/cc-skills
B2B LinkedIn ghostwriting — hooks, post structures, and copywriting frameworks for conversion-focused posts. Use when the user wants to write LinkedIn content, create ghostwritten posts, ghostwrite for a founder or executive, or develop a B2B social strategy. Apply when the user shares a story, result, or insight and wants it turned into a post. Do NOT use for newsletter or Substack issues — use samber/cc-skills@substack-ghostwriting instead.
copywriting-tone-of-voice-creator
samber/cc-skills
Builds a brand tone of voice guide (TONE.md) — voice attributes with do's/don'ts, NN/g positioning, tone modulation matrix, lexicon, channel rules — for downstream content skills to consume. Also ports an existing TONE.md to a new channel (blog → LinkedIn, web → Twitter/X, in-product UI). Covers B2B SaaS, B2C/D2C, NGO, public sector, consulting, industrial, product-led, personal, and volunteering brands. Apply when the user wants to define or refresh a brand voice, port it to a new channel, or set up a content factory. Not for writing individual posts, articles, emails, or UI strings — use the dedicated writing skills. Not for SOUL.md, PROSE.md (samber/cc-skills@copywriting-prose-creator), or DESIGN.md.
frontend-design-deslop
samber/cc-skills
Designs distinctive, non-generic UI — typography, OKLCH color, design tokens (DESIGN.md), layout, components, motion, dark mode, accessibility — for landing pages, SaaS apps, dashboards, ecommerce, decks, docs, portfolios, avoiding the AI-slop / Claude-esque default look. Use whenever building or styling any web frontend, app, dashboard, landing page, deck, or artifact, or when the user says "make it not look like AI", "de-slopify", "deslop", "less generic", "give it character", "design a UI for X", "design an app", "update DESIGN.md", or complains the output looks like every other AI site. Trigger even on a bare "build a UI for X" with no aesthetic named. Not for writing marketing copy.
humaniseur-fr
samber/cc-skills
Remove AI-writing patterns from French text and inject voice and personality. Use when editing, reviewing, or rewriting French content that reads like ChatGPT or Claude output. Detects and fixes 38 patterns: AI vocabulary (crucial, essentiel, notamment, dans le paysage), anglicisms from English-first models (faire du sens, adresser un problème), formulaic openings (À l'ère de, Dans un monde où), participle clauses in -ant, em dash overuse, decorative emojis, mixed guillemets and apostrophes, uniform sentence length. Trigger on humaniser, déslopifier, nettoyer le texte IA, enlever le slop, make it sound human. Do NOT use for English text — use samber/cc-skills@humanizer-en-asd-ste100 instead.
deep-research
samber/cc-skills
Deep research on any topic — broad parallel web searches, multi-source validation, confidence tracking, and a cited Markdown report. Use whenever the deliverable is a thorough sourced report rather than a quick answer: 'research ', 'deep dive on X', 'analyze the landscape', 'competitive analysis', 'compare these options', 'who are the players in Z', 'literature review', 'background on Y', 'what papers exist on X', 'product teardown', 'regulatory overview', 'funding landscape', 'what trends are emerging in X', 'patent landscape', 'community health', or any request requiring scanning many sources and producing a cited written analysis. Covers 11 research types: market (TAM/SAM, segments, pricing, trends), domain (industry structure, ecosystem, regulatory overview), technical (architecture, tooling, benchmarks, technology evaluation), competitive (competitor teardown, positioning, win/loss), product (feature analysis, reviews, teardowns, roadmap signals), academic (literature surve
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.