
Browser Extension
- 2 installs
- 230 repo stars
- Updated January 24, 2026
- xenitv1/claude-code-maestro
Guides building Manifest V3 browser extensions with service-worker persistence, Side Panel API, chrome.storage state, and cross-browser compatibility.
About
A skill for building modern browser extensions on Manifest V3, covering service-worker termination, persistence via chrome.storage/IndexedDB, and the Side Panel API. A developer uses it when creating or hardening a browser extension.
- Manifest V3 service-worker persistence via alarms and offscreen API
- Mandatory durable state in chrome.storage/IndexedDB, not globals
Browser Extension by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,862 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/xenitv1/claude-code-maestro --skill browser-extensionAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 230 |
| Last updated | January 24, 2026 |
| Repository | xenitv1/claude-code-maestro ↗ |
What it does
Guides building Manifest V3 browser extensions with service-worker persistence, Side Panel API, chrome.storage state, and cross-browser compatibility.
Files
<domain_overview>
🌐 BROWSER EXTENSION: THE 2026 MASTERCLASS
Philosophy: Extensions are ephemeral, restricted, yet powerful. Persistence is an Art. Security is a Mandate.
Design Constraint: For UI/UX, Aesthetics, and Layout, YOU MUST REFER TO THE frontend-design SKILL.PERSISTENCE PARADOX GUARD (CRITICAL): Never rely on global variables or in-memory state in background scripts. AI-generated code frequently fails by assuming Manifest V3 service workers are persistent. They are NOT; they terminate after 30 seconds of inactivity. You MUST backup every piece of state to chrome.storage or IndexedDB immediately upon change. This skill aims to eliminate "volatile-state" bugs typical of generic AI implementations. If data is not in durable storage, it does not exist. </domain_overview> <manifest_architecture>
🏗️ PROTOCOL 1: THE MANIFEST V3 CONSTITUTION
All extensions must be built on Manifest v3. No exceptions. 1. Manifest Blueprint:
- Service Workers: No persistent background pages. Use
"background": { "service_worker": "background.js" }. - No Remote Code: All scripts must be local.
unsafe-evalis forbidden. - Permissions: Principle of Least Privilege. Use
optional_permissionswhere possible. - Action UI: Prefer
actionoverbrowser_actionorpage_action.
2. Side Panel Supremacy:
- Requirement: Use
chrome.sidePanelfor persistent, non-intrusive experiences. - API:
chrome.sidePanel.setOptions({ path: 'sidepanel.html', enabled: true }).
</manifest_architecture> <persistence_engine>
⚡ PROTOCOL 2: THE PERSISTENCE ENGINE (ANTI-TERMINATION)
Service Workers sleep. You must keep the logic alive. 1. The Alarm Pulse:
- Use
chrome.alarmsto wake up the Service Worker every 1-5 minutes for background sync.
2. The Offscreen Document (When needed):
- Use the
offscreenAPI for tasks like DOM parsing, heavy calculations, or keeping the SW alive via periodic messaging.
3. State Management Protocol:
- NEVER rely on global variables.
- Mandatory: Use
chrome.storage.sessionfor transient session-only secrets. - Mandatory: Use
IndexedDBorchrome.storage.localfor large datasets and persistent user data.
</persistence_engine> <security_fortress>
🔐 PROTOCOL 3: THE SECURITY FORTRESS
1. Context Bridge Safety:
- Content Scripts are "Hostile Territory". Always sanitize data passed to the Service Worker via
chrome.runtime.sendMessage.
2. Declarative Net Request:
- Use
declarativeNetRequestfor blocking/modifying headers. Only usewebRequestas a fallback for Firefox if dynamic rules are critical.
</security_fortress> <design_integration>
🎨 PROTOCOL 4: DESIGN & UI/UX (INTEGRATED)
Direct Instruction: You are an extension developer, not a designer. You must outsource the "Soul" of the UI.
1. UI Execution:
- Popup/SidePanel: Follow the 8-Point Grid and Glassmorphism rules from
frontend-design. - Component Atomization: Use Atomic Design 2.0 principles.
- Friction: Ensure the popup interaction is < 400ms (Doherty Threshold).
</design_integration> <audit_and_reference>
🛠️ PROTOCOL 5: SCRIPT ENFORCEMENT (THE SENTINEL)
Every extension build MUST pass the high-tier audit suite. 1. [manifest-auditor.js](skills/browser-extension/scripts/js/manifest-auditor.js):
- Rule: MV3 compliance and CSP safety. No broad permissions.
2. [persistence-check.js](skills/browser-extension/scripts/js/persistence-check.js):
- Rule: Service Worker "Heartbeat" verification and State integrity.
3. [asset-master.js](skills/browser-extension/scripts/js/asset-master.js):
- Rule: Icon dimensional audit and asset optimization.
---
📂 COGNITIVE AUDIT CYCLE
1. Run node scripts/js/manifest-auditor.js -> Clean? 2. Run node scripts/js/persistence-check.js -> Heartbeat detected? 3. Run node scripts/js/asset-master.js -> Assets optimized? 4. MANDATORY: Run playwright test -> All paths pass? 5. Is it Manifest v3 compliant? 6. Does the Service Worker handle termination gracefully (State stored)? 7. Are permissions minimized? 8. Is the UI justified by a "Narrative-First" screenplay from frontend-design?
Link: frontend-design
</audit_and_reference>
#!/usr/bin/env node
/**
* MAESTRO EXTENSION ASSET MASTER
*
* Rules:
* 1. Mandatory Icon Sizes (16, 48, 128).
* 2. No placeholder icons (Generic names like icon.png).
* 3. File size optimization (< 100KB for UI assets).
*/
const fs = require('fs');
const path = require('path');
/**
* Recursively find all files in a directory.
*/
function walkDir(dir, fileList = []) {
try {
const files = fs.readdirSync(dir);
for (const file of files) {
const filePath = path.join(dir, file);
try {
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
walkDir(filePath, fileList);
} else {
fileList.push(filePath);
}
} catch (err) {
// Skip inaccessible
}
}
} catch (err) {
// Skip inaccessible
}
return fileList;
}
/**
* Audits extension assets for presence and optimization.
*/
function auditAssets(directory) {
const issues = [];
const requiredIcons = ['icon16.png', 'icon48.png', 'icon128.png'];
const foundIcons = [];
const files = walkDir(directory);
for (const filePath of files) {
const file = path.basename(filePath);
const ext = path.extname(file).toLowerCase();
if (['.png', '.jpg', '.jpeg', '.svg'].includes(ext)) {
foundIcons.push(file);
try {
const stat = fs.statSync(filePath);
const sizeKb = stat.size / 1024;
if (sizeKb > 100) {
issues.push(`[OPTIMIZATION] Asset '${file}' is too large (${sizeKb.toFixed(1)}KB). Max 100KB for extensions.`);
}
} catch (err) {
// Skip
}
}
}
for (const req of requiredIcons) {
if (!foundIcons.some(f => f.includes(req))) {
issues.push(`[UX-COMPLIANCE] Missing icon size: ${req}. Store apps require exact dimensions.`);
}
}
return issues;
}
/**
* Main function.
*/
function main() {
console.log('🎨 STARTING ASSET INTEGRITY AUDIT...');
const targetDir = process.argv[2] || '.';
const issues = auditAssets(targetDir);
if (issues.length > 0) {
console.log(`\n🚨 ${issues.length} ASSET VIOLATIONS:`);
for (const issue of issues) {
console.log(` ❌ ${issue}`);
}
process.exit(1);
} else {
// Write success state
try {
const projectRoot = process.cwd();
const stateDir = path.join(projectRoot, '.maestro');
if (!fs.existsSync(stateDir)) {
fs.mkdirSync(stateDir, { recursive: true });
}
fs.writeFileSync(path.join(stateDir, 'audit.state'), String(Date.now() / 1000));
} catch (err) {
console.log(`[WARN] Could not save audit state: ${err.message}`);
}
console.log('✅ ASSETS VERIFIED: Optimized and Dimensionally correct.');
process.exit(0);
}
}
main();
#!/usr/bin/env node
/**
* MAESTRO MANIFEST AUDITOR (The Extension Sentinel)
*
* Rules:
* 1. Manifest v3 is mandatory.
* 2. No 'unsafe-eval' in CSP.
* 3. No overly broad host permissions.
* 4. Mandatory action and background definitions.
*/
const fs = require('fs');
const path = require('path');
/**
* Audit manifest.json for security and compliance.
*/
function auditManifest(filepath) {
const issues = [];
try {
const content = fs.readFileSync(filepath, 'utf-8');
const data = JSON.parse(content);
// RULE 1: Manifest Version
if (data.manifest_version !== 3) {
issues.push("[V3-MANDATE] Manifest version must be 3. MV2 is deprecated and insecure.");
}
// RULE 2: CSP Security
const csp = data.content_security_policy || {};
const extensionPagesCsp = csp.extension_pages || '';
if (extensionPagesCsp.includes('unsafe-eval') || extensionPagesCsp.includes('unsafe-inline')) {
issues.push("[SECURITY-CSP] 'unsafe-eval' or 'unsafe-inline' detected in CSP. Critical security risk.");
}
// RULE 3: Host Permissions
const hostPermissions = data.host_permissions || [];
const dangerousHosts = ['<all_urls>', '*://*/*', 'http://*/*', 'https://*/*'];
for (const host of hostPermissions) {
if (dangerousHosts.includes(host)) {
issues.push(`[LEAST-PRIVILEGE] Broad host permission '${host}' detected. Use specific domains.`);
}
}
// RULE 4: Core Components
if (!data.background || !data.background.service_worker) {
issues.push("[ARCHITECTURE] Missing 'background.service_worker'. MV3 requires service worker.");
}
if (!data.action) {
issues.push("[UX-ARCH] Missing 'action' definition. MV3 extensions should use 'action' for UI.");
}
} catch (err) {
issues.push(`[ERROR] Could not parse manifest.json: ${err.message}`);
}
return issues;
}
/**
* Main function.
*/
function main() {
console.log('🛡️ STARTING MANIFEST SECURITY AUDIT...');
let target = process.argv[2] || 'manifest.json';
if (fs.existsSync(target) && fs.statSync(target).isDirectory()) {
target = path.join(target, 'manifest.json');
}
if (!fs.existsSync(target)) {
console.log(`[SKIP] ${target} not found. Skipping manifest audit.`);
return;
}
const issues = auditManifest(target);
if (issues.length > 0) {
console.log(`\n🚨 ${issues.length} MANIFEST VIOLATIONS FOUND:`);
for (const issue of issues) {
console.log(` ❌ ${issue}`);
}
process.exit(1);
} else {
// Write success state
try {
const projectRoot = process.cwd();
const stateDir = path.join(projectRoot, '.maestro');
if (!fs.existsSync(stateDir)) {
fs.mkdirSync(stateDir, { recursive: true });
}
fs.writeFileSync(path.join(stateDir, 'audit.state'), String(Date.now() / 1000));
} catch (err) {
console.log(`[WARN] Could not save audit state: ${err.message}`);
}
console.log('✅ MANIFEST VERIFIED: Security & Compliance standards met.');
process.exit(0);
}
}
main();
#!/usr/bin/env node
/**
* MAESTRO PERSISTENCE CHECKER (SW Survival Analyst)
*
* Rules:
* 1. Must listen to chrome.alarms.onAlarm for wakeup.
* 2. Must use chrome.storage for state (No globals).
* 3. Service Worker must be in the root or background/ directory.
*/
const fs = require('fs');
const path = require('path');
/**
* Analyzes a Service Worker for persistence patterns.
*/
function checkPersistence(filepath) {
const issues = [];
try {
const content = fs.readFileSync(filepath, 'utf-8');
// RULE 1: Alarm Wakeup
if (!content.includes('chrome.alarms.onAlarm.addListener')) {
issues.push('[PERSISTENCE] Service Worker missing alarm listener. SW will terminate and never wake up.');
}
// RULE 2: Storage usage
if (!content.includes('chrome.storage') && !content.includes('chrome.storage.local')) {
issues.push("[STATE-LOSS] Use of 'chrome.storage' not detected. Persist state to avoid data loss on termination.");
}
// RULE 3: Global Variables (Naive check)
const globalsPattern = /^(?:let|var)\s+\w+\s*=/gm;
const globalsFound = content.match(globalsPattern) || [];
if (globalsFound.length > 2) {
issues.push(`[ARCHITECTURE] ${globalsFound.length} global variables detected. SW globals are ephemeral. Use storage.`);
}
} catch (err) {
issues.push(`[ERROR] Could not read service worker: ${err.message}`);
}
return issues;
}
/**
* Main function.
*/
function main() {
console.log('⚡ STARTING PERSISTENCE INTEGRITY CHECK...');
const target = process.argv[2] || 'background.js';
if (!fs.existsSync(target)) {
console.log(`[SKIP] ${target} not found. Skipping persistence check.`);
return;
}
const issues = checkPersistence(target);
if (issues.length > 0) {
console.log(`\n🚨 PERSISTENCE RISKS DETECTED in ${target}:`);
for (const issue of issues) {
console.log(` ⚠️ ${issue}`);
}
process.exit(1);
} else {
// Write success state
try {
const projectRoot = process.cwd();
const stateDir = path.join(projectRoot, '.maestro');
if (!fs.existsSync(stateDir)) {
fs.mkdirSync(stateDir, { recursive: true });
}
fs.writeFileSync(path.join(stateDir, 'audit.state'), String(Date.now() / 1000));
} catch (err) {
console.log(`[WARN] Could not save audit state: ${err.message}`);
}
console.log('✅ PERSISTENCE VERIFIED: Pulse and State patterns detected.');
process.exit(0);
}
}
main();