Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Added
- `npm run eval:mcp`: the same question about a local page with a known answer, asked to an agent with the webperf MCP server, with Chrome DevTools MCP and the webperf skills, and with Chrome DevTools MCP alone, graded on the diagnosis and measured in tokens, turns and time. It runs by hand, not in CI.
- `npm run smoke:cli-package`: packs the CLI as the publish workflow does, installs it in an empty folder and checks its MCP server without Chromium and after `npx playwright install chromium`. It runs by hand before a release of the CLI.
- LCP-Subparts splits the Resource Load Time into the wait for the server and the download of the resource, in `details.subParts.resourceLoadTime.waiting` and `.download`, from its Resource Timing entry. When the wait is the larger part of the slowest phase, the console recommends the server, CDN and cache instead of compressing the image. The split is missing when another origin hides its timing (no `Timing-Allow-Origin`).

### Changed
- CI skips the build and the end-to-end tests on its own when a pull request only changes documentation, instead of waiting for the `skip-e2e` label. Opening a pull request with the label fired two runs and cancelled one, which showed as a failed check.
- Examples, CLI commands, the `OWN_DOMAINS` hint of the snippets and the test data use the domains reserved for documentation (`example.com`, `example.net`, `example.org`) instead of real sites. `scripts/example-domains.test.js`, in `npm run test:site`, fails when a real site comes back as an example.
- `getINPDetails()` of INP returns a result object, `{ script, status, count, items }`, like the other functions the snippets expose, instead of an array. `items` holds the 15 slowest interactions as plain data, with the target as a CSS selector instead of the DOM element. Code or agents that read the array need to read `items`.

### Fixed
- The generated skills run in the conversation of the agent, not in a forked context (`context: fork`): a forked skill runs in a subagent that does not get the conversation, so it did not know the URL or the open page and answered that it had no page to measure.
- INP, Interactions and Input-Latency-Breakdown measure the phases over the whole interaction, not over one of its events. A slow click handler was reported as `pointerup`, with 0 ms of processing and the presentation as the bottleneck; it is reported as `click`, with the processing as the bottleneck. An interaction whose entries arrive in separate observer callbacks counts once.
- Interactions and Input-Latency-Breakdown return `unsupported` in browsers without Event Timing.
- Script-Loading lists a `nomodule` script with the strategy `nomodule`, never as blocking: browsers with modules never fetch it.
Expand Down
15 changes: 14 additions & 1 deletion cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,30 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The CL

## [Unreleased]

---

## [1.1.0] — 2026-10-21

### Added
- `webperf-snippets mcp` starts an MCP server over stdio, for AI agents, with a `list_snippets` tool that lists the snippets with their category, title, aliases and whether they track interactions. It answers clients of the 2026-07-28 revision of the protocol and of the earlier ones. The `@modelcontextprotocol/server` SDK is a new dependency, loaded only by this command.
- The `run_snippet` tool of the MCP server opens a URL, runs one snippet and returns its result object, with progress notifications. A page that does not load or an unknown snippet comes back as a tool error the agent can act on; a snippet that reports an error stays a result.
- The MCP server keeps pages open between calls for the tracking snippets: `open_page` installs them and returns a session id, `interact` clicks, types, hovers, scrolls or waits, `read_results` returns what they recorded and `close_page` closes the page. At most three pages are open, an unused page closes after 10 minutes, and a cancelled call or a client that disconnects closes its pages and Chromium.
- The `run_workflow` tool of the MCP server runs the workflows of the CLI with the follow-ups of their decision tree, and `get_crux` returns CrUX field data with the key read from `CRUX_API_KEY` in the environment of the server.
- The MCP server offers the result contract of the snippets (`webperf://schema`, and one section per snippet at `webperf://schema/{snippet}`) and the workflows of each category (`webperf://workflows/{category}`) as resources, and the prompts `audit_lcp`, `debug_inp` and `audit_page`, which chain the tools with the schema sections the answer needs.
- The MCP server is listed in the MCP Registry as `io.github.nucliweb/webperf-snippets` (`server.json`, and `mcpName` in `package.json`). The package is published with npm provenance.

