Aller au contenu
Cette page n’est pas encore traduite — voici la version anglaise.

Your browser is quietly an operating system: the 4 WebAssembly engines in our extension

One Chrome extension, no backend for its core features: a real database, two AI inference engines and a full Python interpreter, all running as WebAssembly. What each engine does, how it's wired, and what it costs.

Dannick K.
15 octobre 2026 · 5 min de lecture
PrésenterTableau

Aussi dans English

Partager
Sur cette page
  1. The browser has the parts of an OS
  2. Three engines that used to need a server
  3. Real Python, locked in a box
  4. What it costs, and what it buys

Under the hood is a series about how AWFlow, a browser-native automation tool, works inside. This is #2.

AWFlow has no backend for its core features. Yet a single Chrome extension runs a real database, two AI inference engines and a full Python interpreter. All four are possible because of WebAssembly. Here’s what each one does, how it’s wired up, and what it costs.

The idea

Your browser is quietly an operating system.

It runs real software: storage, threads, a GPU, a sandbox.IndexedDB, Web Workers, WebGPU and WebAssembly give it the parts of an OS.

Ligne animée
Version texte
  1. The idea: Your browser is quietly an operating system.

The browser has the parts of an OS

WebAssembly (WASM) is a binary format that languages like Rust, C and C++ compile to. The browser runs it at close to native speed, inside the same sandbox as any web page: no install and no system access. If you want the plain-words tour of how that works, WebAssembly, explained covers it; this post is about what we built on top.

For a product like ours, it changes the architecture. Instead of running engines on a server and sending users’ data to them, we ship the engines to the user. And the browser already has the pieces an engine expects from an operating system:

An operating systemYour browser
A disk
IndexedDB and the Cache API
Processes
Web Workers
Drivers for the GPU
WebGPU
Programs you install
WASM engines shipped in the extension
Permissions
The sandbox and the extension's CSP

Rules about what code may do.Same-origin sandbox plus MV3 CSP: script-src 'self' 'wasm-unsafe-eval'.

Analogie
Version texte
  1. An operating system: A disk ≈ Your browser: IndexedDB and the Cache API
  2. An operating system: Processes ≈ Your browser: Web Workers
  3. An operating system: Drivers for the GPU ≈ Your browser: WebGPU
  4. An operating system: Programs you install ≈ Your browser: WASM engines shipped in the extension
  5. An operating system: Permissions ≈ Your browser: The sandbox and the extension's CSP

Here are the four engines, from the bottom of the stack to the top:

Engine Compiled from What it does in AWFlow
SurrealDB Rust The local database: workflows, run history, agents, knowledge
ONNX Runtime Web C++ Local AI tasks via transformers.js: classify, summarize, translate, transcribe, embed
WebLLM (MLC) WASM runtime + WebGPU Chat LLMs on the user’s GPU
Pyodide CPython Real Python for the Code node
  1. Your workflowsData, AI steps and Python code, on your machine.
  2. Four enginesSurrealDB, ONNX Runtime Web, WebLLM, Pyodide.
  3. Web WorkersEach heavy engine in its own thread, off the UI.
  4. WASM + WebGPUCompiled engines at close to native speed, GPU kernels.
  5. Browser sandboxSame sandbox as any web page: no install, no system access.

Peel it apart: a sandbox, a runtime, threads, engines, then your work.Browser sandbox → WebAssembly + WebGPU → dedicated workers → four engines → workflows.

Couches
Version texte
  1. Your workflows / Four engines / Web Workers / WASM + WebGPU / Browser sandbox
  2. Your workflows: Data, AI steps and Python code, on your machine. · Four engines: SurrealDB, ONNX Runtime Web, WebLLM, Pyodide. · Web Workers: Each heavy engine in its own thread, off the UI. · WASM + WebGPU: Compiled engines at close to native speed, GPU kernels. · Browser sandbox: Same sandbox as any web page: no install, no system access.

