Skip to main content
Auric Artisan · Documentation

Auric Artisan Browser Extension Developer Reference

Published: May 26, 2026 Updated: September 26, 2026 Runtime: Extension 1.0.2 Audience: Extension maintainers Author: Chirag Bansal
Back to Documentation Auric Artisan Home

Overview

Source-level reference for maintaining the Auric Artisan browser extension, version 1.0.2. It maps how one source tree under extension/ becomes generated manifests for Chromium and Firefox, the three runtimes and the messages between them, the settings and storage keys, the accessibility engine, translation, and the build, test and release commands that keep it shippable.

Table of contents

  1. 1. Runtime overview
  2. 2. Source layout
  3. 3. Manifest generation and permissions
  4. 4. Popup shell, surfaces and spaces
  5. 5. Search and settings
  6. 6. Storage contract
  7. 7. Background worker
  8. 8. Content script and message protocol
  9. 9. Color engine and contrast math
  10. 10. Accessibility engine and audit overlay
  11. 11. Tool panel responsibilities
  12. 12. Shared components and injected UI
  13. 13. Translation and locales
  14. 14. Permissions, privacy and security
  15. 15. Build, test and release
  16. 16. Validation checklist

1. Runtime overview

+

The extension is one source tree that builds four apps for two browser engines. Only the suite, named Auric Artisan, is published; color, a11y and devtools set published: false and stay as internal build targets. There is no bundler and no transpiler: the source is the shipped JavaScript, and the build copies files, writes manifests and checks the result.

At run time there are three pieces. The background worker owns the browser's own right-click items, keyboard commands, the badge and privileged relays. One extension page, popup.html, holds every tool and is shown as the toolbar popup, the Chromium side panel, the Firefox sidebar or a separate window. The content script owns everything drawn on a web page. Nothing depends on a server; the only outbound traffic is a page the user chooses to open.

Layer Primary responsibility
packages/runtime/background.js Service worker on Chromium, event page on Firefox: browser right-click items, commands, install page, badge, relays for the in-page menu, side panel tracking.
packages/popup/popup.html and popup.js Every tool, the search, Settings, the tour; one page for every surface.
packages/runtime/content.js Declared on every page; vision filters, the inspector, the contrast scan, and lazy imports of the pickers, the right-click menu, the audit overlay and the a11y engine.
packages/runtime/page-overlay.js The audit overlay: boxes, numbered pins, the finding card and the page dock, in a shadow root.
packages/a11y/engine.js The 80-rule WCAG 2.2 engine, imported into the page when an audit runs.

The version is 1.0.2 for every app. Section 15 notes which parts of the current source the changelog still lists as Unreleased.

2. Source layout

+
  • extension/version.json: the one version every manifest reads.
  • extension/apps/<id>/app.config.mjs: id, name, shortName, brand, geckoId, description (132 characters at most), tabs, defaultTab, features.a11yEngine, published and commands.
  • extension/build/build.mjs: the CLI that copies, composes, localizes, validates and zips. extension/build/compose.mjs: buildManifest(), manifestMessages(), buildMessages() and filterPopup().
  • extension/shared/fonts/: Manrope and Fraunces. extension/store/: listing copy, artwork and permission justifications. extension/docs/: the extension's own documentation and decision records.
  • extension/dist/<target>/<app>/: build output, git-ignored, plus auric-<app>-<target>-<version>.zip when zipping.
