Open source, end to end. You decide what leaves.
Everything that runs in the page and on your machines is Apache-2.0 and needs no account: the runtime, its model, the MCP server and the genclass skill. Keep the runtime's anonymous diagnostics on: they carry its decisions and counts, no text from your page unless you opt in, and never from local hosts; they give the app a free dashboard, and they improve the model. One flag turns them off where policy requires it. This page names every request that leaves your network, and how to stop each one.
What is open source
The repository genclass-dev/GenClass is Apache-2.0, and so is everything it publishes:
| Part | Where | Needs |
|---|---|---|
| The runtime: observe, guard and heal modes, the devtools overlay, the measured visual checks, sinks, the local page check | @genclass/runtime on npm; one dependency, onnxruntime-web | A browser. No account, no key. |
| The model, 10 MB, with its model card | @genclass/runtime-model on npm, or your own origin | Nothing |
| The MCP server for coding agents: findings, explain, replay, explore, the generated Playwright test | @genclass/mcp on npm; no dependencies | The developer's machine; a dev page connected |
| The genclass skill and the plugin | genclass-dev/genclass-plugin | The MCP server |
| The diagnostics collector and the dashboards behind genclass.dev | telemetry-worker/ in the repository, a Cloudflare Worker | Your own Cloudflare account, if you want one (below) |
| The model's training code, simulators and evaluation | training/, sim/, realapps/ and bench/ in the repository | For a review; nothing at runtime |
Not open source, and not needed: the hosted page check at genclass.dev (scan --hosted, or genclass_scan with hosted: true), genclass.dev's accounts, export and forwarding as a hosted service, and Enterprise, which runs GenClass's models in our cloud and the coding-agent loop as a service.
What you keep, what you give up
With the diagnostics on, the default, you keep everything: every mode, the reports with their evidence, the devtools overlay on localhost, the visual checks and their fixes, rt.explain(id) and rt.audit(), sinks into your own logging, the local page check, the free dashboard and its private link (no account needed), and for your coding agents the MCP server, the skill, findings as they happen, explore, replay and the regression test. The diagnostics are the runtime's decisions and counts, with no text from your page unless you opt in; every field is listed.
With --no-telemetry nothing reaches genclass.dev, and you give up what runs there: the dashboard and its private link, export and forwarding from the collector (Sentry, PostHog, Datadog, Slack, a signed webhook), interaction analytics, your own classifier (a person from GenClass trains it on the diagnostics your app sends, or on bug reports and labelled examples you share), and genclass_analytics with source: "production", which reads that dashboard. The nearest open-source equivalents: a webhook sink to an endpoint you own, the console-json sink into the log shipper you run, and the collector in your own cloud.
The setup
Four steps; the first and the last are the ones every team needs. The runtime's init shows its diff and asks before it writes (--dry-run only shows, --yes applies); fetch-model downloads into the folder you name, and the MCP server's init writes .mcp.json and the skill at once, without asking. The runtime commands name the 0.3.0 line, npm's beta tag (the MCP server is pinned at its release, 0.2.2): a bare npm install @genclass/runtime gets the stable 0.2.x line, which has no agent link, no named sinks and no visual checks.
1. The runtime, in heal mode
init finds your framework and package manager, installs @genclass/runtime, adds import "@genclass/runtime/auto/heal" first in your entry file (a folder of plain HTML pages gets a script tag pinned with an integrity hash) and a line that loads the devtools overlay in development only. Once you approve the diff it creates the app's free dashboard link at genclass.dev (it sends the package name, nothing else), writes the token into a marked option file next to the entry, and saves the private link in .genclass.local, which it adds to .gitignore; --no-token skips the link.
Heal mode is the one we recommend. GenClass reports what its model finds likely, with the evidence, and when it is sure it acts with minimal steps that it logs: it drops a stale response, merges or blocks a duplicate submit, retries a failed request or serves its cached answer, hedges a slow call, and rolls back a bad write or asks your store to resync. Discards and rollbacks can be undone, and a breaker steps the mode down after repeated undos. On held-out simulated apps heal intervenes wrongly in 0.59% of cases at the default setting (model 0.2.0), over its 0.5% target, and in 0.00% on held-out real apps; precision among its actions was not measured for 0.2.0, so keep a sink and read what it did. --mode guard keeps the guard-tier actions only (discard, defer, coalesce, delay), and leaving the flag out is observe, which reports and changes nothing.
The diagnostics stay on, as with every init: from public hosts, and never from localhost or private networks, the runtime sends its decisions, action outcomes, model status and counts to the maintainers' collector, and to the app's dashboard with its token. No text from the page unless you opt into sending the situation text, never cookies; the collector stores no IP address or user agent. The console says so once per page, with the opt-out. The data comes from your users' browsers, so name GenClass in your privacy policy, and where you need consent for analytics, start with telemetry: false until it is given. Every field.
Turning the diagnostics off
--no-telemetry writes telemetry: false into the marked option file (data-telemetry="off" on a script tag, telemetry=off in Astro's <meta name="genclass"> line), implies --no-token, and makes no request of its own. By hand, the same thing:
// genclass.config.ts, imported before the runtime
(globalThis as { GENCLASS_CONFIG?: object }).GENCLASS_CONFIG = { telemetry: false };
// first in the entry file
import "./genclass.config";
import "@genclass/runtime/auto/heal";
<!-- plain HTML: first in <head>, the version pinned -->
<script src="https://cdn.jsdelivr.net/npm/@genclass/runtime@0.3.0-beta.5" data-mode="heal" data-telemetry="off" data-devtools="local"></script>
Or GenClass.init({ mode: "heal", telemetry: false }) in code (then import @genclass/runtime/discover first and pass autoState: true for the automatic React, Redux and Zustand discovery that /auto does by itself). The option is read once, when the runtime starts: with it, nothing is sent and no console notice appears. The per-visitor opt-outs, ?genclass=no-telemetry, localStorage and Global Privacy Control, work either way.
2. The model from your own origin
By default the browser downloads the model and ONNX Runtime's wasm from cdn.jsdelivr.net, at idle, once, then cached: public files, with no app data in the request (about 13 MB on WASM, 18 MB on WebGPU). For a closed network, or a Content-Security-Policy with no third-party origin, serve them yourself:
fetch-model downloads the model's variants and both ONNX Runtime builds into the folder your app serves as it is (public/ for Vite, Next.js and Astro, static/ for SvelteKit): about 64 MB in all, or about 24 MB with --variant q8 --ort wasm, which a host with a 25 MiB per-file limit such as Cloudflare needs, since the WebGPU build's wasm is 27 MB. It checks the model files against the sizes and SHA-256 hashes in the model card and records ONNX Runtime's hashes next to them; info <dir> verifies the folder again later, and --from and --ort-from take a mirror of your own. --model-url is the same as the options model: { baseUrl: "/genclass-model/", ortWasmPaths: "/genclass-model/ort/" } (data-model and data-ort on a script tag); when only the WASM build is present, init also sets device: "wasm".
With a bundler nothing else loads from a CDN. The script-tag path loads the runtime's own files on demand (the model worker, ONNX Runtime's JavaScript, sinks, the visual checks, the overlay, the agent link) from jsDelivr at the pinned version, unless you serve the package's dist/ folder yourself and point the tag at it (--cdn <url>, data-base). The policy then needs https://genclass.dev in connect-src for the diagnostics and nothing else from outside (connect-src 'self' alone with --no-telemetry), 'wasm-unsafe-eval' in script-src, and worker-src 'self' (blob: for the script tag). Blocked and not self-hosted, GenClass observes without a model, prints one warning naming the origin, and detects nothing.
3. Reports in your own logs
A report is a console line in the end user's browser, with its evidence in a collapsed group, and the dashboard shows what GenClass found and did, by page. A sink is how each report also reaches your own logs. Two ship with the runtime and need no code: console-json prints one JSON line per record for the log shipper you already run, and webhook:<url> sends batched POSTs to an endpoint you own. Add --sink console-json or --sink webhook:/genclass to the init command (data-sink on a script tag), or pass a function of your own:
GenClass.init({
mode: "heal",
sinks: [{ send: (r) => myLogger.info("genclass", r), kinds: ["detection", "intervention"] }],
});
The webhook sends the redacted evidence by default (webhook({ url, evidence: false }) in code sends the structured fields only; :noevidence is console-json's option); it can hold short fragments of what users typed, and the endpoint is yours. A webhook on another origin needs that origin in connect-src. rt.audit() exports every decision and action as JSON. All sink options.
4. The MCP server and the skill, on each developer's machine
This is what makes a coding agent useful on timing bugs, and it is local by construction. Two lines in the app, one command in the project:
// the app's browser entry, next to the import init added; development builds only
import rt from "@genclass/runtime/auto/heal";
if (import.meta.env.DEV) import("@genclass/runtime/agent").then((a) => a.connectAgent(rt));
The first records what happens on local pages for the server; it talks only to 127.0.0.1, and a production build drops it (Next.js: process.env.NODE_ENV === "development"). The second writes the server into .mcp.json for Claude Code and the genclass skill to .claude/skills/genclass/SKILL.md; config <client> prints the block for Cursor, VS Code, Codex, Gemini CLI and others, and the plugin installs are on the skill page. Two settings are yours to choose: GENCLASS_DASHBOARD set to the app's private dashboard link lets genclass_analytics read your own production numbers, and GENCLASS_REPORT=on mirrors what the agent finds, replays and proves to the dashboard's Loop view; unset, the server sends nothing off the machine. Never pass hosted: true to genclass_scan unless you want the page URL sent to genclass.dev's page check; from a terminal, npx @genclass/runtime@beta scan <url> --local stays on the machine and needs Playwright's Chromium. For a dev server that is not on localhost (a *.test name, a container, a LAN address), connectAgent(rt, { anyHost: true }) with the origin in GENCLASS_AGENT_ORIGINS. The browser showing the page and the server must share a machine: the bridge is loopback only.
Or hand it to your coding agent
The same four steps as one prompt. It makes the agent show you the diff first and keeps every setting above.
What leaves your network
- To genclass.dev, with the diagnostics on: the app's package name, once, when
initcreates its free dashboard link (--no-tokenskips it); then, from public hosts only, the runtime's anonymous diagnostics in batches: its decisions, action outcomes, model status, counts, the hostname and id-normalised paths. No text from the page unless you opt in, never cookies, and no IP address or user agent is stored. Every field, and the threat model. - To genclass.dev, with
--no-telemetry: nothing. No diagnostics, no dashboard token, andinititself makes no request, not even npm's dist-tag check for newer releases. - To cdn.jsdelivr.net: the model and ONNX Runtime files, once per browser, unless you serve them (step 2); on a plain HTML site the runtime's own files too, unless you serve
dist/. Public files; no app data in the requests. - From the MCP server: nothing, unless you set
GENCLASS_DASHBOARDorGENCLASS_REPORT(step 4). It listens on127.0.0.1and keeps its recordings in.genclass/agent/in the project, which it adds to.gitignore. - On developer machines:
npmandnpxfetch the packages from the npm registry or your mirror;fetch-modeldownloads from jsDelivr or the mirror you name;scan --localneeds Playwright's Chromium, which Playwright downloads from its own servers; the skills CLI, if you use it, reports each install to skills.sh (DISABLE_TELEMETRY=1stops it). - The hosted page check gets a URL only with
hosted: true,scan --hosted, or ascanwithout--localwhen Playwright is missing. It never gets alocalhostor private address.
How to verify
- On a deployed page with the diagnostics on, the console shows
[GenClass] Model ready (…). Mode: heal.and, once per page,[GenClass] Sends anonymous diagnostics (decisions and counts, no page text) to improve the model. Opt out: …. With--no-telemetrythat notice never appears. Onlocalhostand private hosts nothing is sent either way, so check a public host. - On the runtime handle (the default export of
/auto/heal, orGenClass.runtimewith the script tag),rt.telemetryreads{ enabled: true, endpoint: "https://genclass.dev/api/v1/events", … }, or{ enabled: false, reason: "option" }with the flag. - In the browser's network panel, filter by
genclass.dev: batched POSTs to/api/v1/eventsabout every ten seconds while something happened, or nothing with the flag. Filter byjsdelivr: nothing once the model is self-hosted. - With the model served from your own origin (step 2), a Content-Security-Policy with
connect-src 'self' https://genclass.dev(or'self'alone with the flag) enforces it; with the model from jsDelivr,connect-srcmust also allowhttps://cdn.jsdelivr.net, or GenClass detects nothing.
License, dependencies, versions
Apache-2.0 for every package, with the license and a NOTICE file at the repository root. The runtime has one dependency, onnxruntime-web (Microsoft, MIT); the MCP server has none. The model weights are on npm as @genclass/runtime-model under the same license, with a model card. For a security review: the threat model, the interception surface (every browser API the runtime wraps, what each mode may change, how it restores the originals), the security policy and telemetry. Decisions are made on the device, every action is logged with its evidence, and ?genclass=off on a URL installs nothing on that page.
beta tag (0.3.0-beta.5 as this page is built); the stable 0.2.x line, npm's latest, has none of them: it ignores data-sink, stops init --sink with "unknown option", and has no @genclass/runtime/agent or /sinks entry to import. Pin the version in a script tag, as init does with an integrity hash, and upgrade on purpose. npx @genclass/runtime@beta remove takes out exactly what init added.Your own collector
The diagnostics collector and the dashboards behind genclass.dev are in the repository as telemetry-worker/, a Cloudflare Worker with R2 and D1 storage. Deploy it to your own Cloudflare account and point your pages at it with telemetry: { endpoint: "https://your-collector/v1/events" }: the diagnostics then go to you and no one else. Its README documents the deployment GenClass runs, with its storage, retention and accounts. A dashboard in your own cloud with support, SSO and invoices is Enterprise, and so is the coding-agent loop run as a service.