MetaMask for inference. A MV3 browser extension that lets any website use your LLM
(OpenRouter) under per-origin USD spending budgets you grant. The site asks for completions
through an injected window.aimask API; the key never leaves the extension.
Protocol and semantics: see SPEC.md. This repo is the M0+M1 reference build.
Bun + turbo monorepo. Packages live under packages/:
core— pure decision logic (jsonrpc, ledger/budget, model negotiation, SSE, catalog, OpenRouter shaping, PKCE, errors). Nochrome.*, nofetch. Unit-tested.extension— the WXT MV3 extension: thin IO adapters and UI.entrypoints/holds the background worker, the content scripts, and the consent / options / popup pages;lib/holds the router, storage, OpenRouter client, consent, and crypto.sdk—@aimask/sdk, the zero-dependency client a site imports: types, a synchronous detector, and named error codes.tsconfig— shared TypeScript base.
site/ is the docs and landing site; demo/ is a local end-to-end demo page.
bun install
bun run build # builds both chrome-mv3 and firefox-mv3Load the unpacked build from packages/extension/.output/:
- Chromium (Chrome, Brave, Edge): open
chrome://extensions, enable Developer mode, click Load unpacked, and selectpackages/extension/.output/chrome-mv3/. - Firefox: open
about:debugging, choose This Firefox, click Load Temporary Add-on, and pick any file insidepackages/extension/.output/firefox-mv3/.
Single target: bun run build:chrome or bun run build:firefox.
npm install @aimask/sdkimport { getAimask } from "@aimask/sdk";
const aimask = getAimask(); // Aimask | null — null means the extension isn't installedFull client and error codes: see the SDK README.
Open the extension's Options page, then either:
- Connect with OpenRouter (PKCE OAuth via
chrome.identity), or - paste an OpenRouter API key.
The key is encrypted (AES-GCM) and stored only in the background chrome.storage.local; pages
never see it. Grants (per-origin budgets) are listed there and can be revoked.
bun run build:sdk # the demo page serves the built SDK bundle
bun run demo # http://localhost:5733Exercises the full flow: availability → requestSession (consent popup) → chat →
chatStream (with abort) → usage, including 4001/4200 error rendering.
bun run typecheck && bun run lint && bun test