distributions/codex/skills/browser-extension-patterns/SKILL.md
Build browser extensions with Manifest V3 for Chrome, Firefox, and cross-browser compatibility. Covers content scripts, background workers, popup UI, storage APIs, and extension messaging. Triggers on browser extension development, Manifest V3, or Chrome extension requests.
npx skillsauth add a-organvm/a-i--skills browser-extension-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build cross-browser extensions with Manifest V3 architecture.
my-extension/
├── manifest.json # Extension manifest
├── background/
│ └── service-worker.js # Background service worker
├── content/
│ └── content-script.js # Injected into web pages
├── popup/
│ ├── popup.html # Popup UI
│ ├── popup.js # Popup logic
│ └── popup.css # Popup styles
├── options/
│ ├── options.html # Settings page
│ └── options.js
├── icons/
│ ├── icon-16.png
│ ├── icon-48.png
│ └── icon-128.png
└── _locales/ # Internationalization
└── en/messages.json
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"description": "Brief description of what it does",
"permissions": ["storage", "activeTab"],
"host_permissions": ["https://*.example.com/*"],
"background": {
"service_worker": "background/service-worker.js"
},
"content_scripts": [{
"matches": ["https://*.example.com/*"],
"js": ["content/content-script.js"],
"css": ["content/content-style.css"],
"run_at": "document_idle"
}],
"action": {
"default_popup": "popup/popup.html",
"default_icon": {
"16": "icons/icon-16.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
},
"options_page": "options/options.html",
"icons": {
"16": "icons/icon-16.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
}
// background/service-worker.js
// Installation
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
chrome.storage.local.set({ settings: { enabled: true, theme: 'light' } });
}
});
// Message handling from content scripts and popup
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
switch (message.type) {
case 'getData':
fetchData(message.url).then(sendResponse);
return true; // Async response
case 'updateBadge':
chrome.action.setBadgeText({ text: String(message.count) });
break;
}
});
// Alarm-based periodic tasks (replaces MV2 persistent background)
chrome.alarms.create('sync', { periodInMinutes: 30 });
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'sync') syncData();
});
// content/content-script.js
// DOM manipulation on target pages
function enhancePage() {
const elements = document.querySelectorAll('.target-class');
elements.forEach(el => {
const badge = document.createElement('span');
badge.className = 'my-extension-badge';
badge.textContent = 'Enhanced';
el.appendChild(badge);
});
}
// Run when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', enhancePage);
} else {
enhancePage();
}
// Communicate with background
async function requestData(url) {
return chrome.runtime.sendMessage({ type: 'getData', url });
}
// Listen for messages from background/popup
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'getPageData') {
sendResponse({ title: document.title, url: location.href });
}
});
// Chrome storage API (synced across devices)
const storage = {
async get(key) {
const result = await chrome.storage.sync.get(key);
return result[key];
},
async set(key, value) {
await chrome.storage.sync.set({ [key]: value });
},
async getLocal(key) {
const result = await chrome.storage.local.get(key);
return result[key];
},
onChange(callback) {
chrome.storage.onChanged.addListener((changes, area) => {
callback(changes, area);
});
}
};
// Usage
await storage.set('settings', { theme: 'dark', enabled: true });
const settings = await storage.get('settings');
<!-- popup/popup.html -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div id="app">
<h2>My Extension</h2>
<label>
<input type="checkbox" id="enabled"> Enabled
</label>
<div id="status"></div>
</div>
<script src="popup.js"></script>
</body>
</html>
// popup/popup.js
document.addEventListener('DOMContentLoaded', async () => {
const settings = await chrome.storage.sync.get('settings');
document.getElementById('enabled').checked = settings.settings?.enabled;
document.getElementById('enabled').addEventListener('change', async (e) => {
await chrome.storage.sync.set({
settings: { ...settings.settings, enabled: e.target.checked }
});
// Notify content scripts
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, { type: 'settingsChanged', enabled: e.target.checked });
});
});
// Polyfill for Firefox WebExtensions API
const browser = globalThis.browser || globalThis.chrome;
// Feature detection
const isFirefox = typeof browser !== 'undefined' && browser.runtime?.getBrowserInfo;
const isChrome = typeof chrome !== 'undefined' && chrome.runtime?.id;
{
"background": {
"scripts": ["background/service-worker.js"]
},
"browser_specific_settings": {
"gecko": {
"id": "[email protected]",
"strict_min_version": "109.0"
}
}
}
| Permission | When | Impact |
|-----------|------|--------|
| activeTab | Need current tab only | Low (user-triggered) |
| storage | Need to save settings | Low |
| tabs | Need tab URLs/titles | Medium |
| host_permissions | Need page access | High (shows warning) |
| <all_urls> | Need all page access | Very High (avoid if possible) |
Principle: Request minimum permissions. Use activeTab over broad host permissions when possible.
<all_urls> permission — Request only the hosts you needchrome.storage APIruntime.onInstalled to handle updates and cleanuptesting
Designs systems for encoding, scoring, and generating choreographic movement using Laban notation, computational geometry, and procedural animation principles.
tools
Manage monorepos and multi-package repositories with workspace tools, dependency management, selective builds, and change detection. Covers npm/pnpm workspaces, Turborepo, and Python monorepo patterns. Triggers on monorepo setup, workspace management, or multi-package repository requests.
development
Curated bundle for managing monorepos with containerized deployment pipelines. Includes monorepo management, Docker containerization, CI/CD deployment, and coding standards. Use when setting up or improving multi-package repository infrastructure.
development
Apply modular synthesis principles to system design, workflow architecture, and conceptual frameworks. Use when designing modular systems, creating architecture diagrams using synthesis metaphors, applying signal flow thinking to data pipelines, or translating between audio engineering and software concepts. Triggers on modular architecture design, signal flow diagrams, synthesis-inspired system thinking, or "oscillator/patch" metaphors.