The module system
The kit ships as the full repo; the setup wizard prunes the modules you
don’t keep. What makes that safe is a contract: every prunable feature
module carries a module.json manifest declaring everything it owns
(code, npm dependencies, env vars, manifest permissions, and docs). One
declaration removes all of it together.
Manifests live at the package root for workspace packages
(packages/gate/module.json) or under
apps/extension/modules/<id>/module.json for app-level modules
(broadcasts, error-reporting, content-demo, demo-newtab, demo-devtools),
validated against tooling/config/module.schema.json.
Anatomy of a manifest
Section titled “Anatomy of a manifest”{ "$schema": "../../tooling/config/module.schema.json", "id": "billing", "title": "Billing & entitlements", "description": "Stripe checkout/portal routes, webhook-written entitlements, useEntitlement('paid').", "files": ["packages/core-billing/**", "backend/functions/src/billing/**"], "dependsOn": ["auth"], "npmDependencies": { "@extensionstart/core-billing": "workspace:*" }, "env": [{ "name": "WXT_API_URL", "description": "deployed Functions base URL" }], "permissions": [], "wiring": ["apps/extension/entrypoints/background/index.ts"], "docs": []}filesglobs are repo-root-relative; a module can own files outside its package (the auth module ownsapps/extension/entrypoints/offscreen/**).dependsOnis by module ID. The resolver keeps dependencies of any kept module (keepinggateforce-keepsbilling) and drops dependents of any dropped one (droppingbillingdropsgatetoo).- Core modules set
"removable": false; the wizard never offers to prune them. - Shared last-owner rule: env vars and permissions listed by several
modules (e.g.
WXT_API_URL) are pruned only when no kept module lists them. permissionsis why the generatedmanifest.jsonshrinks when you prune: each module declares thechrome.*permissions and host patterns it needs, and a smaller permission surface means a faster, safer store review.
Wiring markers
Section titled “Wiring markers”A module’s code often touches shared files it doesn’t own: the background import order, the messaging protocol, surface roots, e2e specs. Those touchpoints carry marker comments so the pruner can strip them without codemods:
- Line marker: a
// module:<id>suffix (or{/* module:<id> */}in JSX,/* module:<id> */in CSS) removes that single line when<id>is dropped. - Block marker: everything from a line containing
module:<id>:startthrough the line containingmodule:<id>:end(inclusive) is removed. Blocks of different modules may nest.
Each manifest lists the shared files carrying its markers under wiring;
the pruner strips exactly those files. The hard pass criterion: any
prune combination leaves pnpm typecheck and pnpm lint green with zero
dangling imports.
Backend files stay
Section titled “Backend files stay”Manifests list backend files a module owns as documentation of ownership,
but the pruner leaves backend/** in place. The Hono app is one
self-contained function; unused routes are harmless, and deleting
them would require invasive edits to the backend entrypoint. Delete them
manually if you want a minimal backend.
Adding your own module
Section titled “Adding your own module”- Create the manifest (
apps/extension/modules/<id>/module.jsonfor an app-level feature) withid,title,description, andfilesglobs for everything the module owns. - Where your module touches shared files (adding an import to
background/index.ts, a message to the protocol, a component to a surface), tag each touchpoint with a// module:<id>line marker or amodule:<id>:start/module:<id>:endblock, and list those files underwiring. - Declare
npmDependencies,env(names must exist inapps/extension/.env.example),permissions, anddependsOnas they apply. - Keep the manifest in sync: adding a file, dependency, env var, or
permission to the module means updating its
module.jsonin the same change. - Prove it prunes cleanly:
Then, on a scratch branch, run a real prune that drops your module and check
Terminal window pnpm create extstart --dry-run --keep none # your module in the plan?pnpm typecheckandpnpm lintstay green.
