diff --git a/FAQ.md b/FAQ.md index 221f117f..6fbb3ed3 100644 --- a/FAQ.md +++ b/FAQ.md @@ -171,6 +171,15 @@ Nothing is sold on the site. The pricing page shows the plans in force. Details: [genclass.dev/pricing](https://genclass.dev/pricing), [billing/plans.json](https://github.com/genclass-dev/GenClass/blob/main/billing/plans.json). +## Can I use it without an account? + +Yes. Two commands set up every open-source part, and nothing asks you to sign in: +`npx @genclass/runtime@beta init --agent` (the runtime in observe mode, the dev-only overlay and agent link, and the +app's free dashboard link; `--agent` is new in `0.3.0-beta.6`) and `npx -y @genclass/mcp@0.2.1 init` (the MCP server and the `genclass` skill for Claude Code). +Anonymous diagnostics stay on, as with every `init` (never page text, never from local hosts); +`init --no-telemetry --agent` turns them off and creates no dashboard link. Details: +[INSTALL.md](https://github.com/genclass-dev/GenClass/blob/main/docs/runtime/INSTALL.md#how-do-i-set-up-the-open-source-parts-only). + ## How is it different from Sentry, Datadog or my tests? Error trackers and APM collect exceptions, traces and timings; a stale response or a double submit usually throws diff --git a/README.md b/README.md index 9f180e47..f8168b92 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ Angular, Solid and plain-HTML apps (measured in Chromium with an unpublished 0.1 2026-10-10, not re-run on 0.2.2 or 0.3.0: [compatibility matrix](https://github.com/genclass-dev/GenClass/blob/main/compat/RESULTS.md)). -**Status: `@genclass/runtime@0.3.0-beta.5`, the newest line (npm `beta` dist-tag: `npm install @genclass/runtime@beta`; -the stable line is `0.2.x`), with model `@genclass/runtime-model@0.2.0`.** npm dist-tags on 2026-11-02: `latest` is -`0.2.3` and `beta` is `0.3.0-beta.5` (`0.3.0-beta.1` to `0.3.0-beta.5` were released between 2026-10-22 and -2026-11-02). This README describes the `0.3.0` line; `0.2.x`, npm's `latest`, is the exception for an app that cannot +**Status: `@genclass/runtime@0.3.0-beta.6`, the newest line (npm `beta` dist-tag: `npm install @genclass/runtime@beta`; +the stable line is `0.2.x`), with model `@genclass/runtime-model@0.2.0`.** npm dist-tags on 2026-11-03: `latest` is +`0.2.3` and `beta` is `0.3.0-beta.6` (`0.3.0-beta.1` to `0.3.0-beta.6` were released between 2026-10-22 and +2026-11-03). This README describes the `0.3.0` line; `0.2.x`, npm's `latest`, is the exception for an app that cannot take a prerelease. Both lines load the same model. AI coding agents working on this repository: start at [AGENTS.md](AGENTS.md). @@ -37,6 +37,22 @@ Once you approve, `init` installs the package, adds one import first in your ent devtools overlay in development only) and creates your app's dashboard token (`--no-token` skips it; every flag: [INSTALL.md](docs/runtime/INSTALL.md)). +**Two commands, no account.** They set up every open-source part, and nothing asks you to sign in (`--agent` is new +in `0.3.0-beta.6`): + +```bash +npx @genclass/runtime@beta init --agent # the runtime (observe), the dev-only overlay and agent link, your free dashboard link +npx -y @genclass/mcp@0.2.1 init # the GenClass MCP server and the `genclass` skill for Claude Code +``` + +The first adds one marked import plus an option file with the app's token (plain HTML: the script tag with +`data-token`; Astro: a `` line), creates the app's free dashboard link at genclass.dev (it sends +the package name, nothing else) and keeps anonymous diagnostics on, as every `init` does (never page text, never from +local hosts; `init --no-telemetry --agent` turns them off and creates no link); the second writes +`.mcp.json` and `.claude/skills/genclass/SKILL.md` (other agents: `npx -y @genclass/mcp@0.2.1 config `). Nothing +else is needed; `npx @genclass/runtime@beta remove` undoes the first +([the open-source setup](docs/runtime/INSTALL.md#how-do-i-set-up-the-open-source-parts-only)). + Or by hand: `npm install @genclass/runtime@beta`, then first in your entry file (any bundler; Next.js 15.3 or later: `instrumentation-client.ts`, earlier versions: a client component in the root layout or `pages/_app`): @@ -47,7 +63,7 @@ import "@genclass/runtime/auto"; Or with no build step, first in ``: ```html - + ``` - **That covers network, user actions, errors and timing in the whole app, and its state where it can be found.** @@ -140,7 +156,7 @@ The full tables, with every false-intervention rate next to its recall, are unde ## New: your coding agent can see the race, replay it, and prove the fix -`@genclass/mcp` (`0.2.0`, on npm since 2026-10-25) is an MCP server for Claude Code and other coding agents. Your +`@genclass/mcp` (`0.2.1`, on npm since 2026-10-28) is an MCP server for Claude Code and other coding agents. Your app's development build (`@genclass/runtime` `0.3.0-beta.1` or later) connects to it with one line, and the agent gets every click, request, the order the responses arrived and what they wrote, uncaught errors with the click and request behind them, and the on-device model's detections. It can run your steps again with the network answering in @@ -272,7 +288,7 @@ but the gate fired anyway. Source and history: 10.2 MB q8, about 180 to 600 ms per model pass at 500 to 1,170 tokens on one WASM thread (estimated from runs in Node, not in a browser), loaded from jsDelivr at idle and cached. The model and the situation text it reads (`situation-v2.3`) are the same in `0.2.2` and in every `0.3.0` release so far -(`0.3.0-beta.0` to `0.3.0-beta.5`; each CHANGELOG entry says no model-visible text changed). On held-out data (§1): +(`0.3.0-beta.0` to `0.3.0-beta.6`; each CHANGELOG entry says no model-visible text changed). On held-out data (§1): | profile | guard FIR | guard recall (clear / real) | heal FIR | heal recall (clear / real) | report threshold | |---|---|---|---|---|---| @@ -435,7 +451,7 @@ a new tag and regenerated data (`training/curriculum/rt.py` mirrors the renderer |---|---| | [`packages/runtime`](packages/runtime) | `@genclass/runtime`, the library: observers, causality, stores and adapters, learned baselines, relations and profiles, facts, triage, policy gate, actions, model host (Web Worker, ONNX Runtime Web on WebGPU or WASM), measured visual checks, devtools overlay. [README](packages/runtime/README.md) · [CHANGELOG](packages/runtime/CHANGELOG.md) | | [`packages/runtime-model`](packages/runtime-model) | `@genclass/runtime-model`, the default model package (data only; `files/` is gitignored and filled at release time) and its [model card](packages/runtime-model/MODEL_CARD.md) | -| [`packages/mcp`](packages/mcp) | `@genclass/mcp` (`0.2.0` on npm), the MCP server for coding agents: pages connect through `@genclass/runtime/agent`; the agent gets findings in causal order, replays, explore verdicts, generated regression tests and, with `genclass_scan`, the page audit ([AGENT.md](docs/runtime/AGENT.md)). [README](packages/mcp/README.md) · [CHANGELOG](packages/mcp/CHANGELOG.md) | +| [`packages/mcp`](packages/mcp) | `@genclass/mcp` (`0.2.1` on npm), the MCP server for coding agents: pages connect through `@genclass/runtime/agent`; the agent gets findings in causal order, replays, explore verdicts, generated regression tests and, with `genclass_scan`, the page audit ([AGENT.md](docs/runtime/AGENT.md)). [README](packages/mcp/README.md) · [CHANGELOG](packages/mcp/CHANGELOG.md) | | [`packages/playwright`](packages/playwright) | `@genclass/playwright` (unreleased), GenClass for Playwright: a fixture that puts the runtime on every page under test (observe mode, seeded network chaos with `page.route`, the model skipped by default) and writes one race file per test, and a reporter that turns those files into one markdown report for the pull request, with the evidence line and what reproduced across seeds. [README](packages/playwright/README.md) | | [`packages/nuxt`](packages/nuxt), [`packages/astro`](packages/astro) | `@genclass/nuxt` and `@genclass/astro` (unreleased): the runtime as a Nuxt module and as an Astro integration, one line in the framework's config, with options for the mode, the token, telemetry and the devtools overlay; browser only. [Nuxt README](packages/nuxt/README.md) · [Astro README](packages/astro/README.md) | | [`packages/sv`](packages/sv) | `@genclass/sv` (unreleased), a community add-on for the Svelte CLI: `npx sv add @genclass` sets up GenClass in a SvelteKit app (the dependency, its import first in `src/hooks.client`, the devtools overlay in development). [README](packages/sv/README.md) | diff --git a/docs/adoption/listings/mcp.md b/docs/adoption/listings/mcp.md index 2610a91a..48cdc790 100644 --- a/docs/adoption/listings/mcp.md +++ b/docs/adoption/listings/mcp.md @@ -372,6 +372,9 @@ Source: mxschmitt/awesome-playwright `README.md` (section "AI & Agents", alphabe ## Skill and plugin directories (2026-10-28) +The skill's own listings (skills.sh, `gh skill`, cursor.directory, the curated lists, what the skill file needs where) +are in [skills.md](skills.md) (2026-11-02); this section keeps the plugin and MCP-server directories. + The skill is `skills/genclass/SKILL.md`, at the root of both repositories; the plugin is the root of genclass-plugin. Verified on this machine on 2026-10-28 from the pushed repository: `claude plugin marketplace add`, `codex plugin marketplace add` and `codex plugin add genclass@genclass`, `gemini extensions install`, `gh skill install` (gh 2.103) diff --git a/docs/adoption/listings/skills.md b/docs/adoption/listings/skills.md new file mode 100644 index 00000000..11fafaec --- /dev/null +++ b/docs/adoption/listings/skills.md @@ -0,0 +1,248 @@ +# Listing the `genclass` skill: every skill directory, ready to send + +Where a SKILL.md-based skill (the Agent Skills format, agentskills.io) gets listed, what each place reads, and what +is left to do for `skills/genclass/SKILL.md`. Checked on 2026-11-02; each section names its source. Nothing here has +been submitted. This file takes over the skill items of the last section of `mcp.md` ("Skill and plugin +directories", 2026-10-28); the plugin and MCP-server directories stay there. + +Not readable from the session that wrote this (facts from those sites come from search excerpts, the tool's own +repository or the 2026-10-28 notes in `mcp.md`, and are marked "not verified"): skills.sh, vercel.com, agentskills.io, +docs.github.com, cli.github.com, github.blog, the `gh` manual mirrors, cursor.com, smithery.ai, developers.openai.com, +docs.tessl.io, claude-plugins.dev, skillsmp.com, agenticskills.io, awesomeskill.ai. + +## What is true today (keep every entry to this) + +- **The skill.** `skills/genclass/SKILL.md` at the root of `genclass-dev/GenClass` (the repository was renamed from + `GenClass-lib` on 2026-11-02; the old name still resolves, see below) and at the root of `genclass-dev/genclass-plugin`, + byte-identical to `packages/mcp/plugin/skills/genclass/SKILL.md` (`packages/mcp/test/manifests.test.ts` keeps it so + and `npm run sync -w @genclass/mcp` refreshes it). 80 lines; frontmatter `name: genclass`, `license: Apache-2.0`, + `description` of 509 characters; no scripts, references or assets. It is the procedure; the triggers are its + description and the server's instructions (`docs/runtime/AGENT.md` section 4.2). +- **It is valid.** Against the Agent Skills specification (agentskills/agentskills `docs/specification.mdx`): `name` at + most 64 characters, lowercase letters, digits and hyphens, equal to the directory name; `description` non-empty, at + most 1,024 characters; `license`, `compatibility` (at most 500 characters), `metadata` (string map) and + `allowed-tools` (experimental) optional; body under 500 lines. `claude plugin validate` (Claude Code 2.1.316) passes + on `packages/mcp/plugin` ("These checks found nothing to report") and on `skills/`. The spec's own validator, + `skills-ref validate`, could not be installed in the session (the install was refused), so run it once by hand. +- **What it needs to be useful.** The GenClass MCP server (`@genclass/mcp`, npm) on the developer's machine and a page of + their dev server connected through `@genclass/runtime/agent`. Installed alone, the skill's last section tells the + agent how to add the server; it does nothing by itself. Every entry says "with the GenClass MCP server". +- **Install lines, run on 2026-11-02** with the skills CLI 1.7.4 (npm `skills`, Vercel Labs, published 2026-10-19), + telemetry off, `--list` only: `npx skills add genclass-dev/genclass-plugin`, `npx skills add genclass-dev/GenClass` and + the old `npx skills add genclass-dev/GenClass-lib` each clone the repository and find exactly one skill, `genclass`, + with the description above. The GenClass clone is the whole 109 MB repository, so the install lines keep naming + `genclass-plugin`. `gh skill install genclass-dev/genclass-plugin genclass` was verified on 2026-10-28 with gh 2.103 + (`mcp.md`); the session's gh is 2.89, which has no `skill` command, so it was not re-run. +- **Releases and stars.** `GenClass`'s latest GitHub release is v0.2.1 (2026-10-11), before the skill existed, and + `genclass-plugin` has no release; the tools that read the latest release before the default branch (`gh skill`, + Gemini CLI, per `mcp.md`) therefore work from `genclass-plugin` only. Stars: `GenClass` 7, `genclass-plugin` 0. Lists + with a star or usage threshold (sections 7.1 and 7.2) are closed to it for now. +- **Measured claims.** Only what `mcp.md` states: one page, the race found in 5 of 6 reordered runs, 0 of 6 differing + on the fixed page. No rate beyond that in any entry. +- **GitHub topics.** `genclass-plugin`: `agent-skills`, `claude-code-plugin`, `claude-plugin`, `codex-plugin`, + `gemini-cli-extension`, `mcp`, `mcp-server`, `debugging`, `frontend`, `playwright`, `race-condition`. `GenClass` carries + `claude-code-plugin`, `gemini-cli-extension` and `mcp-server` but not `agent-skills` (41,066 public repositories carry + that topic). Adding it is a repository setting, done by hand. + +### Texts to reuse + +- Ten words or fewer (section 7.1): `Find and prove fixes for timing bugs in web apps.` +- One sentence: `A skill for coding agents with the GenClass MCP server: record what happens inside a web app's pages in causal order, re-run a page with responses delivered in different orders to find race conditions, replay one exact order, and prove the fix with a generated Playwright test.` +- The skill's own description (509 characters) is what the skills CLI, skills.sh and Claude Code show; reuse it where a + form asks for the description and allows it. + +## Order + +1. Nothing to submit: skills.sh lists installs by itself (section 1); the plugin bundle already submitted to Anthropic's + directory is the only route there (section 3); Codex and Gemini CLI read the plugin repository (sections 4, 5). In + this repository: the skills.sh badge, the `--path` install line for Gemini CLI, and the `agent-skills` topic on + `GenClass` (by hand). +2. cursor.directory (web form, detects `skills/*/SKILL.md`; section 6), then github/awesome-copilot (a pull request that + copies the skill into that repository under MIT; section 2.2, needs the owner's decision on the licence). +3. Later, once installs and stars exist: VoltAgent/awesome-agent-skills, travisvn/awesome-claude-skills, + ComposioHQ/awesome-claude-skills (section 7). The crawlers in section 8 need nothing and were not reachable. + +--- + +## 1. skills.sh (Vercel Labs) and the `skills` CLI + +Source: npm `skills` 1.7.4 (`README.md`, `docs/creating-skills.md`, `docs/commands.md`, `docs/agents.md`, +`docs/troubleshooting.md`, and `dist/cli.mjs` for the telemetry); the runs above. skills.sh/about: not verified +(search excerpts only). + +- **What it is.** The CLI installs skills from any public git repository into the skill folders of 79 agents (Claude + Code `.claude/skills/`, Codex, Cursor, Copilot, Gemini CLI, OpenCode, Antigravity and others `.agents/skills/`, + Windsurf `.windsurf/skills/`; `-g` for the user scope, `-a` to pick agents, `--skill` to pick skills, `--copy` instead + of symlinks, `-y`, `--list`). skills.sh is the directory built from its telemetry. +- **How `npx skills add genclass-dev/GenClass` works.** It clones the repository (GitHub shorthand, URL, GitLab, Azure, + any git URL, a local path, or a direct `SKILL.md` or archive URL), then looks for `SKILL.md` in the root, `skills/` + (and its `.curated/`, `.experimental/`, `.system/`), `.agents/skills/`, `.claude/skills/`, `.windsurf/skills/` and + about 50 other agent folders, each walked three levels deep (a shallower `SKILL.md` shadows deeper ones; + `--full-depth` searches outside them), plus skills declared in `.claude-plugin/marketplace.json` or `plugin.json` + (`skills.sh.json` at the root can add folders; nothing found means a recursive search). Then it asks which skills and + agents (non-interactive inside an agent), links one canonical copy into each agent's folder, records the source for + `update`, `check` and `remove`, and sends one install event. +- **The listing is the telemetry.** After an install from a GitHub repository that GitHub confirms is public, the CLI + requests `https://www.skills.sh/tele/t` with `event=install`, `source` (owner/repo), `skills`, `agents`, `global`, the + skill file URLs, the CLI version, `ci=1` in CI and the detected agent; `find` sends the query; `DISABLE_TELEMETRY=1` or + `DO_NOT_TRACK=1` turns it off ("anonymous usage data", "No personal information"). Before an install it asks + `https://www.skills.sh/tele/audit` for the partner security audits of those skills. Not verified (About page + excerpts): the site "indexes public skills shipped through the open skills CLI and ranks them by anonymous install + telemetry", each page shows the source repository, install count, the agents it is most used on and the audit + results, one skill under several repository names is merged at query time, inflated counts are hidden. No + submission, form or claim step was found. +- **Status.** Listed since the owner's installs on 2026-10-28 at `skills.sh/genclass-dev/genclass-lib/genclass` + (`mcp.md`); `genclass-plugin` and the renamed `genclass-dev/genclass` get pages the same way (whether the site merges + the three: not verified). Nothing to do; `metadata.internal` must stay absent (it hides a skill from the CLI). +- **In this repository.** The badge the CLI's own README uses, for `packages/mcp/README.md` and the plugin README: + `[![skills.sh](https://skills.sh/b/genclass-dev/genclass-plugin)](https://skills.sh/genclass-dev/genclass-plugin)` + (format from vercel-labs/skills; whether the badge renders for this repository is not verified). + +## 2. GitHub CLI `gh skill` and GitHub Copilot + +### 2.1 `gh skill` + +Source: `mcp.md` (install verified 2026-10-28); npm `skills` `docs/agents.md` for Copilot's folders. The GitHub +changelog ("Manage agent skills with GitHub CLI", 2026-04-16), docs.github.com and the `gh skill` manual pages were not +reachable: the command details below are from search excerpts of those pages and are not verified. + +- **What it is.** In GitHub CLI 2.90.0 and later, a public preview: `gh skill search`, `preview`, `install`, `update`, + `publish` (`list` in later builds). `install OWNER/REPO [SKILL]` installs from a repository; `@tag` or `@sha` and + `--pin` fix a version; the default agent is Copilot and the default scope the project; `--agent claude-code`, + `cursor`, `codex`, `gemini-cli`, `antigravity` or `--dir` choose where; hidden folders such as `.claude/skills/` need + `--allow-hidden-dirs`. The latest release is read before the default branch (`mcp.md`), hence `genclass-plugin`. + Where Copilot reads project skills (`.github/skills/` per third-party pages) is not verified. +- **No directory to submit to.** `gh skill search` searches GitHub; what it indexes (SKILL.md files, the `agent-skills` + topic, an index of its own) is not verified. `gh skill publish` validates a skill against the specification and + publishes it as a tag or release in its own repository (`--fix` for metadata); it is not a registry and is not used + here: `genclass-plugin` is assembled by `packages/mcp/scripts/plugin-repo.mjs`, re-synced daily and never edited or + tagged by hand (AGENTS.md), and the skill already carries the `license` field `publish` recommends (packages/mcp/CHANGELOG.md, Unreleased). +- **By hand.** Add the `agent-skills` topic to `genclass-dev/GenClass` (repository settings). Nothing else. + +### 2.2 github/awesome-copilot (community collection) + +Source: github/awesome-copilot `README.md`, `CONTRIBUTING.md`, `docs/README.skills.md` (2026-11-02). + +- **How.** A pull request that copies the skill into their repository: `npm run skill:create -- --name genclass + --description "..."` makes `skills/genclass/SKILL.md`, paste the body, `npm run skill:validate`, then `npm run build` + (the README tables are generated; CI fails if they are stale). Branch from and target `main`, not `staged`. Each PR + gets a state label and a risk tier from the `submission-gate` check; bundled scripts or MCP configuration are "High" + risk (this skill has neither; it names tools of a server the user installs). Reviewers are assigned by hand. An + agent opening the PR adds `🤖🤖🤖` to the title; a person does not. Rejected: skills that "mainly restate what + frontier models already do well"; paid services follow their separate guidance. +- **Licence.** "By contributing to this repository, you agree that your contributions will be licensed under the MIT + License." The copy there would be MIT while ours is Apache-2.0: the owner decides; keep `license: Apache-2.0` out of + the copied frontmatter if they agree, or do not submit. +- **The entry.** Generated from the frontmatter: name `genclass`, the description, "Bundled Assets: None", and the + install line `gh skill install github/awesome-copilot genclass`. The PR description: the one-sentence text above, that + it needs the GenClass MCP server (`npx -y @genclass/mcp@0.2.1`) and a dev server on the same machine, and the measured + result. + +## 3. Anthropic's directory and Claude Code marketplaces + +Source: claude.com/docs/directory/publish, code.claude.com/docs/en/plugins/publish, code.claude.com/docs/en/skills, +code.claude.com/docs/en/plugins/create-marketplace (2026-11-02). + +- **Skills are not a listing.** "Skills aren't a submission type on their own. Put them in a bundle." A listing is a + plugin bundle (a GitHub repository, public before it goes live, paid claude.ai plan) or an MCP connector (a remote + server). The plugin bundle `genclass-dev/genclass-plugin`, submitted 2026-10-28 and waiting for a reviewer (`mcp.md` + section 3), carries this skill; once published, its Usage tab reports "how often each skill and MCP server runs". + `claude-plugins-official` takes no submissions through the portal. Nothing to do. +- **Claude Code.** Reads `.claude/skills//SKILL.md` (project, personal, nested, `--add-dir`), a plugin's + `skills//`, managed settings and skills synced from claude.ai, not `.agents/skills/` (so the skills CLI links + into `.claude/skills/` for it). All frontmatter is optional there; the listing shows `description` plus `when_to_use` + cut at 1,536 characters; `license`, `compatibility` and `metadata` are accepted and ignored; claude.ai uploads and the + Skills API reject any key beyond the six spec fields, so the file's three keys are right. Both `GenClass` (root + marketplace, `source: ./packages/mcp/plugin`) and `genclass-plugin` are marketplaces; `/plugin install genclass + --marketplace genclass-dev/genclass-plugin` does both steps (Claude Code 2.1.275 or later). +- **claude-plugins.dev** (indexes public plugin repositories by topic, `mcp.md`): not reachable, not verified. + +## 4. Codex + +Source: github.com/openai/skills and github.com/openai/plugins READMEs (2026-11-02); developers.openai.com not reachable. + +- openai/skills, the catalog (`skills/.system`, `.curated`, `.experimental`, `$skill-installer`), "is deprecated" and + points to the plugins guide; openai/plugins is "a curated collection of Codex plugin examples" (`.codex-plugin/plugin.json`, + `skills/`, `.mcp.json`, `.agents/plugins/marketplace.json`) with no text on submissions; OpenAI's directory takes + local servers from approved partners only (`mcp.md`, not re-verified). The route stays `codex plugin marketplace add + genclass-dev/genclass-plugin` then `codex plugin add genclass@genclass` (verified 2026-10-28), or the skills CLI. Nothing to submit. + +## 5. Gemini CLI + +Source: google-gemini/gemini-cli `docs/cli/skills.md` (2026-11-02). + +- Skills are discovered in `~/.gemini/skills/` or `~/.agents/skills/` (user) and `.gemini/skills/` or `.agents/skills/` + (workspace), plus "skills bundled within installed extensions"; `gemini skills install + --consent`, with `--path` for "a subdirectory of a Git repo containing the skill" and `--scope user|workspace`. No + skills gallery: geminicli.com/extensions crawls the `gemini-cli-extension` topic (`mcp.md`), and `genclass-plugin` + is an extension with the skill inside. +- **In this repository**, one more install line for the READMEs (from the doc page; no Gemini CLI in the session, not + run): `gemini skills install https://github.com/genclass-dev/genclass-plugin.git --path skills/genclass --consent`. + +## 6. Cursor + +Source: cursor/community-plugins `README.md` (the source of cursor.directory, 2026-11-02); `mcp.md` section 10 for the +Cursor Marketplace. Cursor's own skills documentation (cursor.com, docs.cursor.com) was not reachable. + +- **cursor.directory.** "All content is submitted through the website - no pull requests needed for data": + cursor.directory/plugins/new, sign in with GitHub or Google, paste the repository URL, Submit. It detects, under the + Open Plugins standard, `skills/*/SKILL.md`, `.mcp.json`, `hooks/hooks.json`, `rules/*.mdc`, `agents/*.md`, + `.lsp.json`; every submission is reviewed by a Cursor SDK agent (`composer-2`) and stored as safe, suspicious or + malicious. Submit `https://github.com/genclass-dev/genclass-plugin` (the skill, `.mcp.json` and the hook are at its + root). Whether a skill without a plugin manifest is listed is not documented. By hand. +- **Cursor Marketplace** (cursor.com/marketplace/publish, manual review): as in `mcp.md` section 10. By hand. + +## 7. Curated lists (pull requests by a person) + +### 7.1 VoltAgent/awesome-agent-skills + +Source: its `CONTRIBUTING.md` (2026-11-02). Links only; "Skill must have real community usage"; "Brand new skills that +were just created are not accepted"; description "10 words or fewer"; "Author/org prefix included in the name"; PR +title `Add skill: author/skill-name`; at the end of Community Skills, Development and Testing. Later. Draft line: + +``` +- **[genclass-dev/genclass](https://github.com/genclass-dev/genclass-plugin/tree/main/skills/genclass)** - Find and prove fixes for timing bugs in web apps. +``` + +### 7.2 travisvn/awesome-claude-skills + +Source: its `CONTRIBUTING.md` (2026-11-02). One row, `- **[Name](link)** - description`; "if your skill hasn't acquired +a basic 10 stars, it will be closed automatically"; a skill "based around a SaaS" is closed; no PR "generated or +submitted with AI assistance"; more than one file is "a strong guideline". Later, by a person, from `GenClass` (7 stars). + +### 7.3 ComposioHQ/awesome-claude-skills + +Source: its `CONTRIBUTING.md` (2026-11-02). Copies the skill folder into their repository on their template ("When to +Use This Skill", "How to Use", "Example"), one README line in alphabetical order, PR title `Add genclass skill`, an +"Inspired by" or "Credit" line, tested on Claude.ai, Claude Code and/or the API; no licence stated. Later, as 2.2. + +### 7.4 Not routes + +anthropics/skills has no contribution statement (its README highlights partner skills Anthropic chooses); +hesreallyhim/awesome-claude-code takes the plugin (`mcp.md` section 13); block/agent-skills was archived on 2026-09-25. + +## 8. Crawlers and aggregators (nothing to do, not verified) + +Sites that index public GitHub repositories with a `SKILL.md` or mirror the skills CLI's index, none reachable from the +session: SkillsMP (search results say it crawls GitHub, some with a 2-star floor), Smithery skills ("mirrors the skills +CLI's index", `mcp.md`), agenticskills.io (a submit form, a "verified org" badge), awesomeskill.ai, skills-hub.ai +(badges with install counts), skillselion.com, vibeindex.ai, skills.cat, Tessl (`tessl skill publish --public` after +approval, `mcp.md`). Check in a month whether they list `genclass-dev/genclass-plugin`; submit nothing. + +## 9. The skill file against each place + +| field or file | spec | the file | needed anywhere? | +|---|---|---|---| +| `name` | required, at most 64, lowercase, equals the folder | `genclass` | everywhere; done | +| `description` | required, at most 1,024 | 509 characters, the triggers first | everywhere; done (Claude Code shows up to 1,536) | +| `license` | optional, short | `Apache-2.0` | no directory requires it; `gh skill publish` recommends it; it travels with the copies in 2.2 and 7.3 | +| `compatibility` | optional, at most 500 | absent | nowhere. Optional, in this repository: `Needs the GenClass MCP server (npm @genclass/mcp) and the app's dev server on the same machine; Node 20 or later.` Claude Code ignores it; `manifests.test.ts` checks the frontmatter, so run it after | +| `metadata` | optional string map | absent | nowhere; `metadata.internal: true` would hide it from the skills CLI | +| `allowed-tools` | experimental | absent | nowhere; leave out | +| Claude-only keys (`argument-hint`, `paths`, ...) | not in the spec | none | keep none: claude.ai and the Skills API reject them | +| `scripts/`, `references/`, `assets/` | optional | none | none required; travisvn prefers more than one file | +| layout `skills/genclass/SKILL.md` at the root | | both repositories | the skills CLI, `gh skill`, cursor.directory, Claude Code and Codex plugins, Gemini `--path`: all read it | +| a `LICENSE` next to `SKILL.md` | not required | the repository's `LICENSE` | none asks | +| `skills.sh.json` | optional | absent | not needed: `skills/` is a default folder | +| README badge and install lines | | `npx skills add`, `gh skill install` present | add the skills.sh badge (1) and the Gemini line (5) in this repository | +| GitHub topic `agent-skills` | | `genclass-plugin` yes, `GenClass` no | add on `GenClass`, by hand | diff --git a/docs/runtime/AGENT.md b/docs/runtime/AGENT.md index d89b5a4c..66cb8447 100644 --- a/docs/runtime/AGENT.md +++ b/docs/runtime/AGENT.md @@ -57,7 +57,9 @@ Every launcher is pinned to the release. `packages/mcp/server.json` is the entry (published by the release workflow with GitHub OIDC after the npm package); the listings for other directories are drafted in [docs/adoption/listings/mcp.md](../adoption/listings/mcp.md). -In the app's browser entry, development builds only (`@genclass/runtime` 0.3.0-beta.1 or later): +`npx @genclass/runtime@beta init --agent` (0.3.0-beta.6) adds the line for you, next to the import it writes (plain HTML: a +module script after the tag). By hand, in the app's browser entry, development builds only (`@genclass/runtime` +0.3.0-beta.1 or later): ```ts import { GenClass } from "@genclass/runtime"; @@ -437,7 +439,9 @@ This is one page and one bug class, a proof of the mechanism, not a recall figur findings each witness makes stay as they were, so on an app whose cache writes its own bookkeeping (Redux Toolkit Query's statuses, subscriptions) `genclass_findings` still lists those (RESULTS.md section 22 counts them). - WebSocket and EventSource messages are recorded, not reordered; failure responses are not held. Both are next. -- The script-tag build has no agent entry yet (ESM only). +- The script-tag build has no agent attribute; a page without a bundler loads the ESM entry next to it, which + `init --agent` writes: a module script after the tag that, on `localhost`, imports `dist/agent.js` from the script + URL's directory and calls `connectAgent(GenClass.runtime)` (module scripts run after deferred ones, in order). - Production: today the agent reads production through the dashboard (counts by diagnosis and page) and reproduces locally with `focus` on the flagged signature, and with `GENCLASS_REPORT` the dashboard shows what it reproduced and fixed (section 4.5). Sending production witnesses (the recorded order of a real user's diff --git a/docs/runtime/ANALYTICS.md b/docs/runtime/ANALYTICS.md index d6cc9ba3..6c2430cc 100644 --- a/docs/runtime/ANALYTICS.md +++ b/docs/runtime/ANALYTICS.md @@ -6,7 +6,7 @@ app's token (or a custom telemetry endpoint), are turned off by every telemetry never record element text, and never reach the model or a decision. Status: merged into `main` on 2026-10-18 and shipped in `@genclass/runtime` 0.3.0-beta.1 (2026-10-22, npm's `beta` dist-tag); visits, funnels, navigation paths and the version check (sections 1.2, 3.1, 11 and 4.1) followed in 0.3.0-beta.2 (2026-10-25); the newest release is -0.3.0-beta.5 (2026-11-02). npm's `latest`, 0.2.3, has no analytics (section 4.1). +0.3.0-beta.6 (2026-11-03). npm's `latest`, 0.2.3, has no analytics (section 4.1). Design written 2026-10-17 and **approved by the owner the same day** with every recommendation in [section 9](#9-decisions-for-the-owner) (AGENTS.md rule 8: widening what telemetry sends needs that OK). **Built** diff --git a/docs/runtime/API.md b/docs/runtime/API.md index 0ccc968b..e96633c8 100644 --- a/docs/runtime/API.md +++ b/docs/runtime/API.md @@ -1,7 +1,7 @@ # GenClass Runtime API reference (@genclass/runtime) This page describes every export, option, event, action and type of `@genclass/runtime` on `main`. -`npm i @genclass/runtime` installs 0.2.3 (`latest`); `npm i @genclass/runtime@beta` installs 0.3.0-beta.5. Items +`npm i @genclass/runtime` installs 0.2.3 (`latest`); `npm i @genclass/runtime@beta` installs 0.3.0-beta.6. Items marked 0.3.0 are not in 0.2.x; items marked 0.3.0-beta.1 (interaction analytics, the devtools redesign) and later are on npm's `beta` dist-tag since 2026-10-22. diff --git a/docs/runtime/ARCHITECTURE.md b/docs/runtime/ARCHITECTURE.md index d37956ca..99ea0d0e 100644 --- a/docs/runtime/ARCHITECTURE.md +++ b/docs/runtime/ARCHITECTURE.md @@ -3,8 +3,8 @@ GenClass Runtime (`@genclass/runtime`) is a browser library. It watches what a web app does (requests, pushed messages, user actions, timers, state writes, errors) and, for the few situations that look risky, asks a small on-device model whether something is going wrong and what to do. This page explains how the parts fit together and -why they are built this way, for `@genclass/runtime` on `main` (version string 0.3.0-beta.5; npm `latest` is 0.2.3, `beta` is -0.3.0-beta.5) with model +why they are built this way, for `@genclass/runtime` on `main` (version string 0.3.0-beta.6; npm `latest` is 0.2.3, `beta` is +0.3.0-beta.6) with model `@genclass/runtime-model` 0.2.0. Items marked 0.3.0 are in the 0.3.0 line (0.3.0-beta.0 and later) and not in 0.2.x. How to use it: [API.md](API.md). Binding rules: [CONTRACT.md](CONTRACT.md). Every measured number: [RESULTS.md](RESULTS.md). Terms: the [glossary](README.md#glossary). diff --git a/docs/runtime/INSTALL.md b/docs/runtime/INSTALL.md index c71c1fa0..33ca296b 100644 --- a/docs/runtime/INSTALL.md +++ b/docs/runtime/INSTALL.md @@ -2,18 +2,18 @@ How to add `@genclass/runtime` to a web app and take it out again: the `init` and `remove` commands with every flag, the app token and dashboard that `init` creates, the zero-code options, the import, the script tag and its -attributes, `GenClass.init()`, and the projects `init` was tested on. For `@genclass/runtime` 0.3.0 (`0.3.0-beta.0` on the npm +attributes, `GenClass.init()`, and the projects `init` was tested on. For `@genclass/runtime` 0.3.0 (`0.3.0-beta.6` on the npm `beta` dist-tag). The short version is in the [package README](../../packages/runtime/README.md#install). ## Which version should I install? While `0.3.0` is in beta, every npm and npx command here names the `@beta` dist-tag. Without it you get the stable -`0.2.x` (`0.2.2` was npm `latest` on 2026-10-22; `npm view @genclass/runtime dist-tags` shows them now), whose +`0.2.x` (`0.2.3`, npm's `latest` since 2026-10-28; `npm view @genclass/runtime dist-tags` shows them now), whose runtime ignores a token and whose CLI has no `login`, `connect`, `whoami`, `logout`, `dashboard`, `--token` or `--sink`. Both lines load model `@genclass/runtime-model@0.2.0` by default. -Pin the script tag's version (`https://cdn.jsdelivr.net/npm/@genclass/runtime@0.3.0-beta.0`): the unversioned URL -serves the `latest` dist-tag (`0.2.2` on 2026-10-22) until 0.3.0 is released. +Pin the script tag's version (`https://cdn.jsdelivr.net/npm/@genclass/runtime@0.3.0-beta.6`): the unversioned URL +serves the `latest` dist-tag (`0.2.3` on 2026-11-03) until 0.3.0 is released. **Older versions.** `0.1.0-beta.3` has these problems, fixed in `0.2.0`: app builds carried 41 MB of unused ONNX Runtime wasm, a CSP-blocked model failed silently, `init` could not turn telemetry off, and `status.scope.mode` read @@ -60,10 +60,13 @@ Content-Security-Policy (`next.config` headers, a proxy or middleware, a `` | both | the project directory (default: the current directory) | | `--from ` | init | install `@genclass/runtime` from this spec (a version, tag or tarball path) | | `--cdn ` | init | plain HTML: the script URL (default: jsDelivr, this version, with an SRI hash; this version's unpkg URL gets one too; other URLs get no hash) | | `--no-sri` | init | plain HTML: no integrity attribute | +| `--sync` | init | plain HTML: a blocking script tag (the default is `defer`: the page never waits for the CDN; GenClass then starts after classic scripts that have neither `defer` nor `async`) | +| `--no-network` | init | do not ask npm for newer releases (`--dry-run`, `--no-token` and `--no-telemetry` do not ask either) | | `--strategy instrumentation\|layout\|pages` | init | Next.js only: where the import goes. By default `instrumentation-client` on Next.js 15.3 and later, else `layout` (App Router) or `pages` (Pages Router) | | `--keep-package` | remove | leave `@genclass/runtime` installed (by default `remove` uninstalls it if nothing else imports it) | @@ -136,6 +139,34 @@ reached, `init` says so, sets GenClass up without a token, and points you to [genclass.dev/start](https://genclass.dev/start); run `init --token gc_...` later. `--dry-run` sends nothing and installs nothing. +## How do I set up the open-source parts only? + +Two commands, no account, nothing to sign in to (`--agent` is new in `0.3.0-beta.6`): + +```bash +npx @genclass/runtime@beta init --agent # the runtime in observe, the dev-only overlay and agent link, your free dashboard link +npx -y @genclass/mcp@0.2.1 init # the GenClass MCP server and the `genclass` skill for Claude Code +``` + +The first finds your framework, installs `@genclass/runtime`, adds one marked import (plain HTML: the script tag, +pinned with an integrity hash) with the dev-only devtools and agent lines, and, once you approve the diff, creates the +app's free dashboard link at genclass.dev (it sends the package name, nothing else) and writes the token into a marked +`genclass.config.ts` (or `.js`) next to your entry (`data-token` on a script tag). GenClass's anonymous diagnostics +stay on, as with every `init` (never page text, never from local hosts; +[TELEMETRY.md](../../packages/runtime/TELEMETRY.md)): `init --no-telemetry --agent` turns them off and implies +`--no-token`; `--no-token` alone skips the link. Browsers still download the model and +onnxruntime-web, public files, from jsDelivr unless you serve them (`--model-url`, +[Content-Security-Policy and self-hosting](../../packages/runtime/README.md#content-security-policy-and-self-hosting)). +Add `--mode guard` to let GenClass act, `--sink console-json` for findings in your own logs. + +The second writes the server into `.mcp.json` and the `genclass` skill (the procedure Claude Code follows for timing +bugs) to `.claude/skills/genclass/SKILL.md`; it runs on your machine and needs no account +([`@genclass/mcp`](../../packages/mcp/README.md); other agents: `npx -y @genclass/mcp@0.2.1 config `). Run the dev +server: until the MCP server runs, the page logs one failed request to `127.0.0.1:47357`, the agent link finding no +server: reload the page once it runs (the link tries once per page load). `npx @genclass/runtime@beta remove` takes the +first command's changes out; delete `.mcp.json`'s entry and +`.claude/skills/genclass/` for the second. + ## How do I install it by hand? **One import** (any bundler; the package is ESM only, there is no `require` build), first in your entry file, so it @@ -162,7 +193,7 @@ During SSR or in Node, `/auto` installs nothing and returns an inert runtime. **One script tag** (no build step), first in ``: ```html - + ``` It exposes `window.GenClass` (since `0.3.0` also `window.GenClass.protect`), discovers the app's state like the diff --git a/docs/runtime/OPTIONS-SPEC.md b/docs/runtime/OPTIONS-SPEC.md index df3c0a13..0277f360 100644 --- a/docs/runtime/OPTIONS-SPEC.md +++ b/docs/runtime/OPTIONS-SPEC.md @@ -3,7 +3,7 @@ This page is the design spec for the configuration options of `@genclass/runtime`: why each option exists and how the options combine. The reference for each option is [API.md](API.md) and the JSDoc in `packages/runtime/src/types.ts`; where they differ from this spec, they describe the code. `npm i @genclass/runtime@beta` -installs 0.3.0-beta.5 (npm's `beta` dist-tag, 2026-11-02); plain `npm i @genclass/runtime` installs the stable line, +installs 0.3.0-beta.6 (npm's `beta` dist-tag, 2026-11-03); plain `npm i @genclass/runtime` installs the stable line, 0.2.3 (`latest`). Items marked 0.3.0 are not in 0.2.x. Status: built. Most options here shipped in 0.1.0-beta.1 (the CHANGELOG's "Batch 12, 19 options") and are in every diff --git a/docs/runtime/README.md b/docs/runtime/README.md index dd247f26..85c8e2ef 100644 --- a/docs/runtime/README.md +++ b/docs/runtime/README.md @@ -1,8 +1,8 @@ # GenClass documentation This is the index of the GenClass Runtime documentation: which document answers which question, how current each one -is, and where genclass.dev shows it. It covers `@genclass/runtime` on `main` (version string 0.3.0-beta.5; -`npm i @genclass/runtime@beta` installs 0.3.0-beta.5, `npm i @genclass/runtime` installs 0.2.3) and the model +is, and where genclass.dev shows it. It covers `@genclass/runtime` on `main` (version string 0.3.0-beta.6; +`npm i @genclass/runtime@beta` installs 0.3.0-beta.6, `npm i @genclass/runtime` installs 0.2.3) and the model `@genclass/runtime-model` 0.2.0. Items marked 0.3.0 are in the 0.3.0 line (0.3.0-beta.0 and later) and not in 0.2.x. The [glossary](#glossary) at the end defines the terms the other documents use. diff --git a/docs/runtime/SINKS.md b/docs/runtime/SINKS.md index a0bcae6f..2d793b93 100644 --- a/docs/runtime/SINKS.md +++ b/docs/runtime/SINKS.md @@ -32,7 +32,7 @@ npx @genclass/runtime@beta init --sink webhook:/genclass # or console-json; re ```html - + ``` diff --git a/package-lock.json b/package-lock.json index 3018f76f..494f6f23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16964,7 +16964,7 @@ }, "packages/runtime": { "name": "@genclass/runtime", - "version": "0.3.0-beta.5", + "version": "0.3.0-beta.6", "license": "Apache-2.0", "dependencies": { "onnxruntime-web": "1.30.0" diff --git a/packages/mcp/README.md b/packages/mcp/README.md index baf016c8..f8b57330 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -307,9 +307,10 @@ read a report, what to say when done, what to do when the tools are missing) is To remove it: delete `.claude/skills/genclass/` (or the directory the skill tool wrote to); with the plugin, `/plugin uninstall genclass@genclass`. -Then connect the app's development build (once). The agent link needs the newest runtime line, `@genclass/runtime` -0.3.0-beta.1 or later: `npm install @genclass/runtime@beta` (a bare `npm install @genclass/runtime` gets npm's -`latest`, the older 0.2.x, which has no agent entry): +Then connect the app's development build (once): `npx @genclass/runtime@beta init --agent` (0.3.0-beta.6 or later) adds a dev-only line next to +the import it writes (plain HTML: a module script after the tag), installing the runtime first if needed. By hand, the +agent link needs the newest runtime line, `@genclass/runtime` 0.3.0-beta.1 or later: `npm install @genclass/runtime@beta` +(a bare `npm install @genclass/runtime` gets npm's `latest`, the older 0.2.x, which has no agent entry): ```ts import { GenClass } from "@genclass/runtime"; diff --git a/packages/mcp/src/tools.ts b/packages/mcp/src/tools.ts index 47aa1314..6b92b136 100644 --- a/packages/mcp/src/tools.ts +++ b/packages/mcp/src/tools.ts @@ -559,6 +559,7 @@ export function setupText(cwd: string, client?: string | null): string { const guard = next ? `process.env.NODE_ENV === "development"` : vite ? "import.meta.env.DEV" : `process.env.NODE_ENV !== "production"`; const where = next ? "a client component loaded once from the root layout (\"use client\")" : vite ? "the app's entry (src/main.tsx or src/main.ts), before the app renders" : "the app's browser entry, before the app starts"; const lines = [ + "One command does the app side: npx @genclass/runtime@beta init --agent (@genclass/runtime 0.3.0-beta.6 or later; it installs the runtime if needed and adds a dev-only agent line next to the import it writes; --no-telemetry too for no diagnostics). By hand:", installed ? "@genclass/runtime is installed." : `1. Install the newest runtime, 0.3.0-beta.1 or later (the agent entry and analytics; 0.2.x has neither${has("@genclass/runtime") ? `; this project has ${JSON.stringify(range)}${have !== range ? `, installed ${have}` : ""}` : ""}): npm install @genclass/runtime@beta`, diff --git a/packages/mcp/test/manifests.test.ts b/packages/mcp/test/manifests.test.ts index f443f0c6..c5024172 100644 --- a/packages/mcp/test/manifests.test.ts +++ b/packages/mcp/test/manifests.test.ts @@ -76,6 +76,10 @@ const PINS: Pin[] = [ { file: "docs/runtime/AGENT.md", text: (s) => s.replace(PINNED, pinned(V)) }, { file: "README.md", text: (s) => s.replace(PINNED, pinned(V)) }, { file: "packages/runtime/README.md", text: (s) => s.replace(PINNED, pinned(V)) }, + { file: "docs/runtime/INSTALL.md", text: (s) => s.replace(PINNED, pinned(V)) }, + { file: "FAQ.md", text: (s) => s.replace(PINNED, pinned(V)) }, + // the runtime CLI's own text (init --help, the Next line after init --agent) names the server's launcher + { file: "packages/runtime/bin/lib/version.mjs", text: (s) => s.replace(PINNED, pinned(V)) }, ]; function read(file: string): string { diff --git a/packages/runtime/CHANGELOG.md b/packages/runtime/CHANGELOG.md index 2f6fa3ce..65967a7c 100644 --- a/packages/runtime/CHANGELOG.md +++ b/packages/runtime/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.3.0-beta.6 (2026-11-03) + +- **The open-source setup is two commands** (`bin/lib/`, owner request 2026-11-02). `init --agent` adds the dev-only + agent link next to the import it writes, the same way it adds the devtools line: `if () + import("@genclass/runtime/agent").then((a) => a.connectAgent(genclass))` in every framework it knows (one `if` block + in the files it creates for Next.js; plain HTML gets a module script after the tag, which loads `dist/agent.js` from + the script URL's directory on `localhost` and connects `GenClass.runtime`; module scripts run after deferred ones, + in order). `remove` takes it out, wrapped by a formatter or not, and refuses an edited one. So + `npx @genclass/runtime@beta init --agent` and `npx -y @genclass/mcp@0.2.1 init` set up every open-source part with no + account (anonymous diagnostics on and a free dashboard link, as with every `init`; `--no-telemetry` for neither; + owner decision 2026-11-02), and the READMEs, INSTALL.md ("How do I set up the open-source parts only?"), + FAQ, AGENT.md, the MCP server's setup text and genclass.dev/start/open-source say so with those two commands instead + of a nine-step hand edit. No runtime code, no model-visible text, no change to what is sent. Tests: + `test/install/cli.test.ts` ("init --agent"). + ## 0.3.0-beta.5 (2026-11-02) Security fixes from the adversarial review of the mode-raise fix (`0.3.0-beta.2`); the same four fixes are in `0.2.3` diff --git a/packages/runtime/INTERCEPTION.md b/packages/runtime/INTERCEPTION.md index a27a2029..fb810483 100644 --- a/packages/runtime/INTERCEPTION.md +++ b/packages/runtime/INTERCEPTION.md @@ -7,9 +7,9 @@ browser global, compares what changed with the inventory at the end of this page and counts the patch sites in `src/` (a new `addEventListener`, `defineProperty` or global assignment fails the test until this page is updated). -> **Version.** Written for `@genclass/runtime` 0.3.0-beta.5 as it is on GitHub `main` (released 2026-11-02). The -> copy in an npm package describes that package's version. As of 2026-11-02, `npm i @genclass/runtime@beta` installs -> 0.3.0-beta.5 (the 0.3.0 line: 0.3.0-beta.1 to 0.3.0-beta.5, released 2026-10-22 to 2026-11-02), and +> **Version.** Written for `@genclass/runtime` 0.3.0-beta.6 as it is on GitHub `main` (released 2026-11-03). The +> copy in an npm package describes that package's version. As of 2026-11-03, `npm i @genclass/runtime@beta` installs +> 0.3.0-beta.6 (the 0.3.0 line: 0.3.0-beta.1 to 0.3.0-beta.6, released 2026-10-22 to 2026-11-03), and > `npm i @genclass/runtime` installs 0.2.3 (`latest`, 2026-10-28), which has no measured visual checks, no `protect()`, > no webhook sink and no interaction analytics. Items marked 0.3.0 are not in 0.2.x; the interaction analytics rows > (`src/analytics/`) and the devtools overlay's `theme: "dark"` default are 0.3.0-beta.1, the `genclass.analytics.` diff --git a/packages/runtime/README.md b/packages/runtime/README.md index 88df3d9d..c9ea7d0e 100644 --- a/packages/runtime/README.md +++ b/packages/runtime/README.md @@ -35,6 +35,22 @@ Once you approve the diff, `init` also creates your app's free dashboard at genc `package.json` `name`; `--no-token`, `--token`, `--no-telemetry` and `--dry-run` create no dashboard and never contact genclass.dev ([Your dashboard](#your-dashboard)). +**Two commands, no account.** They set up every open-source part, and nothing asks you to sign in (`--agent` is new +in `0.3.0-beta.6`): + +```bash +npx @genclass/runtime@beta init --agent # the runtime (observe), the dev-only overlay and agent link, your free dashboard link +npx -y @genclass/mcp@0.2.1 init # the GenClass MCP server and the `genclass` skill for Claude Code +``` + +The first adds one marked import plus an option file with the app's token (plain HTML: the script tag with +`data-token`; Astro: a `` line), creates the app's free dashboard link at genclass.dev (it sends +the package name, nothing else) and keeps anonymous diagnostics on, as every `init` does (never page text, never from +local hosts; `init --no-telemetry --agent` turns them off and creates no link); the second writes +`.mcp.json` and `.claude/skills/genclass/SKILL.md` (other agents: `npx -y @genclass/mcp@0.2.1 config `). Nothing +else is needed; `npx @genclass/runtime@beta remove` undoes the first +([the open-source setup](https://github.com/genclass-dev/GenClass/blob/main/docs/runtime/INSTALL.md#how-do-i-set-up-the-open-source-parts-only)). + Or by hand: ```bash @@ -50,7 +66,7 @@ import "@genclass/runtime/auto"; // first line of your entry file (Next.js 15.3+ Or with no build step, first in ``: ```html - + ``` That is the whole setup. Network traffic, user actions, errors and timing are observed, and so is your app's state: @@ -59,7 +75,7 @@ React component state, Redux and Redux Toolkit stores, and Zustand stores with ` are not: there, stale responses are reported only for stores you register (double submits need no state). **Versions:** this README describes `0.3.0` with model `@genclass/runtime-model@0.2.0`. The newest line is -`0.3.0-beta.5`, npm's `beta` dist-tag (`0.3.0-beta.1` to `beta.5` were released between 2026-10-22 and 2026-11-02); +`0.3.0-beta.6`, npm's `beta` dist-tag (`0.3.0-beta.1` to `beta.6` were released between 2026-10-22 and 2026-11-03); npm's `latest` is still the older `0.2.3` (`npm view @genclass/runtime dist-tags` shows them now). Every npm and npx command here names `@beta`: without it npm installs `0.2.x`, which has no token, dashboard, interaction analytics, visual checks or agent link and ignores those options without a word (a TypeScript app gets a type error for @@ -468,7 +484,9 @@ npx @genclass/runtime@beta remove # undo exactly what init added Other flags: `--yes`, `--no-telemetry` (`--telemetry` undoes it on a later run and writes no telemetry option, so the default applies: on, but off on local hosts), `--no-token`, `--token gc_...`, `--sink`, `--model-url`, `--no-install`, -`--no-devtools`, and from `0.3.0-beta.2` `--no-network` and `--sync` (plain HTML). +`--no-devtools`, `--agent` (from `0.3.0-beta.6`: the dev-only agent link too, so your coding agent sees the dev +pages; [Your coding agent](#your-coding-agent-replay-and-explore)), and from `0.3.0-beta.2` `--no-network` and +`--sync` (plain HTML). **Which version** (from `0.3.0-beta.2`). `init` (and `login`, `connect`) first prints its own version and the npm dist-tag it came from, asks npm's dist-tags once (`npm view @genclass/runtime dist-tags`, at most 3 s; never with @@ -476,11 +494,11 @@ dist-tag it came from, asks npm's dist-tags once (`npm view @genclass/runtime di on npm, with the command that runs it: ``` - ✔ Version @genclass/runtime 0.3.0-beta.4 (npm dist-tag beta) - ▲ Newer @genclass/runtime 0.3.0-beta.5 is on npm (dist-tag beta): run npx @genclass/runtime@beta init instead + ✔ Version @genclass/runtime 0.3.0-beta.5 (npm dist-tag beta) + ▲ Newer @genclass/runtime 0.3.0-beta.6 is on npm (dist-tag beta): run npx @genclass/runtime@beta init instead ``` -It installs its own version (`@genclass/runtime@^0.3.0-beta.5` today), and a project that already has an older one +It installs its own version (`@genclass/runtime@^0.3.0-beta.6` today), and a project that already has an older one (a `0.2.x` from `npx @genclass/runtime init` without `@beta`) is upgraded, after the same diff and question. Every command it prints names `@beta` while it is a prerelease. @@ -509,7 +527,7 @@ Options go in `window.GENCLASS_CONFIG = { ... }` (any `InitOptions`, set before **3. One script tag** (no build step), first in ``: ```html - + ``` It exposes `window.GenClass` and loads the model worker and the overlay on demand from the same version; `data-mode`, @@ -675,9 +693,14 @@ Claude Code and other coding agents, and lets the agent: - **keep the proof:** a generated Playwright test that sets the same order and fails while the bug is there. ```bash -claude mcp add genclass -- npx -y @genclass/mcp@0.2.1 +npx @genclass/runtime@beta init --agent # the app side: a dev-only line next to the import init writes (0.3.0-beta.6) +npx -y @genclass/mcp@0.2.1 init # the server in .mcp.json and the `genclass` skill, for Claude Code ``` +Other agents: `npx -y @genclass/mcp@0.2.1 config `, or `claude mcp add genclass -- npx -y @genclass/mcp@0.2.1`. By +hand, the app side is one line in a development build (plain HTML: a module script after the tag, which `init --agent` +writes too): + ```ts import { GenClass } from "@genclass/runtime"; import { connectAgent } from "@genclass/runtime/agent"; diff --git a/packages/runtime/TELEMETRY.md b/packages/runtime/TELEMETRY.md index 56c770d7..1101715a 100644 --- a/packages/runtime/TELEMETRY.md +++ b/packages/runtime/TELEMETRY.md @@ -4,10 +4,10 @@ GenClass Runtime (`@genclass/runtime`), an open-source browser library that repo sends anonymous diagnostics about its own decisions to its maintainers, by default on public websites; this page lists every event and field it sends, where they are stored and for how long, and every way to turn it off. -> **Version.** Written for `@genclass/runtime` 0.3.0-beta.5 (2026-11-02), the version on GitHub `main`, in +> **Version.** Written for `@genclass/runtime` 0.3.0-beta.6 (2026-11-03), the version on GitHub `main`, in > `package.json` and in the `runtime` field of every batch. The copy in an npm package describes that package's version. -> As of 2026-11-02, `npm i @genclass/runtime@beta` installs 0.3.0-beta.5 (the newest line; 0.3.0-beta.1 to beta.5 were -> released 2026-10-22 to 2026-11-02) and `npm i @genclass/runtime` installs the stable line, 0.2.3 (`latest`, +> As of 2026-11-03, `npm i @genclass/runtime@beta` installs 0.3.0-beta.6 (the newest line; 0.3.0-beta.1 to beta.6 were +> released 2026-10-22 to 2026-11-03) and `npm i @genclass/runtime` installs the stable line, 0.2.3 (`latest`, > 2026-10-28). Items > marked 0.3.0 are not in 0.2.x; interaction analytics are marked 0.3.0-beta.1, visits and navigation paths > 0.3.0-beta.2. @@ -106,7 +106,7 @@ segment holding an `@`, such as an e-mail address, is `:id` too). "token": "gc_…", // only when the app configured a valid token (InitOptions.token); see "App tokens" "sid": "3f9c…", // 24 hex chars from crypto.getRandomValues, new on every page load, never stored "sent": 12034, // ms since this page's GenClass started (no wall-clock time is sent) - "runtime": "0.3.0-beta.5", // @genclass/runtime version + "runtime": "0.3.0-beta.6", // @genclass/runtime version "model": "2.0.0-rc4t", // model card version, or null without a model "events": [ /* ≤ 100 events, ≤ 60 KB per request */ ] } diff --git a/packages/runtime/bin/genclass-runtime.mjs b/packages/runtime/bin/genclass-runtime.mjs index e635c6c5..b374f389 100755 --- a/packages/runtime/bin/genclass-runtime.mjs +++ b/packages/runtime/bin/genclass-runtime.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node // genclass-runtime CLI (Node >= 20, no dependencies). Also runs as `npx @genclass/runtime `. // -// genclass-runtime init [--mode observe|guard|heal] [--token | --no-token] [--yes] [--dry-run] [--no-install] [--no-devtools] +// genclass-runtime init [--mode observe|guard|heal] [--token | --no-token] [--agent] [--yes] [--dry-run] [--no-install] [--no-devtools] // genclass-runtime remove [--yes] [--dry-run] [--keep-package] // Set GenClass up in a project (framework detection, install, one marked import in the entry file, an app token // and private dashboard link from genclass.dev) and take it out again. Implemented in bin/lib/ (owner: INSTALL). @@ -57,7 +57,7 @@ const ORT_FILES = { const ROLES = ["tokenizer", "calibration", "meta"]; const USAGE = `Usage: - genclass-runtime init [--mode observe|guard|heal] [--token | --no-token] [--yes] [--dry-run] [--no-install] [--no-devtools] + genclass-runtime init [--mode observe|guard|heal] [--token | --no-token] [--agent] [--yes] [--dry-run] [--no-install] [--no-devtools] genclass-runtime remove [--yes] [--dry-run] [--keep-package] genclass-runtime login [--yes] [--no-browser] [--no-connect] genclass-runtime connect [--app ] [--name ] [--yes] [--dry-run] [--no-install] diff --git a/packages/runtime/bin/lib/edit.mjs b/packages/runtime/bin/lib/edit.mjs index 94e21997..ba2a24a6 100644 --- a/packages/runtime/bin/lib/edit.mjs +++ b/packages/runtime/bin/lib/edit.mjs @@ -1,9 +1,10 @@ // Text edits for `genclass-runtime init|remove`. Everything init adds carries a marker: // - single lines: `import genclass from "@genclass/runtime/auto"; // genclass:init` // - blocks (files init creates): from a line containing `genclass:init start` to one containing `genclass:init end` -// - three inline forms, used only when the place to insert shares its line with other code (a one-line or -// ): `{/* genclass:inline */}`, `` (Astro) and -// `` (HTML) +// - four inline forms, used only when the place to insert shares its line with other code (a one-line or +// ): `{/* genclass:inline */}`, `` (Astro), +// `` (HTML) and `` +// (HTML with --agent: the agent link's module script) // `planRemoval` deletes exactly those (a marked statement together with its line break), so a file init only added // to comes back byte for byte, and refuses (reports a problem, deletes nothing there) when a marked line or block is // not what init wrote. `switchMode` re-points the same marked code at another mode. @@ -119,6 +120,8 @@ export const AUTO = (mode) => (mode ? `@genclass/runtime/auto/${mode}` : "@gencl const AUTO_SPEC = String.raw`"@genclass/runtime/auto(?:/(?:observe|guard|heal))?"`; const DEVTOOLS_CALL = String.raw`import\("@genclass/runtime/devtools"\)\.then\(d=>d\.mountDevtools\(genclass\)\)`; +// the dev-only agent link (init --agent): the same shape, @genclass/runtime/agent's connectAgent on the runtime +const AGENT_CALL = String.raw`import\("@genclass/runtime/agent"\)\.then\(a=>a\.connectAgent\(genclass\)\)`; const COND = String.raw`[^;{}]+?`; const IMPORT_AUTO = String.raw`import(?:genclassfrom)?${AUTO_SPEC};?`; // the options file init writes with --no-telemetry / --telemetry / --model-url, imported right before /auto @@ -126,8 +129,12 @@ const IMPORT_CONFIG = String.raw`import"(?:\.{1,2}/)+(?:[\w.-]+/)*genclass\.conf const CONFIG_STATEMENT = String.raw`(?:\(globalThisas\{GENCLASS_CONFIG\?:\w+\}\)|globalThis)\.GENCLASS_CONFIG=\{[^;]*\};?`; const META_CONFIG = String.raw``; const DEV_LINE = String.raw`if\(${COND}\)${DEVTOOLS_CALL};?`; -// the same with braces (ESLint's `curly` fix) -const DEV_BLOCK = String.raw`if\(${COND}\)\{${DEVTOOLS_CALL};?\}`; +const AGENT_LINE = String.raw`if\(${COND}\)${AGENT_CALL};?`; +// the same with braces (ESLint's `curly` fix), and the one block Next.js's created files hold both calls in +const DEV_BLOCK = String.raw`if\(${COND}\)\{(?:${DEVTOOLS_CALL};?(?:${AGENT_CALL};?)?|${AGENT_CALL};?)\}`; +const AGENT_BLOCK = String.raw`if\(${COND}\)\{${AGENT_CALL};?\}`; +// plain HTML with --agent: a module script after the runtime's tag (module scripts run after deferred ones, in order) +const AGENT_SCRIPT = String.raw`if\(\["localhost","127\.0\.0\.1"\]\.includes\(location\.hostname\)\)import\("[^"]*"\)\.then\(a=>a\.connectAgent\(GenClass\.runtime\)\);?`; /** Statements init writes on one marked line (normalised, see norm()). */ const LINE_RE = new RegExp( "^(?:" + @@ -137,11 +144,13 @@ const LINE_RE = new RegExp( META_CONFIG, DEV_LINE, DEV_BLOCK, + AGENT_LINE, + AGENT_SCRIPT, String.raw`import\{isDevModeasgenclassDevMode\}from"@angular/core";?`, String.raw`import\{GenClassInit\}from"[^"]*genclass-init";?`, String.raw``, String.raw`]*>`, - String.raw``, + String.raw``, ].join("|") + ")$", ); @@ -155,20 +164,23 @@ const BLOCK_RE = new RegExp( CONFIG_STATEMENT, DEV_LINE, DEV_BLOCK, + AGENT_LINE, String.raw`importtype\{AppProps\}from"next/app";?`, String.raw`exportfunctionGenClassInit\(\)\{returnnull;?\}`, - String.raw`exportdefaultdefineNuxtPlugin\(\(\)=>\{(?:${DEV_LINE}|${DEV_BLOCK})?\}\);?`, + String.raw`exportdefaultdefineNuxtPlugin\(\(\)=>\{(?:${DEV_LINE}|${DEV_BLOCK})?(?:${AGENT_LINE}|${AGENT_BLOCK})?\}\);?`, String.raw`exportdefaultfunctionApp\(\{Component,pageProps\}(?::AppProps)?\)\{return\(?\)?;?\}`, ].join("|") + ")*$", ); // Inline forms (init puts them on a line shared with other code); whitespace a formatter adds between the element and // its marker is taken out with them. `ok` checks the element is still what init wrote (an Astro $`); +const INLINE_SCRIPT_RE = new RegExp(String.raw`^$`); +const AGENT_SCRIPT_RE = new RegExp(`^${AGENT_SCRIPT}$`); const INLINE = [ { re: /\s*\{\s*\/\*\s*genclass:inline\s*\*\/\s*\}/g }, { re: /` : null; +} const unpkgUrl = (version, min) => `https://unpkg.com/@genclass/runtime@${version}/dist/genclass.global${min ? ".min" : ""}.js`; /** @@ -305,6 +337,7 @@ function planHtml(p, o, ctx) { const files = htmlFiles(p.dir); if (!files.length) return { changes: [], manual: "no .html file with a in this directory" }; const tag = scriptTag(o, ctx.pkgDir, ctx.version); + const agent = o.agent ? agentTag(o, ctx.version) : null; const changes = []; for (const f of files) { const before = readText(f) ?? ""; @@ -313,18 +346,21 @@ function planHtml(p, o, ctx) { const line = lines[li]; let after; if (/<\/head>/i.test(line)) { - // a one-line head: put the tag right after + // a one-line head: put the tag (and the agent script) right after const m = /]*>/i.exec(before); const at = m.index + m[0].length; - after = before.slice(0, at) + `${tag}` + before.slice(at); + after = before.slice(0, at) + `${tag}` + (agent ? `${agent}` : "") + before.slice(at); } else { const next = lines.slice(li + 1).find((l) => l.trim() !== ""); const indent = next !== undefined ? indentOf(next) : indentOf(line) + indentUnit(before); after = insertLineAt(before, li + 1, `${indent}${tag} `); + if (agent) after = insertLineAt(after, li + 2, `${indent}${agent} `); } changes.push({ file: f, kind: "modify", before, after }); } const notes = []; + if (o.agent && !agent) + notes.push(`The agent link was not added: --cdn ${o.cdn} does not end in genclass.global.js or genclass.global.min.js, so the CLI cannot know where that copy's agent.js is. Add the module script by hand (docs/runtime/AGENT.md).`); if (o.sri !== false && !/ integrity="/.test(tag)) { notes.push( o.cdn diff --git a/packages/runtime/bin/lib/version.mjs b/packages/runtime/bin/lib/version.mjs index a5e178b3..1384d1bb 100644 --- a/packages/runtime/bin/lib/version.mjs +++ b/packages/runtime/bin/lib/version.mjs @@ -12,6 +12,8 @@ import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; export const PKG = "@genclass/runtime"; +/** The MCP server's launcher, pinned to its release (packages/mcp/test/manifests.test.ts keeps it current; `npm run sync -w @genclass/mcp`). */ +export const MCP_PKG = "@genclass/mcp@0.2.1"; export const PKG_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."); /** This package's version ("latest" if package.json cannot be read). */ diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 7767a005..7f0e35c7 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@genclass/runtime", - "version": "0.3.0-beta.5", + "version": "0.3.0-beta.6", "description": "Browser library that reports race conditions in web apps while they happen (stale responses, double submits, inconsistent state, failure storms) using a small on-device model. Report-only by default; an opt-in guard mode can prevent a few of them.", "type": "module", "license": "Apache-2.0", diff --git a/packages/runtime/src/version.ts b/packages/runtime/src/version.ts index f9ed7c94..c6e14e88 100644 --- a/packages/runtime/src/version.ts +++ b/packages/runtime/src/version.ts @@ -2,4 +2,4 @@ // test/telemetry.test.ts ("RUNTIME_VERSION matches package.json"); bump both together: .github/workflows/release.yml // checks that the v tag equals package.json and that this file holds the same string. -export const RUNTIME_VERSION = "0.3.0-beta.5"; +export const RUNTIME_VERSION = "0.3.0-beta.6"; diff --git a/packages/runtime/test/install/cli.test.ts b/packages/runtime/test/install/cli.test.ts index c4be0fda..6f828b9e 100644 --- a/packages/runtime/test/install/cli.test.ts +++ b/packages/runtime/test/install/cli.test.ts @@ -13,7 +13,7 @@ import { appendEnd, bodyTagEnd, codeStyle, insertTop, planRemoval, removeMarked, import { integrityFor, nodeOnlyImport, scriptTag } from "../../bin/lib/plan.mjs"; // @ts-expect-error plain ESM module without types import { libraryEvidence } from "../../bin/lib/detect.mjs"; -import { CMD, VERSION, channelOf, cmdFor, compareVersions, versionInSpec, versionStatus } from "../../bin/lib/version.mjs"; +import { CMD, MCP_PKG, VERSION, channelOf, cmdFor, compareVersions, versionInSpec, versionStatus } from "../../bin/lib/version.mjs"; import { assetBase } from "../../src/cdn/global.js"; import { GenClass } from "../../src/index.js"; import { DEFAULT_MODEL_BASE_URL } from "../../src/model/host.js"; @@ -1228,3 +1228,118 @@ describe("the newest line: version line, npm dist-tags, older runtimes upgraded expect(r.out).toContain(`installs @genclass/runtime (this version, ${VERSION}; an older one already in the`); }); }); + +describe("init --agent: the dev-only agent link next to the overlay (the open-source setup's app side)", () => { + const VITE_TS = { + "package.json": pkg({ react: "^19.0.0", vite: "^7.0.0", "@vitejs/plugin-react": "^5" }), + "tsconfig.json": "{}\n", + "index.html": VITE_HTML, + "src/main.tsx": `import { createRoot } from 'react-dom/client'\nimport App from './App.tsx'\n\ncreateRoot(document.getElementById('root')!).render()\n`, + "src/App.tsx": `export default function App() { return }\n`, + }; + + it("Vite: the overlay line, then the agent line, both marked; the top import binds the runtime", () => { + const dir = project(VITE_TS); + const r = cli(dir, "init", "--yes", "--no-install", "--agent"); + expect(r.code, r.out).toBe(0); + expect(r.out).toContain(`npx -y ${MCP_PKG} init`); + expect(r.out).toContain("127.0.0.1:47357"); + const main = readFileSync(join(dir, "src/main.tsx"), "utf8"); + const lines = main.trimEnd().split("\n"); + expect(lines[0]).toBe(`import genclass from '@genclass/runtime/auto' // genclass:init`); + expect(lines.at(-2)).toBe(`if (import.meta.env.DEV) import('@genclass/runtime/devtools').then((d) => d.mountDevtools(genclass)) // genclass:init`); + expect(lines.at(-1)).toBe(`if (import.meta.env.DEV) import('@genclass/runtime/agent').then((a) => a.connectAgent(genclass)) // genclass:init`); + expect(cli(dir, "remove", "--yes").code).toBe(0); + expect(readFileSync(join(dir, "src/main.tsx"), "utf8")).toBe(VITE_TS["src/main.tsx"]); + }); + + it("--agent --no-devtools: the runtime is still bound; only the agent line follows", () => { + const after = roundTrip(project(VITE_TS), "--agent", "--no-devtools"); + const lines = after["src/main.tsx"].trimEnd().split("\n"); + expect(lines[0]).toBe(`import genclass from '@genclass/runtime/auto' // genclass:init`); + expect(lines.at(-1)).toBe(`if (import.meta.env.DEV) import('@genclass/runtime/agent').then((a) => a.connectAgent(genclass)) // genclass:init`); + expect(after["src/main.tsx"]).not.toContain("devtools"); + }); + + it("Next.js 16: both calls in the one development block of instrumentation-client.ts", () => { + const dir = project({ + "package.json": pkg({ next: "16.0.0", react: "^19" }), + "tsconfig.json": "{}\n", + "node_modules/next/package.json": JSON.stringify({ name: "next", version: "16.0.1" }), + "src/app/layout.tsx": `export default function RootLayout({ children }: { children: React.ReactNode }) {\n return (\n \n {children}\n \n );\n}\n`, + }); + const f = roundTrip(dir, "--agent")["src/instrumentation-client.ts"]; + expect(f).toContain(`if (process.env.NODE_ENV === "development") {\n import("@genclass/runtime/devtools").then((d) => d.mountDevtools(genclass));\n import("@genclass/runtime/agent").then((a) => a.connectAgent(genclass));\n}`); + }); + + it("Nuxt 4 and Astro: the agent line in the plugin, and in the inline script", () => { + const n4 = project({ "package.json": pkg({ nuxt: "^4.0.0" }), "tsconfig.json": "{}\n", "app/app.vue": "\n" }); + const plugin = roundTrip(n4, "--agent")["app/plugins/genclass.client.ts"]; + expect(plugin).toContain(` if (import.meta.dev) import("@genclass/runtime/devtools").then((d) => d.mountDevtools(genclass));\n if (import.meta.dev) import("@genclass/runtime/agent").then((a) => a.connectAgent(genclass));\n});`); + const astro = project({ "package.json": pkg({ astro: "^5" }), "src/pages/index.astro": `xhi\n` }); + expect(roundTrip(astro, "--agent")["src/pages/index.astro"]).toContain( + ``, + ); + }); + + it("plain HTML: a module script after the tag, loading the agent entry next to the script URL", () => { + const dir = project({ + "index.html": `\n\n\n \n\n\n\n`, + "about.html": `About`, + }); + const after = roundTrip(dir, "--agent", "--cdn", "https://example.test/dist/genclass.global.min.js", "--no-sri"); + const agent = ``; + expect(after["index.html"]).toContain(`\n \n ${agent} \n `); + expect(after["about.html"]).toContain(`>${agent}`); + const dflt = roundTrip(project({ "index.html": `<html><head><title>x\n` }), "--agent")["index.html"]; + expect(dflt).toContain(`import("https://cdn.jsdelivr.net/npm/@genclass/runtime@${VERSION}/dist/agent.js")`); + // a --cdn copy under another file name: the CLI cannot know where its agent.js is, so no module script and a note + const odd = project({ "index.html": `x\n` }); + const r = cli(odd, "init", "--yes", "--no-install", "--agent", "--no-sri", "--cdn", "https://example.test/gc.js"); + expect(r.code, r.out).toBe(0); + expect(r.out).toContain("The agent link was not added: --cdn https://example.test/gc.js does not end in genclass.global.js"); + const html = readFileSync(join(odd, "index.html"), "utf8"); + expect(html).toContain(''); + expect(html).not.toContain("connectAgent"); + expect(cli(odd, "remove", "--yes").code).toBe(0); + // the READMEs' bare package URL: the agent entry is dist/agent.js next to it + const bare = roundTrip(project({ "index.html": `x\n` }), "--agent", "--no-sri", "--cdn", `https://cdn.jsdelivr.net/npm/@genclass/runtime@${VERSION}`)["index.html"]; + expect(bare).toContain(`import("https://cdn.jsdelivr.net/npm/@genclass/runtime@${VERSION}/dist/agent.js")`); + }); + + it("remove never swallows a user's line below an edited dev-only line (a block needs one of init's calls inside)", () => { + const dir = viteVue(); + const before = snapshot(dir); + expect(cli(dir, "init", "--yes", "--no-install", "--agent").code).toBe(0); + const f = join(dir, "src/main.js"); + const added = readFileSync(f, "utf8"); + const line = `if (import.meta.env.DEV) import("@genclass/runtime/agent").then((a) => a.connectAgent(genclass)); // genclass:init`; + expect(added).toContain(line); + // the developer passes options to the link and adds a function right after it: the marked line is no longer init's + const edited = added.replace(line, `const opts = { anyHost: true };\n${line.replace("a.connectAgent(genclass)", "a.connectAgent(genclass, opts)")}\nfunction reportRaces(races) {}`); + writeFileSync(f, edited); + const r = cli(dir, "remove", "--yes"); + expect(r.code).not.toBe(0); + expect(r.out).toContain("not a statement init writes"); + expect(readFileSync(f, "utf8")).toBe(edited); + expect(snapshot(dir)).not.toEqual(before); + }); + + it("remove takes out a Prettier-wrapped agent line whole, and refuses one that was edited", () => { + const dir = viteVue(); + const before = snapshot(dir); + expect(cli(dir, "init", "--yes", "--no-install", "--agent").code).toBe(0); + const f = join(dir, "src/main.js"); + const added = readFileSync(f, "utf8"); + const line = `if (import.meta.env.DEV) import("@genclass/runtime/agent").then((a) => a.connectAgent(genclass)); // genclass:init`; + expect(added).toContain(line); + writeFileSync(f, added.replace(line, `if (import.meta.env.DEV)\n import("@genclass/runtime/agent").then((a) =>\n a.connectAgent(genclass),\n ); // genclass:init`)); + expect(cli(dir, "remove", "--yes").code).toBe(0); + expect(snapshot(dir)).toEqual(before); + expect(cli(dir, "init", "--yes", "--no-install", "--agent").code).toBe(0); + writeFileSync(f, readFileSync(f, "utf8").replace("a.connectAgent(genclass)", "a.connectAgent(genclass, { anyHost: true })")); + const r = cli(dir, "remove", "--yes"); + expect(r.code).not.toBe(0); + expect(r.out).toContain("not a statement init writes"); + }); +}); diff --git a/telemetry-worker/src/pages.ts b/telemetry-worker/src/pages.ts index 51e09db8..68950633 100644 --- a/telemetry-worker/src/pages.ts +++ b/telemetry-worker/src/pages.ts @@ -62,7 +62,7 @@ export const LOGO = ''; /** The MCP server for coding agents, pinned as its own install blocks pin it (packages/mcp/src/clients.ts). */ -export const MCP_PKG = "@genclass/mcp@0.2.0"; +export const MCP_PKG = "@genclass/mcp@0.2.1"; /** The package names and URLs installPrompt names; passed in, so the page script runs the same function. */ export interface PromptNames { @@ -350,9 +350,9 @@ See priv // ------------------------------------------------------------------------------------- /start/open-source // GenClass's open-source parts with no account: the runtime in the app's pages, the agent link, the MCP server and the -// page check, all Apache-2.0, with no token and the runtime's anonymous diagnostics off, so nothing reaches -// genclass.dev. For teams that cannot sign up for or send data to a hosted dashboard (enterprises). The page sends -// nothing either: its choices rewrite the prompt in the browser, with the server's own openSourcePrompt. +// page check, all Apache-2.0, with no account: init creates the app's free dashboard link and keeps the runtime's +// anonymous diagnostics on, as every init does (`--no-telemetry` for neither; owner decision 2026-11-02). For teams +// that cannot sign up for a hosted dashboard. The page sends nothing either: its choices rewrite the prompt in the browser, with the server's own openSourcePrompt. /** What /start/open-source's choices add to openSourcePrompt; all off is observe, the overlay in development only. */ export interface OpenSourceChoices { @@ -369,10 +369,11 @@ export interface OpenSourceChoices { } /** - * The prompt /start/open-source copies: installPrompt's steps without a token, a dashboard or an agent link, with - * `telemetry: false` (the runtime sends no data anywhere; it still downloads public files from jsDelivr unless the app - * serves them), the MCP server on the developer's machine and the page check run locally. Pure and self-contained, - * like installPrompt: the page script runs this same function. + * The prompt /start/open-source copies: the two commands (`init --agent` for the app, `@genclass/mcp init` for the + * agent), with the app's free dashboard link and anonymous diagnostics on (never page text, never from local hosts; + * the browser downloads public files from jsDelivr unless the app serves them), no account, the MCP server on the + * developer's machine and the page check run locally; the choices are init flags. Pure and self-contained, like installPrompt: the page script runs this + * same function. */ export function openSourcePrompt(c: OpenSourceChoices = {}, n: PromptNames = PROMPT_NAMES): string { const guard = !!c.guard; @@ -380,69 +381,45 @@ export function openSourcePrompt(c: OpenSourceChoices = {}, n: PromptNames = PRO const logs = !!c.logs; const own = !!c.selfHost; const dir = "/genclass-model/"; - // GenClass.init has automatic state discovery off unless asked (autoState: true, with the discover import first) - const init = ["telemetry: false", "autoState: true"]; - if (guard) init.push('mode: "guard"', ...(eager ? ['aggressiveness: "eager"'] : []), "visual: { on: true, fix: true }"); - if (own) init.push(`model: { baseUrl: "${dir}", ortWasmPaths: "${dir}ort/" }`); - if (logs) init.push("sinks: [consoleJson()]"); - // the script tag carries all of it but the aggressiveness, which goes in GENCLASS_CONFIG (as in installPrompt) - const attrs = ['data-telemetry="off"']; - if (guard) attrs.push('data-mode="guard"', 'data-visual="fix"'); - if (own) attrs.push(`data-model="${dir}"`, `data-ort="${dir}ort/"`); - if (logs) attrs.push('data-sink="console-json"'); - attrs.push('data-devtools="local"'); - const flags = ["--no-telemetry", ...(guard ? ["--mode guard"] : []), ...(logs ? ["--sink console-json"] : []), ...(own ? [`--model-url ${dir}`] : [])]; - // init writes no visual or aggressiveness option: the prompt says where to add them + // every choice is an init flag, except the visual fixes and the aggressiveness, which init does not write + const flags = ["--agent", ...(guard ? ["--mode guard"] : []), ...(logs ? ["--sink console-json"] : []), ...(own ? [`--model-url ${dir}`] : []), "--yes"]; const initAdds = guard - ? `${eager ? 'aggressiveness: "eager" and ' : ""}visual: { on: true, fix: true } to the option file it writes (data-visual="fix" on the tag it writes${eager ? ", and the GENCLASS_CONFIG line above" : ""}; Astro gets a line instead: add visual=fix to its content${eager ? ', and the aggressiveness in a window.GENCLASS_CONFIG script before it' : ""})` + ? `add ${eager ? 'aggressiveness: "eager" and ' : ""}visual: { on: true, fix: true } to the option file it writes (data-visual="fix" on the tag it writes${eager ? ', and a line before it' : ""}; Astro gets a line instead: add visual=fix to its content${eager ? ", and the aggressiveness in a window.GENCLASS_CONFIG script before it" : ""})` : ""; - const local = '["localhost", "127.0.0.1"].includes(location.hostname)'; // A step is a one-element array, numbered at the end (choices add steps); other lines are strings. No named inner // function: Wrangler's bundler (keepNames) would wrap it in a __name() helper that the page script, which runs this // function's source, lacks. const out: (string | [string])[] = [ - "Add GenClass's open-source parts to this web app (Apache-2.0, https://github.com/genclass-dev/GenClass): the @genclass/runtime library in its pages, which reports the bugs that never throw (double submits, stale responses that overwrite newer data, write races, visual bugs), and the @genclass/mcp server on this machine, so you, the coding agent, can see what happens on the dev pages, replay it and prove fixes. No GenClass account and no token: nothing is sent to genclass.dev. Do every step yourself.", + "Add GenClass's open-source parts to this web app (Apache-2.0, https://github.com/genclass-dev/GenClass): the @genclass/runtime library in its pages, which reports the bugs that never throw (double submits, stale responses that overwrite newer data, write races, visual bugs), and the @genclass/mcp server on this machine, so you, the coding agent, can see what happens on the dev pages, replay it and prove fixes. No GenClass account and nothing to sign in to: init creates the app's free dashboard link. Two commands do it; run them yourself.", "", - [`Install the runtime with the project's package manager: npm install ${n.pkg} (or pnpm add / yarn add / bun add ${n.pkg}). A site with no build step (plain HTML pages, no bundler) installs nothing: it uses the script tags below.`], + ...(own + ? [ + [`Serve the model from the app itself, so its pages download no model from a CDN: npx ${n.pkg} fetch-model public/genclass-model (the folder the project serves as-is: public/ for Vite, Next.js and Astro, static/ for SvelteKit). It downloads the model and onnxruntime-web's files, checks the model files against the sizes and SHA-256 hashes its model card lists, and records onnxruntime-web's hashes in ort/ort.json; the next step's --model-url points at it. On a host with a 25 MiB per-file limit (Cloudflare), run fetch-model public/genclass-model --variant q8 --ort wasm instead (init --model-url adds device: "wasm" when it finds only the WASM build). With a bundler nothing else loads from a CDN. Without one, the runtime's script and what it loads on demand (its model worker, onnxruntime-web's JavaScript, sinks, visual checks, the overlay, the agent link) still come from jsDelivr unless you serve the package's dist/ folder from the app and point the script tag at it (--cdn ; data-base if they are in different folders).`] as [string], + ] + : []), [ - "Start it as early as possible, with GenClass's anonymous diagnostics off (telemetry: false), so it sends no data anywhere" + + `In the project's root run: npx ${n.pkg} init ${flags.join(" ")} ` + + "It finds the framework and package manager, installs the runtime, adds one marked import first in the browser entry (plain HTML pages, no bundler: the script tag, pinned with an integrity hash, in every page's ), the dev-only devtools overlay and the dev-only agent link (which records what happens on local pages for the GenClass MCP server, talks only to 127.0.0.1 and is never part of a production build; on plain HTML pages it stays in the page and runs only on localhost), and, once applied, creates the app's free dashboard link at genclass.dev (it sends the package name, nothing else) and writes the token into a marked option file next to the entry (data-token on the tag; Astro: a line). GenClass's anonymous diagnostics stay on: its decisions and counts, never text from the page, and never from localhost or private hosts" + (own ? "" : "; the browser still downloads its model and onnxruntime-web, public files, from cdn.jsdelivr.net (about 13 MB, 18 MB on WebGPU devices, then cached) unless the app serves them") + - ". With a bundler, in the browser entry (main.ts, the root layout or the root component), with the discover import first, before React, Redux or Zustand load:", + ". It shows the diff; --yes applies it. " + + (guard + ? `Mode guard: when GenClass is sure, it acts with minimal, reversible steps (it drops a stale response or fixes a CSS bug on the page) and never changes a response${eager ? '; aggressiveness "eager" lets it act on smaller signals' : ""}. Then ${initAdds}.` + : "The mode stays observe: GenClass reports and never changes what the app does.") + + ' React state, Redux stores (configureStore, or createStore with the Redux DevTools compose) and Zustand stores made with the devtools middleware are found automatically; Pinia, Svelte stores, signals and a plain page\'s DOM are watched only for state the app registers with GenClass.runtime.atom("name", initial) or GenClass.runtime.guard("name", { get, set }), written through the handle (one atom per response, such as a search\'s query and its results): do that only if I ask.', ], - ' import "@genclass/runtime/discover"; // first: lets GenClass find React, Redux and Zustand state', - ...(logs ? [' import { consoleJson } from "@genclass/runtime/sinks/console-json";'] : []), - ' import { GenClass } from "@genclass/runtime";', - ` const rt = GenClass.init({ ${init.join(", ")} });`, - " Without a bundler, in the of every HTML page, before the page's own scripts:", - ...(eager ? [' '] : []), - ` `, - " and in the page's scripts the handle (rt below) is GenClass.runtime.", - ` (Or npx ${n.pkg} init ${flags.join(" ")} --yes does steps 1 and 2 and shows the diff, with a bundler or plain HTML pages: it starts GenClass with its zero-code entry (the /auto import with an option file, or the script tag pinned with an integrity hash), which finds React, Redux and Zustand state by itself, and adds step 3's dev-only overlay; the handle is then GenClass.runtime${guard ? `; add ${initAdds}` : ""}${own ? "; run the fetch-model command below before it" : ""}.)`, [ - (guard - ? `Mode guard: when GenClass is sure, it acts with minimal, reversible steps (it drops a stale response or fixes a CSS bug on the page) and never changes a response${eager ? '; aggressiveness "eager" lets it act on smaller signals' : ""}.` - : "Keep the default mode, observe: GenClass reports and never changes what the app does.") + - ' In development builds also mount the devtools overlay, which shows what GenClass sees on the page: if (import.meta.env.DEV) import("@genclass/runtime/devtools").then((d) => d.mountDevtools(rt)); (Next.js: process.env.NODE_ENV === "development"; the script tag\'s data-devtools="local" does the same).', + `Run: npx -y ${n.mcp} init. It writes the GenClass MCP server into .mcp.json for Claude Code (npx -y ${n.mcp} config prints the block for Cursor, VS Code, Codex, Gemini CLI and others) and the genclass skill, the procedure you follow for timing bugs, to .claude/skills/genclass/SKILL.md; then reload your MCP servers. It runs on this machine, its bridge listens on 127.0.0.1 only, and it needs no account: leave GENCLASS_DASHBOARD and GENCLASS_REPORT unset (either one sends to a GenClass dashboard). The app-side lines it prints are already done by the init command above. Its tools: genclass_status, genclass_findings, genclass_explain, genclass_replay, genclass_explore, genclass_scan.`, ], - ['Connect the state that responses write (search results, carts, lists, forms), so GenClass sees each write with the response or click that caused it. React state, Redux stores (configureStore, or createStore with the Redux DevTools compose) and Zustand stores made with the devtools middleware are found automatically (the discover import with autoState: true above; the script tag and init\'s /auto import do it by default); otherwise create it with rt.atom("name", initial) or wrap the store you have with rt.guard("name", { get, set }), and write through the handle. Values one response writes together (a search\'s query and its results) go in one atom, written once per response, so GenClass can drop a stale response as one write: const search = rt.atom("search", { query: "", results: [] }); then search.set((s) => ({ ...s, query: data.q, results: data.results })) and render from search.subscribe.'], - ['Development builds only, add the agent link: import { connectAgent } from "@genclass/runtime/agent"; if (import.meta.env.DEV) connectAgent(rt); (Next.js: process.env.NODE_ENV === "development"). It records what happens on local pages for the GenClass MCP server, talks only to 127.0.0.1 and is never part of a production build.'], - ` Without a bundler, after the runtime's script tag: `, - [`Add the GenClass MCP server to yourself: npx -y ${n.mcp} init writes .mcp.json for Claude Code (npx -y ${n.mcp} config prints the block for Cursor, VS Code, Codex, Gemini CLI and others); then reload your MCP servers. It runs on this machine, its bridge listens on 127.0.0.1 only, and it needs no account: leave GENCLASS_DASHBOARD and GENCLASS_REPORT unset (either one sends to a GenClass dashboard). init also prints setup lines for the app with a bare GenClass.init(): keep the setup from steps 2 and 5 instead. Its tools: genclass_status, genclass_findings, genclass_explain, genclass_replay, genclass_explore, genclass_scan.`], ...(logs ? [ - ['Findings print as [GenClass] lines in the browser console, and the console-json sink also prints each one as one JSON line, for the log shipper the app already uses. If the team has its own endpoint for them, the webhook sink sends batched POSTs there instead: import { webhook } from "@genclass/runtime/sinks/webhook"; sinks: [webhook({ url: "" })], requests: { ignore: [""] } (so GenClass does not watch its own POSTs; data-sink="webhook:" on the script tag does both). Ask me for that URL rather than inventing one.'] as [string], - ] - : []), - ...(own - ? [ - [`Serve the model from the app itself, so its pages download no model from a CDN: npx ${n.pkg} fetch-model public/genclass-model (the folder the project serves as-is: public/ for Vite, Next.js and Astro, static/ for SvelteKit), before init if you use init. It downloads the model and onnxruntime-web's files, checks the model files against the sizes and SHA-256 hashes its model card lists, and records onnxruntime-web's hashes in ort/ort.json; the model option above points at it. On a host with a 25 MiB per-file limit (Cloudflare), run fetch-model public/genclass-model --variant q8 --ort wasm instead and add device: "wasm" to the model option (data-device="wasm" on the script tag; init --model-url adds it when it finds only the WASM build). With a bundler nothing else loads from a CDN. Without one, the runtime's script and what it loads on demand (its model worker, onnxruntime-web's JavaScript, sinks, visual checks, the overlay, the agent link) still come from jsDelivr unless you serve the package's dist/ folder from the app and point the script tag and the agent link's import at it (data-base if they are in different folders).`] as [string], + ['Findings print as [GenClass] lines in the browser console, and the console-json sink also prints each one as one JSON line, for the log shipper the app already uses. If the team has its own endpoint for them, use the webhook sink instead: --sink webhook: on the init command (data-sink="webhook:" on a script tag) sends batched POSTs there and keeps GenClass from watching its own POSTs. Ask me for that URL rather than inventing one.'] as [string], ] : []), [`Run the dev server and load a page to check that the app builds and runs without errors. Until the MCP server runs (your next conversation), the page logs a failed request to 127.0.0.1:47357: that is the agent link finding no server, and expected. In your next conversation, reload a dev page and genclass_status lists it. Then check a page for visual bugs with genclass_scan on its local URL, or from a terminal: npx ${n.pkg} scan http://localhost:5173/ --local (keep --local). It runs headless Chromium on this machine and needs Playwright: if the scan says it is missing, ask me before adding playwright as a dev dependency and downloading Chromium (about 600 MB): npm i -D playwright && npx playwright install chromium; or skip the scan and say so. Do not use hosted: true: it sends the page URL to GenClass's hosted page check, which is not open source.`], ...(c.deploy ? [["Deploy it, as chosen, with the command this project already uses (a deploy script in package.json, wrangler deploy for a Cloudflare Worker, vercel deploy --prod, and so on), then check that the deployed site serves the change."] as [string]] : []), - [`Tell me what you changed${c.deploy ? " and where it is deployed" : ""}, that the app sets no GenClass token and has telemetry off, what it downloads from outside this network, and that a new conversation with you has the GenClass tools.`], + [`Tell me what you changed${c.deploy ? " and where it is deployed" : ""}, the dashboard link init printed if it created one (it is saved in .genclass.local, which init adds to .gitignore; keep it private), what it downloads from outside this network, and that a new conversation with you has the GenClass tools.`], ]; let k = 0; return out.map((l) => (typeof l === "string" ? l : `${++k}. ${l[0]}`)).join("\n"); @@ -462,11 +439,6 @@ function choiceOpt(k: string, label: string, note: string, sub = false): string return ``; } -/** The commands' agent link, before its development check (which is the bundler's: init writes the same one). */ -const AGENT_LINK_HEAD = `// in the app's entry, after the lines init added -import { GenClass } from "@genclass/runtime"; -import { connectAgent } from "@genclass/runtime/agent";`; - /** The prompt block's styles on genclass.dev's palette (the dashboard's .copts and .cprompt, DASH_CSS, re-tokened). */ const OSS_CSS = ` .copts{display:grid;gap:6px;max-width:72ch} @@ -504,7 +476,8 @@ export function openSourcePage(nonce: string): string {

GenClass without an account

The open-source parts only, Apache-2.0: the runtime in your app's pages, and the MCP server and the - page check on your machine. No sign-in, no token, and nothing is sent to genclass.dev.

+ page check on your machine. No sign-in: init creates the app's free dashboard link, and anonymous diagnostics stay on + unless you turn them off.

@@ -517,28 +490,34 @@ export function openSourcePage(nonce: string): string {
-

Paste it into Claude Code, Cursor or Codex: it adds GenClass to your app and the MCP server to the agent, with nothing to sign up for.

+

Paste it into Claude Code, Cursor or Codex: two commands add GenClass to your app and the MCP server and the genclass skill to the agent, with nothing to sign up for.

What leaves your network

    -
  • Nothing goes to genclass.dev: there is no token, and the runtime's anonymous diagnostics are off (telemetry: false).
  • +
  • To genclass.dev: the app's package name, once, when init creates its free dashboard link (--no-token skips it); then, from public hosts only, the runtime's anonymous diagnostics: its decisions and counts, never text from the page (every field). init --no-telemetry --agent turns them off and creates no link, so nothing goes to genclass.dev at all.
  • Browsers download public files from jsDelivr (cdn.jsdelivr.net), once, then cached: the model and onnxruntime-web (about 13 MB on WASM, 18 MB on WebGPU) unless you serve them yourself, and on sites without a bundler the runtime's own files unless you serve its dist/ folder. No app data goes with those requests.
  • The MCP server runs on your machine and its bridge listens on 127.0.0.1 only; with GENCLASS_DASHBOARD and GENCLASS_REPORT unset it sends nothing off the machine, and it keeps what it records in .genclass/agent in the project, which git ignores. genclass_scan and scan --local check pages in headless Chromium on your machine. A page URL leaves it only with hosted: true (or scan without --local when Playwright or its Chromium is missing): it then goes to GenClass's hosted page check (genclass-scan.mehar-144.workers.dev), which is not open source.
  • On developer machines, npm install and npx fetch packages from the npm registry (or your mirror), and the page check's Chromium comes from Playwright's download servers; fetch-model (to serve the model yourself) downloads the model and onnxruntime-web from jsDelivr, or from a mirror you name with --from and --ort-from.
  • The runtime, the MCP server, the model's training code and the collector behind genclass.dev are on GitHub under the Apache-2.0 license; the model's weights are on npm as @genclass/runtime-model (Apache-2.0).
+
+

What you will see

+
    +
  • In the browser console, once the model has loaded: [GenClass] Model ready (…). Mode: observe., then one [GenClass] … line per detection, with its evidence.
  • +
  • On localhost, the devtools overlay (bottom-right, Alt+Shift+G): what GenClass sees on the page, its checks and detections.
  • +
  • In your agent, once the MCP server runs: genclass_status lists the dev page (reload it after starting the server), genclass_findings what GenClass saw, genclass_explore the race, genclass_replay the proof.
  • +
+

Or run the commands yourself

- ${cmd("Add the runtime to your app", `npx ${RUNTIME_PKG} init --no-telemetry`)} - ${cmd("Connect the dev pages to the MCP server: Vite", `${AGENT_LINK_HEAD}\nif (import.meta.env.DEV && GenClass.runtime) connectAgent(GenClass.runtime);`)} - ${cmd("The same for Next.js and webpack", `${AGENT_LINK_HEAD.replace("the app's entry", "the app's entry (Next.js: instrumentation-client.ts)")}\nif (process.env.NODE_ENV === "development" && GenClass.runtime) connectAgent(GenClass.runtime);`)} - ${cmd("Add the MCP server for Claude Code", `npx -y ${MCP_PKG} init`)} + ${cmd("Add the runtime to your app, with the dev-only agent link", `npx ${RUNTIME_PKG} init --agent`)} + ${cmd("Add the MCP server and the genclass skill for Claude Code", `npx -y ${MCP_PKG} init`)} ${cmd("Check a page for visual bugs", `npx ${RUNTIME_PKG} scan http://localhost:5173/ --local`)} -

init shows the diff and asks before it writes; add --mode guard for guard. Other agents: npx -y ${MCP_PKG} config <client> prints the block for Cursor, VS Code, Codex, Gemini CLI and others; keep GENCLASS_DASHBOARD and GENCLASS_REPORT out of it. The scan needs Playwright (npm i -D playwright && npx playwright install chromium).

+

init shows the diff and asks before it writes; add --mode guard for guard, --no-telemetry to send nothing to genclass.dev. Until the MCP server runs, a dev page logs one failed request to 127.0.0.1:47357 (the agent link finding no server). Other agents: npx -y ${MCP_PKG} config <client> prints the block for Cursor, VS Code, Codex, Gemini CLI and others; keep GENCLASS_DASHBOARD and GENCLASS_REPORT out of it. The scan needs Playwright (npm i -D playwright && npx playwright install chromium).