Package Contents
packages/popup popup.html, popup.js, theme.css, shell.css, tools.css, app-scope.js, finding-bridge.js
packages/runtime background.js, content.js, page-overlay.js, color-picker.js/.css, pickers.js, date-core.js, context-menu.js, overlay-host.js, overlay.css, qr.js
packages/ui combo.js/.css, the popup's dropdown
packages/core dom.js, events.js, utils.js, and finding.js (one finding model for audit, contrast and inspector results)
packages/i18n boot.js, i18n.js, rules.js, overlay.js, locales/hi.json, locales/patterns.hi.json
packages/a11y engine.js, rules/*.js, accname.js, contrast.js, dom-utils.js, store.js, analysis*.js
packages/data wcag22.js, aria12.js, html-aam.js, autocomplete.js
packages/brand marks.mjs, icons/<brand>/; legacy-icons/ is never shipped
App Name Tools
suite Auric Artisan (published) All 18, default pick
color Auric Color 12: the eight Colour-space tools, contrast, history, library and launch; default pick
a11y Auric Accessibility scan, contrast, vision, inspect, history, launch; default scan
devtools Auric Developer inspect, tokens, snippets, pick, convert, contrast, library, launch; default inspect

The build copies flat: packages/popup, ui and runtime land at the bundle root; core/, i18n/, fonts/ and the brand's icons/ land in folders of those names; a11y/ and data/ are added only when features.a11yEngine is set (the suite and the a11y app).

3. Manifest generation and permissions

+

There is no manifest in the source tree. buildManifest(app, { version, target }) in compose.mjs writes extension/dist/<target>/<app>/manifest.json from MANIFEST_BASE and the app config. The manifest's description, action title, sidebar title and command descriptions are __MSG_…__ placeholders resolved from generated _locales/en and _locales/hi, with default_locale: "en".

Field Chromium (chrome) Firefox (firefox)
Background service_worker: "background.js" scripts: ["background.js"] (event page)
Workspace side_panel.default_path: "popup.html" sidebar_action.default_panel: "popup.html"
Permissions activeTab, scripting, storage, clipboardWrite, contextMenus, sidePanel The same without sidePanel
Optional permissions clipboardRead, downloads, sessions, requested at run time when the custom right-click menu is turned on
Host access <all_urls>
Content scripts content.js only, on <all_urls> at document_idle, all_frames: false
Web-accessible resources The runtime modules and CSS, the i18n engine and dictionaries, the two fonts and core/*.js, plus a11y/*.js, a11y/rules/*.js and data/*.js in builds with the engine. No use_dynamic_url: with it, the content script's import() calls fail on every site.
Gecko settings Not used id from geckoId (the suite: [email protected]), strict_min_version: "115.0", data_collection_permissions: { required: ["none"] }
Suite command Default key Handled as
_execute_action Alt+Shift+A Opens the popup
open-contrast Alt+Shift+C Queued popup route to contrast
extract-palette Alt+Shift+E Queued route to palette, clicking aa-extract-btn
toggle-vision Alt+Shift+V aa-vision-toggle (deuteranopia) to the page
inspect-element None aa-inspect-start to the page
run-a11y-audit None Queued route to scan, clicking aa-scan-run

The focused apps carry their own commands: the a11y app binds run-a11y-audit to Alt+Shift+R, and the devtools app binds inspect-element to Alt+Shift+I and adds extract-tokens without a key. The build fails on a description over 132 characters (the source or any translation), a key claimed twice, a Firefox manifest without data_collection_permissions, a referenced file missing from the bundle, an absolute path in popup.html, a declared tab with no panel, or a default tab that is not declared. Permission changes are user-visible in the stores and belong in the changelog.

4. Popup shell, surfaces and spaces

+
  • Surfaces. popup.js sets html[data-surface] before first paint: panel when the URL has ?surface=panel, otherwise popup. background.js points the side panel (sidePanel.setOptions) or sidebar (sidebarAction.setPanel) at popup.html?surface=panel, and the window button opens the same URL with windows.create as a 620 × 700 popup window.
  • Tab registry. A hidden nav.aa-tabs holds one button.aa-tab[data-tab] per tool, and each tool is a <section class="aa-panel" data-panel="…">. filterPopup() removes the buttons of tools an app does not ship, marks their panels data-app-excluded="true" (the markup stays because popup.js binds listeners to it at load), activates the default tab and writes data-app, data-tabs and data-default-tab on <body>. app-scope.js stops a restored tab from showing an excluded tool. Keep class before data-panel on each section; the filter's pattern depends on that order.
  • Spaces. SPACES lists Home plus four spaces; TOOL_META gives each tool its label and icon. A space whose tools are all excluded from a build is hidden.
  • Side panel layout. adoptPanelLayout() moves the theme and Settings buttons into the rail and opens a port named aa-panel to the background, posting its window id.
  • Home. renderDashboard() draws HOME_ACTIONS.popup (Pick a colour, Contrast, Inspect, Audit this page) as a launcher in the popup, and HOME_ACTIONS.panel (Pick, Inspect, Audit, Vision) inside the tab card on the panel surface, with the colour of the day, the page's colors, recent colors, Continue, pinned tools and site links.
  • Scripts. i18n/boot.js runs in the head; then the classic scripts popup.js, app-scope.js and combo.js, then the modules color-picker.js and finding-bridge.js, which publish window.AAColorPicker and window.AAFinding for the classic code.
  • Styles. theme.css is the only token deck (--aa-*, per theme on html[data-aa-theme]); shell.css covers the chrome, tools.css the tool panels, combo.css the dropdown and color-picker.css the picker.
Space tools deep (opened from another tool or search)
colour pick, palette, image, gradient, blender harmony, shades, convert
check contrast, vision, scan, findings —
code inspect, tokens, snippets —
saved library, history launch

5. Search and settings

+

Search is backed by COMMANDS in popup.js: 29 entries of type panel, launch (an auricartisan.com route) or click (a header button). commandIsAvailable() hides panel commands whose tab the build removed, and onPage: true flags tools that need a web page. SETTINGS_INDEX adds 15 settings, each with settingTab and settingControl so a result opens Settings at the control. Every typed word must match the title, description, group or keywords, in English or translated; an exact title ranks first. Add a COMMANDS entry, a SPACES slot and a TOOL_META label with every new tool.

Settings live in one object under aa_settings, initialized from DEFAULT_SETTINGS. On load, stored values are merged over the defaults and pickers is merged key by key, so a new picker type starts on. content.js keeps its own copy of the defaults it needs.

Key Default Effect
themeMode'dark'system, light or dark
accentColor'#d3af37'The accent tokens, in the popup and in page overlays
uiSize'normal'compact, normal or large popup size
lang'en'en or hi
copyFormat'hex'hex, rgb, hsl or oklch
naming'css'css, xkcd or off
history, apca, contexttrue Keep history; show APCA; items in the browser's right-click menu
soundfalseA beep on pick or copy
customPickersfalseMaster switch for the website pickers
pickersall truePer type: color, select, date, time, datetime, month, week, number, range, multiselect, datalist, file, checkbox, radio
pickersRespectSitetrueLeave designed controls alone
pickerExcludeHosts, cmExcludeHosts[] Never-on sites for pickers and for the custom menu
customContextMenufalseThe in-page right-click menu
cmStepAsidetrueYield to a site's own right-click menu
scanDeeptrueContrast-scan limits: 3,500 elements and 160 issues, or 1,800 and 80
scanAutoOutlinefalseOutline findings right after an audit
replaceNativePickers, pickersUnifiedfalse Legacy color-input switch and a one-time migration marker
onboardedfalseSet when the first-run tour closes

Imported settings pass through sanitizeImportedSettings(): enums must be known values, booleans must be booleans, accentColor must be a 6-digit hex, only known picker keys survive, and host lists are cleaned, de-duplicated and capped at 100. A new setting needs a default, a control, an importer rule and a SETTINGS_INDEX entry.

6. Storage contract

+
Key Store Shape and limits
aa_settingsstorage.localThe settings object above.
aa_historystorage.localPicked hex colors, newest first, capped by HISTORY_MAX = 50.
aa_lib_colorsstorage.localLibrary colors, up to LIB_COLORS_MAX = 500; the badge counts them.
aa_lib_palettesstorage.local{id, colors[], label?}; saves keep the newest 30, a restored backup up to 100 palettes of up to 64 colors.
aa_snippetsstorage.local{id, type, title, code, url, host, ts}; 200 snippets, code up to 20,000 characters.
aa_pinned_toolsstorage.localCommand ids pinned on Home, up to 8; default pick-color, palette, contrast, shades.
aa_last_toolstorage.local{panel, ts} for Home's Continue.
lastPickstorage.localThe last picked hex.
aa_cm_prefsstorage.local{quick, labels, layout, density} for the custom menu; the quick bar holds 6. Kept apart from aa_settings so menu writes do not rebuild every tab's menu.
aa_pending_commandstorage.local{panel, action, createdAt} written by the background; read once, ignored after 30 s.
aa_last_inspectstorage.localThe pinned inspector snapshot (schemaVersion: 2), bounded to 512 KB.
aa_lang, aa-space-tools, auric-cp-* Extension-page localStorageThe language mirror read at boot, the last tool per space, and the color picker's recent colors and layout choices.

Nothing is synced and nothing injected into a website reads or writes that site's storage. Audit results live only in popup memory. a11y/store.js defines an IndexedDB database (auric-a11y) for scan history and ships in engine builds, but no runtime code imports it, so no database is created. Backups (kind: "aa-backup", schema: 1) carry settings, history, library colors, palettes and snippets. Prefer additive schema changes and update the importer with every shape change.

7. Background worker

+

background.js normalizes browser and chrome, and keeps its logic small and event-driven; page analysis runs in the content script.

  • runtime.onInstalled opens https://auricartisan.com/?utm_source=extension&utm_medium=install on first install, then builds the browser menu, refreshes the badge and flags the panel surface. onStartup repeats the last three.
  • The MENU items aa-inspect, aa-extract, aa-scan, four aa-vision-* simulations and aa-vision-clear are built on the page and action contexts while settings.context !== false, with Hindi titles from the bundled dictionary when lang is hi.
  • sendContentMessage(tabId, message) tries tabs.sendMessage, then injects overlay.css and content.js with scripting and retries once, which covers tabs opened before the install.
  • queuePopupAction(panel, action) writes aa_pending_command and calls action.openPopup(); the popup opens that panel and clicks the button whose id is action.
  • Relays for the in-page menu: aa-perms, aa-download, aa-view-source, aa-open-window, aa-new-tab, aa-reload-bypass, aa-capture, aa-tab (reopen, duplicate, pin-toggle, mute-toggle, close) and aa-zoom (0.25–5). URLs pass safeUrl(), which allows only http:, https:, data: and blob:.
  • Side panel tracking: panel pages hold an aa-panel port and post their window id; aa-panel-open answers whether the sender's window has one, and aa-open-panel opens the panel (or Firefox sidebar) inside the click's user gesture and queues the requested tool.
  • aa-set-context builds or clears the browser menu; storage.onChanged on aa_settings rebuilds it too.
  • refreshBadge() shows the Library color count on #d3af37, as 99+ above 99.

8. Content script and message protocol

+

content.js runs in the isolated world, guarded by window.__auricArtisanLoaded so a second injection does nothing. It merges aa_settings over its defaults and, on load and on every change, applies the theme, the language, the color picker, the website pickers and the right-click menu in that order. Heavy modules are imported with import(runtime.getURL(…)) only when needed: color-picker.js for color-input replacement, pickers.js when customPickers is on and the host is not excluded, context-menu.js when customContextMenu is on, page-overlay.js for audit outlines, a11y/engine.js on aa-scan-page, and the i18n engine for Hindi.

Message to the page Payload Effect and reply
aa-visionfilter or null, strength 0–1Apply or clear a filter; {ok}
aa-vision-togglefilter?Clear if active, else apply (default deuteranopia); {ok, active}
aa-vision-sidefilterToggle the side-by-side comparison; {ok}
aa-scan-outline{options} or {clear: true}Draw the audit overlay from a contrast scan (the list's options, so pins and rows number alike), or close it; {ok, scan}
aa-audit-selectindexSelect a pin and open its card; {ok}
aa-scan-pageoptions: {limit, issueLimit} Contrast scan plus the full audit; {ok, scan, a11y}, with a11y: null in builds without the engine
aa-inspect-startsourceTabId, inspectSessionId, pageUrlStart inspecting; {ok, sourceTabId, inspectSessionId}
aa-inspect-stopsessionStop and undo previews; {ok, restored, snapshot}
aa-inspect-highlightselector + session Pin an element; {ok, snapshot}
aa-inspect-navigatedirection + session parent, child, previous or next; {ok, snapshot}
aa-inspect-apply-css, aa-inspect-reset-css selector, cssText + sessionApply or undo a reversible inline-style preview
aa-picker-replacementenabledTurn color-input replacement on or off

Every aa-inspect-* message except aa-inspect-start must carry the session that started the inspector, or it is refused, so a stale popup cannot drive a page it no longer describes. The page reports back to the popup and panel with runtime.sendMessage: aa-audit-selected (index) when a pin is selected on the page, and aa-audit-closed when the overlay closes. The inspector asks the background aa-panel-open when it starts, and keeps a compact card on the page when the panel will show the details.

9. Color engine and contrast math

+
  • Popup math. popup.js holds the conversions (sRGB and linear, HSL, HSV, CMYK, LAB, LCH, OKLAB, OKLCH, HWB), the CSS named-color map, WCAG ratios and APCA Lc. Keep these helpers deterministic and side-effect free; Contrast, Page palette, Harmony, Scale, Gradient, Mix and Convert all reuse them.
  • The Picker. runtime/color-picker.js is the website's js/components/color-picker.js plus extension-only safety. Its FORMATS are HEX, RGB, HSL, HSV, HWB, CMYK, LAB, LCH, OKLAB, OKLCH, XYZ and P3, and its sections are Specs, Harmony, Scale, Contrast, Vision, Code, Page and Recent.
  • WCAG rows. AA Body 4.5, AA Large 3, AAA Body 7, AAA Large 4.5, AA UI 3 and Gfx 3. APCA tiers are Lc 90, 75, 60, 45 and 30.
  • Fixes. Targets are AA 4.5:1, AA Large 3:1, AAA 7:1, APCA Lc 60 and APCA Lc 75. huePreservingFixes() walks lightness out from the base color, keeping hue and saturation, and returns up to six passing candidates for text and for background.
  • Contrast scan. runContrastScan() in content.js composites backgrounds up the tree. Text is large at 24 px or more, or 18.66 px bold; the threshold is 3:1 for large text and 4.5:1 otherwise. A pair within 1.5 of its threshold, or over a background image or text shadow, is a warning or manual review.
  • Page palette. extractPaletteInPage() runs in the tab through scripting.executeScript: up to 6,000 elements, 12 color properties, custom properties weighted three times, the top 48 kept; clusterPalette() merges near-duplicates and the Dominant mode clusters to eight.
  • Gradients. interpolatedStops() writes 13 stops for the OKLCH and HSL options; the OKLCH option mixes in OKLab.

When changing color math, check every tool that copies, exports or stores color data: one helper feeds previews, accessibility results and saved library payloads at the same time.

10. Accessibility engine and audit overlay

+
Fact Value
Sourcepackages/a11y/ with the standards data in packages/data/
Rules80 in 8 categories (aria 17, names 5, structure 12, forms 10, media 13, keyboard 8, contrast 4, document 11): 59 per element, 21 page-level
Levels69 at A, 9 at AA, 2 at AAA; the audit runs at level AA, so 78 rules run
Options passed by content.jslevel: 'AA', timeoutMs: 30000, maxElementsPerRule: 25000, maxIssuesPerRule: 250; the engine yields every 12 ms (sliceMs)
Shipped inBuilds with features.a11yEngine: the suite and the a11y app
Exportsaudit(), auditStream(), serializeReport(), DEFAULTS, ELEMENT_RULES, PAGE_RULES
  • Every rule skips the extension's own UI (OWN_UI_SELECTOR in a11y/dom-utils.js: the vision overlays, the color picker and [data-aa-overlay]). A rule that throws is recorded in ruleErrors and the audit carries on.
  • The engine's limits are separate from scanDeep, which sets the fast contrast scan's limit and issueLimit (3,500 and 160, or 1,800 and 80). Called without options, the scan defaults to 2,600 elements and 120 issues; aa-scan-outline raises the issue default to 250.
  • core/finding.js maps audit issues, contrast results and scan issues onto one finding shape (fromA11yIssue, fromContrastResult, fromScanIssue), which the Findings tool sorts by severity.
  • runtime/page-overlay.js draws the outlines in its own shadow root through createOverlayHost(), built with createElement only. Pins are numbered in the list's order; the selected finding's card offers the nearest passing text color, Try the fix (an inline color preview put back on undo or close), Copy CSS and Next; the dock closes with Done or Escape. No class, attribute or style of the page is otherwise touched.
  • a11y/store.js (IndexedDB scan history) and the analysis*.js helpers are shipped and tested but not imported by any runtime code yet.

11. Tool panel responsibilities

+
Panel id (label) Runtime contract
pick (Picker)Mounts the color picker (split in the popup, stack in the panel); eyedropColor() tries the popup's EyeDropper, then one run in the page with scripting; updates history and lastPick.
palette (Page palette)Page extraction, four modes, strip or grid, clipboard exports, SVG copy, PNG and ASE downloads, Save and Open.
image (Image)Reads 6, 8, 12 or 16 colors from a dropped, pasted or browsed image, or from captureVisibleTab.
harmony, shades, convertDeep tools behind the Picker: nine harmony schemes, Tailwind/Material/tint/shade/tone scales with exports, and the ten-field converter.
gradient, blender (Mix)Linear, radial and conic gradients with sRGB, OKLCH and HSL interpolation; mixing in sRGB, Linear RGB, LAB, OKLAB or HSL and six blend modes.
contrastWCAG rows, APCA tiers and readable sizes, a color-vision check, fixes, suggestions, Swap and Copy report.
visionSends aa-vision and aa-vision-side; Capture downloads the visible tab as a PNG.
scan (Audit)Sends aa-scan-page with the scanDeep limits, renders the score, counts and numbered rows, drives the overlay with aa-scan-outline and aa-audit-select, and copies JSON or CSV.
findingsPools audit, contrast and inspector findings through window.AAFinding.
inspectDrives the aa-inspect-* messages and renders Overview, Styles, A11y, DOM and Live CSS from the snapshot.
tokensReads up to 4,000 elements: 240 custom properties, 8 fonts and 16 type sizes; exports CSS, W3C tokens, Tailwind @theme or JSON.
snippetsThe aa_snippets vault: search, This site, Copy all, Export file, Clear all.
history, libraryStored picks, saved colors and palettes, JSON export to the clipboard.
launch (On the web)Fourteen auricartisan.com routes, each in a new tab.

12. Shared components and injected UI

+
  • color-picker.js exports ColorPicker, createColorPicker, mountInlinePicker, initAllColorPickers, enableAutoColorPickers, disableAutoColorPickers, configureColorPickers, setColorPickerTheme, parseColor and colorMath. It has three shapes: a 296 px popover on color inputs, split in the popup's Picker, stacked in the side panel. An input with data-cp-skip is never replaced, and it persists only on extension pages, never on a visited site.
  • pickers.js is an enhancer registry ({type, selector, match, create}) for select, date, month, number, range, time, week, datetime, file, multiselect, datalist, radio and checkbox. Values are written with setNativeValue() plus real input and change events; lists longer than SEARCH_THRESHOLD = 7 get a search field; one debounced MutationObserver tracks the page.
  • ui/combo.js enhances the popup's own select[data-aa-combo] dropdowns with the same search rule.
  • overlay-host.js: createOverlayHost({id, theme, accent}) returns {mount, place, setTheme, destroy}, a zero-size host on document.documentElement with an open shadow root and an all: initial reset. Hosts in use include #aa-pickers, #aa-color-pickers and #aa-context-menu.
  • context-menu.js builds one scene per right-click (edit, colour, selection, image, media, link, page or element), keeps its quick bar and layout in aa_cm_prefs (default quick bar back, forward, reload, copy-url, copy-shot), offers Inspect in side panel outside Firefox, and stands down on Shift, a page that already handled the event (with cmStepAside), data-aa-no-ext-menu, data-native-context-menu, <meta name="auric-extension-menu" content="off">, [data-aa-own-menu] and auricartisan.com. It uses createElement only, so it works under Trusted Types.
  • core/dom.js, core/events.js and core/utils.js are small shared helpers; core/finding.js is the finding model.

Injected UI follows fixed rules: floating UI lives in a shadow root; anything that must sit in the page is inline-styled; nothing touches the site's storage; the host page is never translated; the audit never audits the extension; and turning a feature off tears down all of its listeners, observers and replaced controls.

13. Translation and locales

+
  • Runtime engine. packages/i18n/i18n.js translates by text: a key is the whitespace-collapsed English of a segment, a text node or a translatable attribute, looked up in locales/hi.json and then in the patterns of locales/patterns.hi.json. Re-running over translated DOM matches nothing, which keeps its MutationObserver from looping.
  • Boot. boot.js imports the engine and dictionary only when the language is not English; aa_settings.lang is the setting and the aa_lang localStorage mirror stops a Hindi popup from painting English first.
  • Pages. In a content script the engine starts with no root; only surfaces registered through i18n/overlay.js are translated, never the host page. Values, format names and standard names are marked data-no-i18n.
  • Browser strings. manifestMessages() and buildMessages() generate _locales/en and _locales/hi from the same hi.json, following the browser's own language. The background translates its eight menu titles with a flat lookup in the same dictionary.
  • Workflow. npm run i18n:extension harvests strings and reports missing Hindi; add the translation to hi.json, or a pattern for strings built from live values.

14. Permissions, privacy and security

+
Permission Why it exists
<all_urls> host access The content script and the page tools act on whatever page the user is on.
activeTab The current tab when the user opens the popup, a shortcut or a menu item.
scripting sendContentMessage's fallback injection, the in-page eyedropper and palette extraction.
storage Settings, history, library, snippets, pinned tools, menu preferences and the last inspection.
clipboardWrite Copy buttons in the popup and in page overlays.
contextMenus The items in the browser's own right-click menu.
sidePanel (Chromium) The docked workspace; Firefox's sidebar_action needs no permission.
clipboardRead, downloads, sessions (optional) Paste, Save as and Reopen closed tab in the custom menu, requested only when it is turned on; aa-perms reports which are granted.

The privacy model has no network requests of its own (no analytics, telemetry or remote code), no accounts, no writes to a website's storage, and page-changing features that are opt-in. Outbound navigation is limited to the welcome page opened once on install and pages the user chooses: auricartisan.com links, the palette's Open, and web search and Google Translate from the custom menu. The Firefox manifest declares data_collection_permissions: { required: ["none"] }; the policy is the extension privacy policy.

Security measures: allow-listed URL schemes for privileged relays, a translation gate that rejects scripts, styles, frames, forms, event handlers and javascript:, validated backups, a 512 KB cap on the inspector snapshot, reversible Live CSS, queued commands that expire after 30 seconds, session-bound inspector messages, and no inline script in extension pages.

15. Build, test and release

+
npm run extension:build                          # every app, both targets
npm run extension:build -- --app suite --target chrome
npm run extension:build:zip                      # --zip --published: store zips for the suite
npm run test:extension:full                      # build, both suites, brutal a11y fixtures
Script What it does
extension:buildnode extension/build/build.mjs; flags --app, --target, --published, --zip
extension:build:zipWrites auric-suite-chrome-<v>.zip, byte-identical -edge- and -opera- copies, and auric-suite-firefox-<v>.zip
extension:icons, extension:store, extension:screenshotsRegenerate the icons, the store artwork and the documentation images (the last two from the built suite)
i18n:extensionHarvest strings and report missing Hindi
test:a11y, test:a11y:runtests/a11y/, with or without a build first
test:extension, test:extension:run tests/extension/, with or without a build first
test:extension:stressBuild, then runtime-stress.test.js
test:extension:fullBuild, both suites, then the analyzer's brutal a11y fixtures
a11y:sync, a11y:sync:checkCopy packages/data into the VS Code package, or check for drift

Version and changelog. extension/version.json is the only place the version lives; bump it there. 1.0.2, dated 2026-09-23, is the latest release in extension/CHANGELOG.md. The source also contains work the changelog lists under Unreleased: the side panel as home base with its rail, the popup as a quick launcher, the audit drawn by runtime/page-overlay.js with numbered pins, a finding card and a page dock, the inspector handing its details to the side panel, the Inspect in side panel menu action, and the aa-panel port with aa-panel-open and aa-open-panel. A build from source therefore reports 1.0.2 but includes that work, while a store install can still show the earlier layout. At release, rename Unreleased to the new version and date and bump the version.

Before uploading, lint the Firefox zip with npx addons-linter; it must report no errors. Chrome, Edge and Opera take the Chromium zip, and Brave and Vivaldi install from the Chrome listing. Safari is not built here: run xcrun safari-web-extension-converter extension/dist/chrome/suite on macOS and build the generated Xcode project; Safari has no side panel or sidebar.

16. Validation checklist

+
  • Run npm run extension:build before any test; the suites load extension/dist/chrome/<app>/, and a stale build passes tests that test nothing.
  • tests/a11y/build.test.js: manifests and filtered popups for 4 apps × 2 targets. tests/extension/background-commands.test.js: every declared command is routed.
  • The popup audits itself with the bundled engine (score 97 or more, no critical or serious failures, in tests/a11y/extension.test.js), and axe-core must report no violations over every panel (popup-accessibility.test.js).
  • The side panel must not scroll sideways from 280 px up (sidebar-responsive.test.js, studio-redesign.test.js); side-panel-redesign.test.js covers the rail, the launcher and the audit overlay.
  • Adding a tool: three tests count 18 panels (popup-real-user.test.js, popup-accessibility.test.js, tests/a11y/extension.test.js).
  • Manually, on the built package in Chrome and Firefox: the popup, side panel and window; Pick from page with the OS eyedropper; the three optional permission prompts, declined once and then accepted; every default shortcut; pickers staying native on auricartisan.com; the Firefox sidebar, a picker, the inspector and the right-click menu; and switching to हिन्दी and back.

For workflow-level instructions, see the Browser Extension User Guide.