Three engines that used to need a server

SurrealDB: a database you ship to the user

SurrealDB’s WASM build includes a storage engine that persists to IndexedDB. Using it looks like using a remote database, except the address is local:

import { Surreal } from 'surrealdb';
import { createWasmEngines } from '@surrealdb/wasm';

const db = new Surreal({ engines: { ...createWasmEngines() } });
await db.connect('indxdb://<local-db-name>');
await db.use({ namespace, database });

Two design choices worth copying:

  • One long-lived connection. The local database is a singleton that stays open for the life of the app. The init promise is cached, so concurrent callers share one connection instead of racing to create two.
  • Same engine, more uses. The same SurrealDB setup also backs our local knowledge bases and vector search.

This is the reason AWFlow works with no account: your workflows and history live in your browser from the first second.

Your browser
Our servers
Your browserwhere you work
A typical backenddatabase, AI, code runner
your workflows and data
results
Server to runnoneAccount needednoData sentnone

Ship the engines instead. They run where you are.SurrealDB, ONNX Runtime Web, WebLLM and Pyodide run client-side as WebAssembly.

Aller-retour
Version texte
  1. Your browser: Your browser · Our servers: A typical backend
  2. Your browser → A typical backend: your workflows and data
  3. A typical backend → Your browser: results
  4. Server to run: yes · Account needed: yes
  5. A typical backend → Your browser · Server to run: none · Account needed: no · Data sent: none

Two places engines can live

The classic way: the database, the AI and the code runner sit on a server.

Your data travels

Every query, prompt and script goes over the network to that server.

Results come back

The server answers, every time.

Someone runs that server

So there is a server to scale and secure, and an account to create before you start.

Ship the engines instead

Put the engines in the browser and the trip disappears: no server for us to run, no account to start, no data to send.

ONNX Runtime Web and WebLLM: two AI engines, each in a worker

  • ONNX Runtime Web, through transformers.js, runs task models: classification, summarization, translation, speech-to-text, embeddings. For each task it uses WebGPU if the GPU path is known to work for that task, and WASM otherwise.
  • WebLLM (from the MLC project) runs chat models. Its runtime is WebAssembly, and the heavy math runs as WebGPU kernels on the user’s graphics card.

Both run in dedicated Web Workers, so downloading or compiling a 2 GB model never freezes the UI. (TensorFlow.js is in the mix too, for a few vision and classic models, but it uses WebGPU, WebGL or CPU backends, so it isn’t one of the four WASM engines.)

The MV3 trap we hit is covered in detail in Running LLMs inside a Chrome extension: ONNX Runtime fetches its WASM files from a CDN by default, and an extension’s CSP (script-src 'self' 'wasm-unsafe-eval') forbids that. You have to ship the runtime files inside the extension and point the library at them.

Real Python, locked in a box

The Code node runs Pyodide, so the Python you write is real CPython.

GlossairePyodide

The standard Python interpreter, compiled to WebAssembly so it runs inside a browser.

CPython compiled to WASM by the Pyodide project; loads in a worker and runs pure-Python code with no server.

CPythonWebAssemblyWeb Worker

Real Python, not a look-alike.Actual CPython, compiled to WebAssembly.

Terme du glossaire
Version texte
  1. The Code node runs Pyodide, so the Python you write is real CPython.
  2. Pyodide: The standard Python interpreter, compiled to WebAssembly so it runs inside a browser. CPython compiled to WASM by the Pyodide project; loads in a worker and runs pure-Python code with no server. (CPython, WebAssembly, Web Worker)

Running user-supplied Python (possibly from a workflow someone else shared) inside your browser needs isolation, so the design is layered:

Five locks on the box

How the Python sandbox is built

  • Its own worker (fait)automatisé
  • A restricted js module (fait)automatisé
  • Capabilities removed after boot (fait)automatisé
  • A fresh interpreter per run (fait)automatisé
  • Timeouts that terminate the worker (fait)automatisé

