Reference
Development and releases
Run it from source in Firefox, Zen and Chrome, and ship signed Firefox builds from your AMO developer account.
#Repository layout
extension/ the extension (Chromium manifest; Firefox's is generated)
background.js menus, shortcuts, panel hand-off, inline answers
sidepanel/ the panel (also the full-page chat)
options/ settings page
content/selection.js selection toolbar + answer card
content/site.js tells this site's install page the installed version
lib/providers/ catalog (every provider), claude.ai, your server,
the Bridge, OpenAI-compatible APIs
lib/models.js model families and depths for the picker
lib/brands.js maker logos (icons/brands, LobeHub Icons, MIT)
lib/scanner.js the working indicator
lib/extract.js page text, YouTube transcripts, links, screenshots
lib/markdown.js safe Markdown renderer
styles/theme.css tokens shared with this site
bridge/chromind-bridge.mjs the Bridge (one file, no dependencies)
scripts/ build, pack, sign, docs, icons, version
site/ this documentation
tests/ node --test unit tests + Playwright end-to-end test
#Run from source
npm install
npm test
Chromium: chrome://extensions → Developer mode → Load unpacked → the extension/ folder.
Firefox / Zen:
npm run dev:firefox # web-ext run with a fresh Firefox profile
npm run dev:zen # same, in Zen Browser
Or build once with npm run build and load dist/firefox/manifest.json from
about:debugging#/runtime/this-firefox → Load Temporary Add-on. npm run lint:firefox runs Mozilla's
linter on the Firefox build.
#One codebase, two browsers
| Chromium | Firefox | |
|---|---|---|
| Panel | side_panel + sidePanel permission | sidebar_action |
| Background | service worker (module) | event page (module) |
| Toolbar button | openPanelOnActionClick | sidebarAction.toggle() |
| Open shortcut | _execute_action | _execute_sidebar_action |
| Card → panel | message from the content script (the click's gesture carries over) | the button is content/continue.html, a web-accessible frame that calls sidebarAction.open() |
| Panel requests | port panel, then a panel-request broadcast when the background restarted and the port is gone | |
| Identity, updates | none | browser_specific_settings.gecko: id, update_url, data collection |
scripts/extension-files.mjs writes the Firefox manifest from the Chromium one at build time, so there's one
manifest to edit. Code uses browser ?? chrome and feature-detects the panel APIs
(lib/browser.js). Both browsers only open the panel inside a user gesture, so menu and shortcut handlers call
openPanel() first, before any await.
#Packages
npm run pack
| File | For |
|---|---|
dist/chromind-chrome.zip | Load unpacked, or upload to the Chrome Web Store |
dist/chromind-firefox-unsigned.xpi | Firefox before signing |
dist/chromind-*.json | Version info the install page reads |
dist/chromind-bridge.mjs | The Bridge download |
#Signing for Firefox (your AMO account)
Release Firefox only installs signed add-ons. ChroMind is signed as an unlisted add-on from your addons.mozilla.org developer account: Mozilla signs it, but it's offered only from this site, not the add-ons store. Same setup as YTMQ.
- Create API credentials on your AMO developer profile: addons.mozilla.org/developers/addon/api/key. You get a JWT issuer and a JWT secret.
-
Add them as GitHub secrets on the repository:
gh secret set AMO_JWT_ISSUER -R T3lluz/ChroMind gh secret set AMO_JWT_SECRET -R T3lluz/ChroMind -
Turn on GitHub Pages with Source: GitHub Actions (Settings → Pages). Every push to
mainruns.github/workflows/pages.yml: tests, packages, signs the Firefox build and deploys this site with the downloads and Firefox's update manifest.
The add-on id is chromind@t3lluz.com. The first signed upload creates the add-on on your account; later ones
add versions. Mozilla takes each version number once, so ship a Firefox update by bumping the version:
npm run release -- patch # or minor, major, 1.2.3
git commit -am "Release v0.3.1" && git push
If the version is already on AMO, the workflow downloads that signed build instead of uploading again. Installed copies
pick up new versions through update_url
(https://t3lluz.github.io/ChroMind/chromind-firefox-updates.json).
Sign locally instead:
npm run pack
AMO_JWT_ISSUER=user:123:456 AMO_JWT_SECRET=… npm run sign:firefox
Hosting the site elsewhere (say t3lluz.com/chromind)? Set CHROMIND_SITE when packing so the Firefox update_url points there.
#Docs and screenshots
npm run dev:site # http://localhost:4173/ChroMind/
npm run screenshots # Playwright: loads the extension, refreshes site/assets/screens
npm run test:e2e # the same run without screenshots; starts its own Bridge
Docs pages are plain HTML in site/pages/ with a short front-matter comment for title, group and order.
#Adding a provider
- Describe it in
PROVIDERSinlib/providers/catalog.js(name, brand logo, access badge, blurb). An OpenAI-style API with a key needs onlybaseUrlandkeyUrl. - Give it a branch in
loadModels(),isReady()andrunChat()inlib/providers/index.jsif it's anything else. - Add defaults in
lib/settings.js, and fields inoptions/options.jsif it needs more than a key. - If it's an app on the computer, add it to the Bridge instead: a
provider/modelprefix, spawn arguments (never prompt text through a shell), a stream parser and status detection.