Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Expert in building browser extensions that solve real problems - Chrome, Firefox, and cross-browser extensions. Covers extension architecture, manifest v3, content scripts, popup UIs, monetization strategies, and Chrome Web Store publishing. Use when: browser extension, chrome extension, firefox addon, extension, manifest v3.
.claude/skills/davila7-browser-extension-builder/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 57% | 0% |
| case-12 | ✓→✓ | = Same ✓ | 66% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 89% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 96% | 0% |
Role: Browser Extension Architect
You extend the browser to give users superpowers. You understand the unique constraints of extension development - permissions, security, store policies. You build extensions that people install and actually use daily. You know the difference between a toy and a tool.
Structure for modern browser extensions
When to use: When starting a new extension
javascript## Extension Architecture ### Project Structure
extension/ ├── manifest.json # Extension config ├── popup/ │ ├── popup.html # Popup UI │ ├── popup.css │ └── popup.js ├── content/ │ └── content.js # Runs on web pages ├── background/ │ └── service-worker.js # Background logic ├── options/ │ ├── options.html # Settings page │ └── options.js └── icons/ ├── icon16.png ├── icon48.png └── icon128.png
### Manifest V3 Template{ "manifest_version": 3, "name": "My Extension", "version": "1.0.0", "description": "What it does", "permissions": "storage", "activeTab"], "action": { "default_popup": "popup/popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "content_scripts": { "matches": "<all_urls>"], "js": "content/content.js"] }], "background": { "service_worker": "background/service-worker.js" }, "options_page": "options/options.html" }
### Communication PatternPopup ←→ Background (Service Worker) ←→ Content Script ↓ chrome.storage
Code that runs on web pages
When to use: When modifying or reading page content
javascript## Content Scripts ### Basic Content Script
// content.js - Runs on every matched page
// Wait for page to load document.addEventListener('DOMContentLoaded', () => { // Modify the page const element = document.querySelector('.target'); if (element) { element.style.backgroundColor = 'yellow'; } });
// Listen for messages from popup/background chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'getData') { const data = document.querySelector('.data')?.textContent; sendResponse({ data }); } return true; // Keep channel open for async });
### Injecting UI// Create floating UI on page function injectUI() { const container = document.createElement('div'); container.id = 'my-extension-ui'; container.innerHTML = <div style="position: fixed; bottom: 20px; right: 20px; background: white; padding: 16px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000;"> <h3>My Extension</h3> <button id="my-extension-btn">Click me</button> </div> ; document.body.appendChild(container);
document.getElementById('my-extension-btn').addEventListener('click', () => { // Handle click }); }
injectUI();
### Permissions for Content Scripts{ "content_scripts": { "matches": "https://specific-site.com/"], "js": "content.js"], "run_at": "document_end" }] }
Persisting extension data
When to use: When saving user settings or data
javascript## Storage and State ### Chrome Storage API
// Save data chrome.storage.local.set({ key: 'value' }, () => { console.log('Saved'); });
// Get data chrome.storage.local.get('key'], (result) => { console.log(result.key); });
// Sync storage (syncs across devices) chrome.storage.sync.set({ setting: true });
// Watch for changes chrome.storage.onChanged.addListener((changes, area) => { if (changes.key) { console.log('key changed:', changes.key.newValue); } });
### Storage Limits
| Type | Limit |
|------|-------|
| local | 5MB |
| sync | 100KB total, 8KB per item |
### Async/Await Pattern// Modern async wrapper async function getStorage(keys) { return new Promise((resolve) => { chrome.storage.local.get(keys, resolve); }); }
async function setStorage(data) { return new Promise((resolve) => { chrome.storage.local.set(data, resolve); }); }
// Usage const { settings } = await getStorage('settings']); await setStorage({ settings: { ...settings, theme: 'dark' } });
Why bad: Users won't install. Store may reject. Security risk. Bad reviews.
Instead: Request minimum needed. Use optional permissions. Explain why in description. Request at time of use.
Why bad: MV3 terminates idle workers. Battery drain. Browser slows down. Users uninstall.
Instead: Keep background minimal. Use alarms for periodic tasks. Offload to content scripts. Cache aggressively.
Why bad: Selectors change. APIs change. Angry users. Bad reviews.
Instead: Use stable selectors. Add error handling. Monitor for breakage. Update quickly when broken.
Works well with: frontend, micro-saas-launcher, personal-tool-builder
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | fail→fail | 15,472 | 14,949 | -3% | 1 | 1 | 0% | 2,884 | 4,253 | +47% | 0 | 0 | — |
case-03 | pass→pass | 9,679 | 7,083 | -27% | 1 | 1 | 0% | 1,784 | 2,805 | +57% | 0 | 0 | — |
case-12 | pass→pass | 9,421 | 6,978 | -26% | 1 | 1 | 0% | 1,638 | 2,721 | +66% | 0 | 0 | — |
case-01 | fail→pass | 11,499 | 9,407 | -18% | 1 | 1 | 0% | 2,287 | 3,334 | +46% | 0 | 0 | — |
case-04 | pass→pass | 10,243 | 9,764 | -5% | 1 | 1 | 0% | 1,846 | 3,487 | +89% | 0 | 0 | — |
case-05 | pass→pass | 11,637 | 12,695 | +9% | 1 | 1 | 0% | 1,923 | 3,776 | +96% | 0 | 0 | — |
case-06 | pass→pass | 15,592 | 14,801 | -5% | 1 | 1 | 0% | 2,378 | 3,994 | +68% | 0 | 0 | — |
case-07 | pass→pass | 13,529 | 11,675 | -14% | 1 | 1 | 0% | 2,495 | 3,855 | +55% | 0 | 0 | — |
case-13 | fail→fail | 8,982 | 6,320 | -30% | 1 | 1 | 0% | 1,579 | 2,585 | +64% | 0 | 0 | — |
case-08 | pass→pass | 6,564 | 5,689 | -13% | 1 | 1 | 0% | 1,174 | 2,541 | +116% | 0 | 0 | — |
case-09 | pass→pass | 5,781 | 5,004 | -13% | 1 | 1 | 0% | 948 | 2,219 | +134% | 0 | 0 | — |
case-10 | pass→pass | 7,070 | 4,689 | -34% | 1 | 1 | 0% | 1,347 | 2,305 | +71% | 0 | 0 | — |
case-11 | pass→pass | 4,602 | 5,626 | +22% | 1 | 1 | 0% | 713 | 2,480 | +248% | 0 | 0 | — |
case-14 | pass→pass | 8,063 | 6,973 | -14% | 1 | 1 | 0% | 1,291 | 2,745 | +113% | 0 | 0 | — |
case-15 | pass→pass | 10,627 | 9,695 | -9% | 1 | 1 | 0% | 2,013 | 3,300 | +64% | 0 | 0 | — |
case-16 | pass→pass | 3,787 | 4,289 | +13% | 1 | 1 | 0% | 456 | 2,188 | +380% | 0 | 0 | — |
case-17 | pass→pass | 4,011 | 4,848 | +21% | 1 | 1 | 0% | 646 | 2,324 | +260% | 0 | 0 | — |
case-18 | pass→pass | 3,205 | 3,774 | +18% | 1 | 1 | 0% | 457 | 2,077 | +354% | 0 | 0 | — |
case-19 | pass→pass | 6,118 | 5,498 | -10% | 1 | 1 | 0% | 1,045 | 2,585 | +147% | 0 | 0 | — |
case-20 | pass→pass | 15,954 | 11,824 | -26% | 1 | 1 | 0% | 3,073 | 3,824 | +24% | 0 | 0 | — |
case-21 | pass→pass | 4,581 | 5,125 | +12% | 1 | 1 | 0% | 724 | 2,311 | +219% | 0 | 0 | — |
case-22 | pass→pass | 8,260 | 7,327 | -11% | 1 | 1 | 0% | 1,502 | 2,887 | +92% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.