Time's up means stopped.On timeout or abort the worker is terminated, not just ignored.

Liste à cocher
Version texte
  1. How the Python sandbox is built
  2. Its own worker
  3. A restricted js module
  4. Capabilities removed after boot
  5. A fresh interpreter per run
  6. Timeouts that terminate the worker

In more detail:

  1. Its own worker. Python never runs in the app page. A worker has no DOM, no chrome.* APIs and no page state.
  2. A restricted js module. Pyodide normally exposes the host’s globalThis to Python. We replace it with a tiny allow-list, and stub out pyodide.http.
  3. Capabilities removed after boot. Once the interpreter has loaded, the worker’s own network, storage, messaging and nested-worker globals are deleted, as defense in depth.
  4. A fresh interpreter per run. Reusing one and resetting its namespace would let one run’s code hook the next run’s input. So every run gets a new interpreter.
  5. Timeouts that actually stop the code. On timeout or abort, the worker is terminated. We don’t just stop waiting for it.

A fresh interpreter takes about 2 seconds to boot with a warm cache (around 5 seconds cold), so we keep one pre-warmed spare: a worker that has loaded Pyodide but never run user code. Each run takes the spare and immediately starts warming the next one. An unused spare is shut down after a minute.

Cold boot
boot ~5 srun
Warm cache
boot ~2 srun
Warm spare
runwarm the next
no boot wait

No boot wait, and still a fresh interpreter every run.Isolation per run is kept; an unused spare shuts down after a minute.

Chronologie
Version texte
  1. Cold boot: boot ~5 s (0–5), run (5–6)
  2. Warm cache: boot ~2 s (0–2), run (2–3)
  3. Warm spare: run (0–1), warm the next (1–3)
  4. no boot wait

What it costs, and what it buys

Shipping engines to the browser isn’t free. Here is what it costs us and how we handle each cost:

Cost How we handle it
Extensions can’t load code from a CDN Every WASM runtime ships inside the extension
Engines are heavy Each one is lazy-loaded the first time it’s used (a test checks the heavy dependencies stay out of the main bundle)
Models are big downloads Downloaded once, cached, visible and deletable in a Local Models page
Not every machine has WebGPU Always a WASM or CPU fallback

And what it buys:

  • No server for us to run, scale or secure, and none for users to trust.
  • No account needed to start.
  • No data sent: prompts, pages and workflow data can stay on the machine.

The easiest way to see the local database at work is to build a first workflow without signing in. This docs example reads the text you select on a page and shapes it into fields; it is saved in the browser’s local database the moment you create it.

Try it

Run a workflow with no account

Open it in AWFlow in a local workspace: it is stored in your browser's database, with no sign-up.

Ouvrir dans AWFlow (s’ouvre dans un nouvel onglet)docs.awflow.io/examples/first-workflow.awf
Scannez pour ouvrir

Call to action. Viewers scan the code, readers click the link.Docs example: When Started → Get Selected Text → Edit Fields, stored in local SurrealDB (IndexedDB).

À vous
Version texte
  1. Run a workflow with no account · Open it in AWFlow in a local workspace: it is stored in your browser's database, with no sign-up. · https://docs.awflow.io/examples/first-workflow.awf

If you’re building a browser extension or a local-first web app, the takeaway is that the browser is now a credible runtime for “server” components.

Shipping engines to the browser

  1. A database, an inference engine and an interpreter all fit
  2. Put each one in a worker
  3. Load them lazily
  4. Keep a fallback

A fallback for every machine.WebGPU when available, WASM or CPU otherwise.

Récap
Version texte
  1. Shipping engines to the browser
  2. A database, an inference engine and an interpreter all fit
  3. Put each one in a worker
  4. Load them lazily
  5. Keep a fallback

Next in the series: how WebLLM turns your GPU into an AI server. AWFlow is free to install.

Automatisez le web où vous êtes. Gratuit, dans votre navigateur.