Model or dataset
kessler/gemma-gem avatar
kessler/gemma-gem

Gemma Gem: a WebGPU Chrome extension that runs Gemma 4 in an offscreen document

Gemma Gem runs Google's Gemma 4 model entirely on-device via WebGPU — no API keys, no cloud, no data leaving your machine.

970 stars105 forksTypeScriptApache-2.0

At a glance

What is it?
Gemma Gem puts a Gemma 4 model inside a Chrome extension using WebGPU and @huggingface/transformers, with an agent loop that can read pages and click elements. The architecture is the interesting part; the hardware table is self-described as unbenchmarked, and that gap is what to check before adopting.
Who is it for?
Adopt Gemma Gem if you want a local Gemma 4 agent inside Chrome and you are willing to run the development build with the offscreen document console open, because that log is where model loading, prompt construction and tool execution are visible.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 109 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What Gemma Gem is for, and who it excludes

The problem Gemma Gem targets is narrow and specific: you want a language model to act on the page in front of you, but you do not want to send that page anywhere. The README states the model runs entirely on-device via WebGPU, with no API keys, no cloud, and no data leaving the machine. That framing matters because the alternative pattern for browser assistants usually involves a hosted endpoint, which means the page content, the DOM, and anything typed into a form travel off the device.

The audience is therefore engineers and power users who already run Chrome with WebGPU enabled and who are comfortable loading an unpacked extension from a build output directory. The README lists the requirements plainly: Chrome with WebGPU support, plus roughly 500MB of disk for the E2B model or about 1.5GB for E4B, cached after the first run. There is no published extension listing in the material, and no releases were retrieved, so the path is a local build rather than an install from a store. Anyone who wants a one-click install, or who works primarily in Firefox or Safari, is outside the target set from the start.

The offscreen document is the load-bearing decision

The architecture diagram in the README splits the extension into three contexts. An offscreen document hosts the model through @huggingface/transformers plus WebGPU and runs the agent loop. A service worker routes messages between content scripts and that offscreen document, and handles two tools: take_screenshot and run_javascript. A content script injects the gem icon and a shadow DOM chat overlay, and executes the DOM tools read_page_content, click_element, type_text and scroll_page.

Putting inference in an offscreen document rather than the service worker is the choice that makes the rest work. MV3 service workers are evicted when idle, and a multi-gigabyte model cannot survive that lifecycle. An offscreen document persists for as long as it is needed, so the weights stay resident and token streaming can continue. The cost is indirection: every tool call crosses a message boundary between the content script, the router, and the offscreen document. The README's own debugging notes point at this seam, describing the offscreen document logs as the most useful because they show model loading, prompt construction, token counts, raw model output, and tool execution. If something misbehaves, that is where the evidence lives.

Splitting tool execution across contexts is also a security boundary, whether or not it was designed as one. run_javascript executes in page context with full DOM access and is handled by the service worker, while click_element and type_text are handled by the content script. Those are different privilege levels, and the README does not describe a confirmation step before a tool fires.

Building and loading the extension

Setup is two commands, per the README:

pnpm install pnpm build

After that you load the unpacked extension from .output/chrome-mv3-dev/ through chrome://extensions with developer mode enabled. The development build keeps logging, source maps and all info, debug and warn output; pnpm build:prod silences logging and minifies, leaving only error logs. Since the README says the offscreen document logs are the most useful for watching model loading and tool execution, the development build is the one to run while you are evaluating behaviour.

Usage is a four-step sequence from the README: navigate to a page, click the gem icon in the bottom-right corner to open the chat, wait for the model to load with progress shown on both the icon and the chat, then ask questions about the page or request actions. The settings panel behind the gear icon in the chat header exposes the Model switch between Gemma 4 E2B and E4B (the selection persists across sessions), a Thinking toggle for native Gemma 4 thinking, Max iterations as a cap on tool call loops per request, rebindable shortcuts, Clear context to reset conversation history for the current page, and Disable on this site, which is persisted per hostname. Defaults for the shortcuts are Alt+G to toggle and Escape to close, and the README notes that bindings persist across sessions with a reset button per field.

Max iterations deserves attention. It is the only guard the README documents against an agent that keeps calling tools, and the default value is not stated in the material.

The tool surface and where each tool runs

Six tools are documented. read_page_content reads the text or HTML of the page or of a CSS selector. take_screenshot captures the visible page as PNG. click_element clicks by CSS selector. type_text types into an input by CSS selector. scroll_page scrolls up or down by a pixel amount. run_javascript executes JavaScript in the page context with full DOM access.

The split is uneven in a way worth noticing. Four tools are selector-based and run in the content script, which constrains them to elements the model can address by CSS selector. Anything behind a shadow root, inside a cross-origin iframe, or rendered into a canvas is not reachable by click_element or type_text. run_javascript is the escape hatch, and it is also the widest one: the README describes it as executing in the page context with full DOM access. A model that can both read a page and run arbitrary JavaScript in it is a different risk profile from a model that can only read, and the README does not describe a sandbox, an allowlist, or a per-call confirmation. Disable on this site is the documented control, and it is per-hostname and persisted, which makes it a blunt instrument rather than a per-action one.