### Changed
- With `--crux-key`, the CrUX object of the JSON report has `failed: true` when the API answers with an error or does not answer, next to `unavailable`. A page with no field data keeps only `unavailable`.
- The examples of `--help` and of the README run the CLI on `https://example.com`, a domain reserved for documentation, instead of a real site.
- The snippets the CLI runs include changes since 1.0.0 that alter their results:
- `LCP-Subparts` splits the Resource Load Time into `waiting` (until the first byte of the response) and `download`, in `details.subParts.resourceLoadTime`, when Resource Timing exposes them. The human report shows the split under the row.
- `INP`, `Interactions` and `Input-Latency-Breakdown` measure the phases over the whole interaction, not over one of its events: a slow click handler comes out as `click` with the processing as the bottleneck, not as `pointerup` with 0 ms of processing. `Interactions` and `Input-Latency-Breakdown` return `unsupported` in browsers without Event Timing.
- `Script-Loading` lists a `nomodule` script with the strategy `nomodule`, never as blocking.
- `Inline-Script-Info-and-Size` tells framework data payloads from scripts, with `isDataPayload` and `details.dataPayloadCount`, and counts analytics only from a call or definition.
- `LCP-Image-Entropy` divides by the displayed area of the image, capped at its natural area, as Chrome does, with `displayedWidth` and `displayedHeight`.

### Fixed
- Without Chromium, which npx does not download, `run_snippet`, `run_workflow`, `open_page` and the CLI say how to install it: `npx playwright install chromium`. The CLI prints it without a stack and exits with `1`. After the install, `open_page` works without restarting the MCP server.
- After an interaction script with a click or a key press, the tracking snippets (INP, Interactions, Input-Latency-Breakdown) report the interactions on a loaded machine too. The browser can deliver their timing later than the frames the runner waited for, and the result was "No interactions recorded yet". The runner reads a snippet that has no data yet again, every 100 ms, for up to 2 seconds.

---
Expand Down Expand Up @@ -128,7 +140,8 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The CL

---

[Unreleased]: https://github.com/nucliweb/webperf-snippets/compare/cli-v1.0.0...HEAD
[Unreleased]: https://github.com/nucliweb/webperf-snippets/compare/cli-v1.1.0...HEAD
[1.1.0]: https://github.com/nucliweb/webperf-snippets/compare/cli-v1.0.0...cli-v1.1.0
[1.0.0]: https://github.com/nucliweb/webperf-snippets/compare/cli-v0.5.0...cli-v1.0.0
[0.5.0]: https://github.com/nucliweb/webperf-snippets/compare/cli-v0.4.1...cli-v0.5.0
[0.4.1]: https://github.com/nucliweb/webperf-snippets/compare/cli-v0.4.0...cli-v0.4.1
Expand Down
2 changes: 1 addition & 1 deletion cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Without `--report-to` the CLI makes no external calls. With it, the results are
"timestamp": "2026-05-06T10:00:00.000Z",
"navMs": 1240,
"results": [],
"meta": { "viewport": "mobile", "waitMs": 3000, "cli_version": "1.0.0" }
"meta": { "viewport": "mobile", "waitMs": 3000, "cli_version": "1.1.0" }
}
```

Expand Down
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "webperf-snippets",
"version": "1.0.0",
"version": "1.1.0",
"mcpName": "io.github.nucliweb/webperf-snippets",
"description": "Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.",
"type": "module",
Expand Down
4 changes: 2 additions & 2 deletions cli/server.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
"source": "github",
"subfolder": "cli"
},
"version": "1.0.0",
"version": "1.1.0",
"packages": [
{
"registryType": "npm",
"registryBaseUrl": "https://registry.npmjs.org",
"identifier": "webperf-snippets",
"version": "1.0.0",
"version": "1.1.0",
"transport": {
"type": "stdio"
},
Expand Down
2 changes: 1 addition & 1 deletion content/CLI.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ Without `--report-to` the CLI makes no external calls. With it, the results are
"timestamp": "2026-05-06T10:00:00.000Z",
"navMs": 1240,
"results": [],
"meta": { "viewport": "mobile", "waitMs": 3000, "cli_version": "1.0.0" }
"meta": { "viewport": "mobile", "waitMs": 3000, "cli_version": "1.1.0" }
}
```

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading