Wxt
Skill ComeOnOliver/skillshub/skills/TerminalSkills/skills/wxt
π§ The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.From the repository description
npx -y skills add ComeOnOliver/skillshub --skill wxtAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
6.3 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
WXT
Overview
WXT is a Vite-based framework for building browser extensions β think "Next.js for extensions." File-based entrypoints, hot reload, TypeScript-first, and it outputs a single extension that works on Chrome (MV3), Firefox (MV2/MV3), Safari, and Edge. No more manually editing manifest.json or reloading the extension after every change.
When to Use
- Building a browser extension for Chrome, Firefox, or all browsers
- Want hot reload during development (not manual reload)
- Need TypeScript + React/Vue/Svelte in your extension
- Migrating from Manifest V2 to V3
- Want one codebase that targets multiple browsers
Instructions
Setup
npx wxt@latest init my-extension
cd my-extension
npm install
npm run dev # Opens Chrome with hot-reloading extension
Project Structure
my-extension/
βββ entrypoints/
β βββ popup/ # Popup UI (click extension icon)
β β βββ index.html
β β βββ main.tsx
β β βββ App.tsx
β βββ options/ # Options page
β β βββ index.html
β β βββ main.tsx
β βββ content.ts # Content script (runs on web pages)
β βββ background.ts # Service worker (background logic)
βββ public/
β βββ icon/
β βββ 16.png
β βββ 48.png
β βββ 128.png
βββ wxt.config.ts
βββ package.json
Content Script
// entrypoints/content.ts β Runs on matched web pages
/**
* Content scripts have access to the DOM of the page.
* Define which URLs to match with the `matches` export.
*/
export default defineContentScript({
matches: ["*://*.github.com/*"], // Run on GitHub pages
main() {
// Add a custom button to every GitHub PR page
const prHeader = document.querySelector(".gh-header-actions");
if (prHeader) {
const btn = document.createElement("button");
btn.textContent = "π€ AI Review";
btn.className = "btn btn-sm";
btn.onclick = async () => {
const diff = document.querySelector(".diff-view")?.textContent;
// Send to background for API call
const review = await browser.runtime.sendMessage({
type: "REVIEW_PR",
diff: diff?.slice(0, 5000),
});
alert(review.summary);
};
prHeader.prepend(btn);
}
},
});
Background Service Worker
// entrypoints/background.ts β Persistent background logic
/**
* Service worker handles API calls, alarms, and message routing.
* No DOM access here β communicate with content scripts via messaging.
*/
export default defineBackground(() => {
// Handle messages from content scripts
browser.runtime.onMessage.addListener(async (msg, sender) => {
if (msg.type === "REVIEW_PR") {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${await storage.getItem("local:apiKey")}`,
},
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: `Review this diff:\n${msg.diff}` }],
}),
});
const data = await response.json();
return { summary: data.choices[0].message.content };
}
});
// Periodic tasks with alarms
browser.alarms.create("check-notifications", { periodInMinutes: 5 });
browser.alarms.onAlarm.addListener(async (alarm) => {
if (alarm.name === "check-notifications") {
// Check for updates, show badge
const count = await checkNotifications();
if (count > 0) {
browser.action.setBadgeText({ text: String(count) });
}
}
});
});
Popup UI (React)
// entrypoints/popup/App.tsx β Extension popup with React
import { useState, useEffect } from "react";
export default function App() {
const [apiKey, setApiKey] = useState("");
const [saved, setSaved] = useState(false);
useEffect(() => {
storage.getItem<string>("local:apiKey").then((key) => {
if (key) setApiKey(key);
});
}, []);
const save = async () => {
await storage.setItem("local:apiKey", apiKey);
setSaved(true);
setTimeout(() => setSaved(false), 2000);
};
return (
<div style={{ width: 300, padding: 16 }}>
<h2>π€ AI PR Reviewer</h2>
<input
type="password"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
placeholder="OpenAI API Key"
style={{ width: "100%" }}
/>
<button onClick={save} style={{ marginTop: 8 }}>
{saved ? "β
Saved!" : "Save Key"}
</button>
</div>
);
}
Build for Multiple Browsers
# Development (Chrome with hot reload)
npm run dev
# Development for Firefox
npm run dev:firefox
# Build for all browsers
npm run build # Chrome MV3
npm run build:firefox # Firefox MV2/MV3
# Zip for store submission
npm run zip
npm run zip:firefox
Examples
Example 1: Build a productivity extension
User prompt: "Build a Chrome extension that blocks distracting websites during focus time."
The agent will create a WXT extension with a popup for configuring blocked sites and focus timer, a content script that shows a block page on matched domains, and background alarms for timer management.
Example 2: Content enhancement extension
User prompt: "Build an extension that adds AI-powered summaries to any article page."
The agent will create a content script that detects article content, a floating sidebar UI, and background API calls to summarize text.
Guidelines
- File-based entrypoints β file name and location determine the extension component
browser.*API β WXT polyfills Chrome and Firefox differences automaticallystoragehelper β type-safe extension storage withstorage.getItem/setItem- Hot reload works β
npm run devreloads content scripts and popup on save - MV3 service workers β background scripts are service workers (no persistent state)
matchesfor content scripts β define URL patterns where scripts should inject- Message passing β content script β background communication via
browser.runtime.sendMessage - One codebase, all browsers β build targets handle manifest differences
- Icons at 16/48/128px β required for Chrome Web Store
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.