Screenshots travel a different path. take_screenshot runs in the service worker, which means image data crosses the same message router as everything else before reaching the offscreen document for inference. The README does not state what resolution or format the model receives beyond PNG capture.

The hardware table is an estimate, and it says so

The README's hardware section is preceded by an explicit disclaimer: estimated minimal requirements, not benchmarked on real devices. That label should govern how the table is read. It lists 4GB of GPU VRAM or shared memory and 6 to 8GB of system RAM for E2B, rising to 6GB and 8 to 16GB for E4B, with Chrome 113+ or Edge 113+ and the shader-f16 GPU feature required in both cases. Integrated GPUs named as working with sufficient shared memory include Intel Xe (Arc), Apple M1+ and Qualcomm Adreno. Discrete GPUs need 4GB or more of VRAM, with a GTX 1650 or RX 6500 XT given as examples. Mobile support is listed as iPhone A14+ and Snapdragon 8 Gen 1+, with the note that it is slow.

Performance guidance is qualitative: slow on integrated GPUs, normal on mid-range discrete GPUs, fast on high-end GPUs. There are no tokens-per-second figures anywhere in the material, and no latency numbers for model load or first token. The one quantitative memory note is that at long contexts of 128K the KV cache adds 10 to 20 percent overhead on top of model weights, which is consistent with the stated 128K context for both checkpoints, both at q4f16 quantization.

The practical consequence is that you cannot size a deployment from this table. The shader-f16 requirement is the one hard gate, since a GPU without that feature fails regardless of memory. Everything above it is an estimate that the project itself declines to stand behind, so the only reliable measurement is the one you take on your own hardware with the offscreen document console open.

Where it fits against a local runtime like Ollama

The obvious alternative for running a model locally is a desktop runtime such as Ollama, which serves a local HTTP endpoint and typically pairs with a separate client. The difference is not the model, since both can host Gemma weights, but where the model sits relative to the browser session. A local server approach gives you a stable process, a CLI, and an API you can script against, and it is not tied to one browser's feature support. It also means the browser extension, if there is one, is a thin client talking to localhost, and the page context is reached through whatever the client can access.

Gemma Gem inverts that. The model lives inside the browser, in an extension context, and the DOM tools are first-class citizens rather than an afterthought: read_page_content, click_element, type_text and scroll_page operate on the live page because the content script is already there. Nothing needs to be installed or kept running outside Chrome, and there is no local port to secure. The trade is portability and process stability. Gemma Gem depends on WebGPU and shader-f16, it is Chrome and Edge only per the requirements, and the model is evicted whenever the offscreen document goes away. If you want one model shared across terminals, editors and browsers, the local-server pattern is the more general fit. If the work is reading and acting on pages you are already looking at, the extension's placement is the advantage.

Maintenance, licence and what the material does not cover

The repository is Apache-2.0 and the last push recorded is 2026-05-29. No releases were retrieved, so there is no versioned artifact to pin and no changelog to read; the unit of upgrade is the main branch. That matters for cost, because the extension bundles two ONNX checkpoints from onnx-community and depends on @huggingface/transformers, WXT and marked. A bump in transformers.js or a change to WXT's build output layout can move the directory you load from, which the README currently gives as .output/chrome-mv3-dev/. Rebuilding with pnpm build after each pull is the whole upgrade procedure as documented.

Apache-2.0 covers the extension code. It does not settle the terms attached to the Gemma weights or to the ONNX conversions, which are separate artifacts fetched at runtime and carry their own terms; that is a question for whoever distributes the result, not something the README addresses. The material also does not describe telemetry, an update mechanism, or any signing or store submission path, so treat this as a source build rather than a distributed product. The debugging section is the most concrete maintenance aid available: chrome://inspect#other lists every inspectable extension context, and chrome://extensions exposes the service worker and offscreen.html views separately, which is enough to tell whether a failure is in the model, the router, or the content script.

Editorial conclusion

Adopt Gemma Gem if you want a local Gemma 4 agent inside Chrome and you are willing to run the development build with the offscreen document console open, because that log is where model loading, prompt construction and tool execution are visible. Do not adopt it if you need Firefox or Safari support, if your GPU lacks shader-f16, or if you expect the hardware table to predict your own frame times, since the README labels those figures as estimates that were not benchmarked on real devices. Verify three things first: that chrome://extensions shows the offscreen document loading the E2B weights without error, that the Max iterations setting is low enough to stop a tool loop before it runs away, and that Disable on this site covers any hostname where run_javascript must never reach page context.

Official sources

  1. Issues
  2. kessler/gemma-gem on GitHub
  3. License: Apache-2.0
  4. README
Community notes

Community notes