Reference browser extensions
The Chromium and Firefox extensions put the shared contextual sidebar into the browser’s own panel and highlight annotated mentions on the page you activate. They are reference shells over existing contracts: the live highlighter (0.5), the core ExtensionEnvelope, the shared ContextSidebar, the fixture search adapter and the fixture annotation provider. Read ADR 0006 for the design and its limits.
Build and load
Section titled “Build and load”npm run build:extensions # → build/extensions/{chromium,firefox}/ and evk-<browser>-<version>.zip- Chromium (116+). Open
chrome://extensions, turn on Developer mode, choose Load unpacked, and pickbuild/extensions/chromium. - Firefox (128+). Open
about:debugging#/runtime/this-firefox, choose Load Temporary Add-on…, and pickbuild/extensions/firefox/manifest.json. Firefox asks you to confirm host access for127.0.0.1when the add-on is installed.
Then run npm run dev and open http://127.0.0.1:4173/extension-fixture.html. Click the EVK toolbar button (or press Alt+Shift+E). The panel opens and the page’s provider-annotated mentions are highlighted. Clicking a mention adds its exact entity to the sidebar search; overlapping or multi-entity mentions open an explicit chooser. Locate in the panel scrolls the page and selects the mention. The panel’s query emphasis is painted back onto the page.
Neither build has been signed or published to a store. Publication is a separate, owner-authorized action.
Permissions and why
Section titled “Permissions and why”| Permission | Why |
|---|---|
activeTab | One-time access to the current tab when you click the toolbar button or use the shortcut. This is how EVK runs on any site without standing access. |
scripting | Injects the packaged content.js into that tab (all frames) after the gesture. |
sidePanel (Chromium only) | Hosts the sidebar in Chrome’s side panel. Firefox uses sidebar_action. |
host http://127.0.0.1/* | Owner decision: lets the synthetic demo pages and the automated tests run against the exact shipped build. Match patterns ignore the port, so this covers every local server on the machine. It does not cover localhost or any other host. |
There are no optional host permissions, no static content_scripts, no externally_connectable, no remote code, and no analytics or network calls of its own. The extension-page CSP is script-src 'self'. If EVK has no access to a page, the panel shows “no access … use the toolbar button” and reads nothing.
Protocol and scoping
Section titled “Protocol and scoping”- Page and panel messages. Everything that crosses between a page and the panel is a validated
ExtensionEnvelope(protocol v1). Page → panel actions arecapabilities(hello),annotations.state,mentions.chooseandentity.activate. Panel → page actions arequery.state,mention.selectandmention.locate. Anything else, and any unknown field, is rejected. - Page sessions. Each document has its own session, context ID and increasing sequence. The router binds a session to the port’s browser-reported tab, frame and document. The payload never claims those.
- Navigation and reloads. Navigation or a document replacement retires the session; late messages from it are refused. A new page needs a new activation. A panel message for an old context is dropped.
- Frames. Each frame is its own session and context. An activation inside a frame switches the panel to that frame’s document.
- Background restarts. Content scripts and panels reconnect and re-announce. No page content is persisted or replayed. With no panel open, an activation only sets a badge.
- Diagnostics. A panel can request counts of rejected messages, sessions and panels. No content is included.
Replacing the providers
Section titled “Replacing the providers”- Search. The panel uses
createFixtureAdapterfrom the integration fixtures. Replace it inextension/panel.tswith yourSearchAdapter. - Credentials. Keep them in the privileged side (background or panel), never in page DOM or broad messages.
- Annotations. They come from
fixtureProvider(url)inextension/background.ts. Replace it with a provider that decides, for a browser-reported frame URL, which container to attach to and which annotations to paint. If your provider needs page text, request it explicitly and document it. The content script never uploads page content by itself.
Checks
Section titled “Checks”-
npm run suite:extensionsloadsbuild/extensions/chromiumunpacked into Chrome for Testing. It covers:- the packaged-manifest review;
- page → panel → page flow;
- profile → graph → evidence flow;
- frames;
- navigation staleness;
- tab isolation;
- forged and malformed messages;
- service-worker restart;
- denied access;
- panel reopen.
The panel runs as a pinned extension tab (
panel.html?tab=<id>), because the native side-panel UI cannot be automated. -
npm run suite:firefoxinstalls the shippedbuild/extensions/firefoxas a temporary add-on in headless Firefox 128+ (tested with 156). It drives Firefox over Marionette. SetEVK_FIREFOX_EXECUTABLEto the Firefox binary. Six scenarios:- the real toolbar action opens the real sidebar and annotates the page through the one-time
activeTabgrant; - page highlight → panel search, query emphasis back on the page, and the overlap chooser;
- frames and navigation retirement;
- denied access on
localhost; - idle background suspension (2 s test timeout) without losing live pages;
- re-activation after an add-on reload.
The toolbar action is triggered through Firefox’s own action handler (a test-only
-remote-allow-system-accesslaunch). Panel interactions use the samepanel.htmlpinned to a tab. - the real toolbar action opens the real sidebar and annotates the page through the one-time
-
Firefox limitation. When the add-on reloads, Firefox unloads the content script without cleanup, so the old page can keep its highlights until it is reloaded. Cleaning up on background suspend would also wipe live pages on every idle suspension, so EVK does not do it (ADR 0007).
-
Still manual: the Chromium side-panel chrome and
Alt+Shift+Ein both browsers.