ohmyperf
by hoainho
README.md
# OhMyPerf
> **The first perf tool an LLM agent can actually fix your site with β statistical proof, not vibes.**
π **Try the viewer live**: [hoainho.github.io/ohmyperf/viewer/](https://hoainho.github.io/ohmyperf/viewer/) β drag any `report.json` onto the page and inspect every metric, every long-task, every render-blocking opportunity in your browser. No install, no signup.
[](https://www.npmjs.com/package/@ohmyperf/cli)
[](https://glama.ai/mcp/servers/hoainho/ohmyperf)
[](https://modelcontextprotocol.io)
[](https://www.chromium.org/)
[](./LICENSE)
OhMyPerf measures Core Web Vitals on a **real machine** with a **real Chromium**, then closes the loop: an AI agent can call **`measure β propose_patch β verify_fix`** in one conversation turn β and prove the fix improved your LCP/INP/CLS with a **Mann-Whitney U test at Ξ±=0.05**, not "looks better to me."
```
ββββββββββββ βββββββββββββββββ ββββββββββββββββ
β measure β β β propose_patch β β β verify_fix β
β real CWV β β ranked, ROI β β p-value per β
β + trust β β first-party β β metric β
ββββββββββββ βββββββββββββββββ ββββββββββββββββ
β β β
trustScore fixPlan verdict:
servability (18 patches improvement |
originClass for tradeit.gg) neutral |
regression
```
## 30-second demo
Real CLI output, no editing:
```bash
$ npx -y @ohmyperf/cli@latest run https://example.com --runs 2 --format json
[ohmyperf] INFO OhMyPerf v1.0.0 report
[ohmyperf] INFO url: https://example.com
[ohmyperf] INFO browser: chromium 148.0.7778.0 (bundled)
[ohmyperf] INFO mode: real; runs=2; duration=2430ms
[ohmyperf] INFO aggregated:
[ohmyperf] INFO lcp median= 256.0 cov=25.0% n=2
[ohmyperf] INFO cls median= 0.000 cov= 0.0% n=2
[ohmyperf] INFO fcp median= 256.0 cov=25.0% n=2
[ohmyperf] INFO ttfb median= 224.5 cov=25.5% n=2
[ohmyperf] INFO tbt median= 0.0 cov= 0.0% n=2
[ohmyperf] INFO runtime.taskDuration median= 25.2 cov=20.2% n=2
[ohmyperf] INFO wrote /path/to/ohmyperf-out/report.json
```
The full [`report.json`](packages/core/src/types.ts) is what LLM agents see β including:
- `Report.trustScore` β overall + per-metric `{level, sampleConfidence, effectConfidence, recommendedAction}`
- `Report.fixPlan` β ranked, deduped, ROI-scored patches with `applicability: first-party | third-party-cannot-apply`
- `Report.meta.servability` β `real-page | bot-challenge-suspected | error-page | timeout-partial | unknown`
- `Report.perfSummary` β the full perf picture in 6 groups: timing (Full-Load Time, not just LCP), network (bytes by type, cache, 1st/3rd-party split, render-blocking, failed requests), javascript (transfer, parse/compile + execution, main-thread blocking), main-thread (TBT, long tasks, layout), errors (JS errors + console warnings/errors), stability (CLS, third-party, trust, servability)
- Every `Resource` tagged with `originClass: same-origin | same-site | same-org | cross-site`
CoV 25% on 2 runs (above 20% noise floor) β `trustScore: low` β agent's `recommendedAction: "rerun with --runs 10 or --mode ci-stable before drawing budget conclusions"`. Honest about its own variance, not vibes.
## Why this exists
| | Lighthouse / PSI | OhMyPerf |
|---|---|---|
| **Runs on** | Synthetic CPU in a Google datacenter | Your actual hardware |
| **Cross-origin iframes** | Network-only (opaque inside) | Per-frame CDPSession (~99% coverage) |
| **Agent-callable** | None | MCP server, 17 tools |
| **Statistical proof of fix** | Threshold gates (flake-prone) | Mann-Whitney U, Ξ±=0.05, per-metric noise floors |
| **First-party vs CDN** | Manual eyeballing | `originClass` + `same-org` tier for org-owned CDNs |
| **Bot challenge detection** | Treats Cloudflare interstitials as real pages | `servability: bot-challenge-suspected` |
| **Honest about variance** | One number, take it or leave it | `trustScore` + per-metric CoV + `recommendedAction` |
## Install
```bash
# CLI
npm install -g @ohmyperf/cli
ohmyperf run https://your-site.com
# MCP server β for Claude (OpenCode/Cursor/Cline) to call tools directly
npm install -g @ohmyperf/mcp-server
# Zero-install one-off
npx -y @ohmyperf/cli@latest run https://your-site.com
```
Requires Node β₯ 22. Playwright Chromium auto-downloads on first run (~150 MB).
## Use it from an AI agent
Add to your MCP client config (Claude Desktop example):
```json
{
"mcpServers": {
"ohmyperf": {
"command": "npx",
"args": ["-y", "@ohmyperf/mcp-server@latest"]
}
}
}
```
Then your LLM has 17 tools available: `measure`, `propose_patch`, `verify_fix`, `get_fix_plan`, `get_trust_score`, `get_servability`, `diff`, `list_runs`, and more. Tested with Claude, OpenCode, Cursor, Cline.
## Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Engine: @ohmyperf/core (frozen 1.0.0 public API) β
β Β· Playwright + raw CDP (Target.setAutoAttach for cross-origin) β
β Β· Plugin runtime Β· Calibration Β· Outlier rejection Β· Diff β
β Β· LLM-first signals: trustScore Β· fixPlan Β· servability β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββΊ CLI npx -y @ohmyperf/cli run <url>
ββββΊ npm SDK import { runEngine } from "@ohmyperf/core"
ββββΊ MCP server 17 tools + 8 prompts (v0.3.0)
ββββΊ Chrome extension click toolbar icon β measure current tab
ββββΊ VSCode extension Cmd+Shift+P β OhMyPerf: Measure URL
ββββΊ Website hoainho.github.io/ohmyperf β drop report.json on /viewer
ββββΊ Share-server Cloudflare Workers or Node
ββββΊ ESLint plugin 7 CWV-linked rules at editor-save time
ββββΊ Fixers SDK archetype registry + proposePatches()
```
**Status**: v0.3.0 current release. Ships the closed agent fix loop (`propose_patch` β `verify_fix`), comprehensive `perfSummary` with console/error capture, trust-gated budget enforcement, and 17 tools + 8 prompts.
## Why OhMyPerf
| Concern | Lighthouse / PageSpeed | OhMyPerf |
|---|---|---|
| **Where measurement runs** | Synthetic emulated CPU in a datacenter | The user's actual machine |
| **CWV numbers** | Inflated by synthetic throttle | Match what users actually experience |
| **Cross-origin iframes** | Network-only β opaque inside | Per-frame `CDPSession` via `Target.setAutoAttach({flatten:true})` |
| **CI reproducibility** | Lighthouse-CI exists but synthetic | Two modes: `real` (honest variance) + `ci-stable` (CPU calibration + Fast 4G throttle) |
| **Accuracy** | Authoritative, internal | LCP/FCP/TTFB Β±10% vs Lighthouse 13.x ([validated](docs/accuracy.md)); INP/CLS via official `web-vitals/attribution` |
| **Diagnostics** | Audit list with savings estimates | LCP/INP sub-parts bar, CLS culprit + rect, long-task β JS URL, render-blocking with wastedMs, third-party impact ([details](docs/diagnostics.md)) |
| **Regression detection** | Threshold gates (flake-prone) | Mann-Whitney U significance test with per-metric noise floors |
| **Plugin model** | Audit-API only, internal | Every metric, audit, reporter is a plugin |
| **Sharing** | PSI URL (public, ephemeral) | Hosted shareable links + static viewer + self-host backend |
| **AI agent access** | None | First-class MCP server (Claude / OpenCode / Cursor / Cline) |
## Surfaces
| # | Surface | Package | Quickstart |
|---|---|---|---|
| 1 | **CLI** | [`@ohmyperf/cli`](apps/cli/) | `ohmyperf run https://example.com` |
| 2 | **npm SDK** | [`@ohmyperf/core`](packages/core/) | `import { runEngine, measure } from "@ohmyperf/core"` |
| 3 | **Chrome extension** | [`apps/extension-chrome/`](apps/extension-chrome/) | Load unpacked β click toolbar icon |
| 4 | **Website (SPA)** | [`apps/website/`](apps/website/) Β· spec [`measurement-spa`](openspec/specs/measurement-spa/spec.md) | `pnpm --filter @ohmyperf/website dev` β measure at `/measure`, view at `/viewer`, history at `/report`. Static export to CF Pages. |
| 5 | **VSCode extension** | [`apps/ide-vscode/`](apps/ide-vscode/) | `Cmd+Shift+P` β `OhMyPerf: Measure URL` |
| 6 | **MCP server** | [`apps/mcp-server/`](apps/mcp-server/) | 17 tools + 8 prompts incl. `measure`, `propose_patch`, `verify_fix`, `get_fix_plan`, `get_trust_score`, `get_servability` |
| 7 | **Share-server** | [`packages/share-server/`](packages/share-server/) | Cloudflare Workers or `node dist/node.js` |
| 8 | **ESLint plugin** | [`@ohmyperf/eslint-plugin`](packages/eslint-plugin/) | `npm i -D @ohmyperf/eslint-plugin` + `extends: ['plugin:ohmyperf/recommended']` |
| 9 | **Fixer SDK** | [`@ohmyperf/fixers`](packages/fixers/) | `import { proposePatches } from "@ohmyperf/fixers"` |
## CLI quickstart
```bash
# Install
npm install -g @ohmyperf/cli
ohmyperf install-browser
# Measure
ohmyperf run https://example.com --runs 5 --format json,html
# CI-gating mode (calibrated CPU + Fast 4G)
ohmyperf run https://example.com --mode ci-stable --runs 5
# Compare two reports with Mann-Whitney significance (exit 1 on regression)
ohmyperf diff baseline.json candidate.json
# Share a report to a hosted endpoint
export OHMYPERF_SHARE_ENDPOINT=https://ohmyperf.dev
ohmyperf share ./ohmyperf-out/report.json
# Diagnostics
ohmyperf doctor
ohmyperf list-plugins --json
```
Subcommands: `run`, `diff`, `share`, `doctor`, `list-plugins`, `install-browser`.
Exit codes 0β12 documented per the [`cli-surface`](openspec/changes/add-ohmyperf-mvp/specs/cli-surface/spec.md) capability spec.
## Example output
```
[ohmyperf] INFO OhMyPerf v1.0.0 report
[ohmyperf] INFO url: https://example.com
[ohmyperf] INFO browser: chromium 147.0.7727.0 (bundled)
[ohmyperf] INFO mode: real; runs=5; duration=4823ms
[ohmyperf] INFO aggregated:
[ohmyperf] INFO lcp median= 44.0 cov=4.3% n=5
[ohmyperf] INFO fcp median= 44.0 cov=4.3% n=5
[ohmyperf] INFO ttfb median= 6.5 cov=12.3% n=5
[ohmyperf] INFO cls median= 0.000 cov=0.0% n=5
[ohmyperf] INFO tbt median= 0.0 cov=0.0% n=5
[ohmyperf] INFO audits: 1
[ohmyperf] INFO [PASS] a11y.axe-violations
[ohmyperf] INFO wrote ./ohmyperf-out/report.json (9 KB)
[ohmyperf] INFO wrote ./ohmyperf-out/report.html (28 KB)
```
## npm SDK quickstart
```ts
import { runEngine, createSilentLogger } from "@ohmyperf/core";
import { createPlaywrightAdapter } from "@ohmyperf/driver-playwright";
import { cwvPlugin, axePlugin } from "@ohmyperf/plugins-builtin";
import { writeJsonReport } from "@ohmyperf/reporter-json";
const { driver, adapter } = createPlaywrightAdapter({
url: "https://example.com",
kind: "chromium",
});
const report = await runEngine({
opts: {
url: "https://example.com",
runs: 5,
mode: "real",
plugins: [cwvPlugin(), axePlugin({ tags: ["wcag2aa"] })],
},
driver,
adapter,
logger: createSilentLogger(),
});
console.log(report.aggregated.lcp);
// { median: 44, p75: 45, p95: 47, mean: 44.5, stdev: 1.2, cov: 0.027,
// runs: 5, droppedOutliers: 0 }
await writeJsonReport(report, "./out");
```
The public API (`@ohmyperf/core`) is frozen at `1.0.0-stable` and enforced by `api-extractor` in CI. See [`packages/core/etc/core.api.md`](packages/core/etc/core.api.md) for the 45-export contract.
## Chrome extension
```bash
cd apps/extension-chrome
pnpm build
# Chrome β chrome://extensions β Developer mode β Load unpacked
# Point at apps/extension-chrome/extension-dist/
```
Click the toolbar icon on any tab. A "measuringβ¦" badge appears, then opens a viewer tab with the full HTML report when done. Uses `chrome.debugger` directly β no companion app, no localhost relay.
Chrome Web Store submission is documented as deferred (requires publisher account + privacy policy URL + review cycle).
## VSCode extension
```bash
cd apps/ide-vscode
pnpm build
# Code β Extensions β β― β Install from VSIX
# Or develop: F5 in this folder launches an Extension Development Host.
```
Commands:
- `OhMyPerf: Measure URL` β prompts for URL, runs the CLI, opens result in a webview.
- `OhMyPerf: Open Report Fileβ¦` β file picker for replaying saved reports.
Settings: `ohmyperf.cliPath`, `ohmyperf.defaultUrl`, `ohmyperf.defaultRuns`, `ohmyperf.defaultMode`.
VSCode Marketplace submission is documented as deferred.
## MCP server (for AI agents)
OhMyPerf ships an MCP (Model Context Protocol) server so AI agents like **Claude Desktop**, **OpenCode**, **Cursor**, **Cline**, and **Continue** can call `measure` and `diff` as first-class tools.
### Register with OpenCode
`~/.config/opencode/opencode.json`:
```json
{
"mcp": {
"ohmyperf": {
"type": "local",
"command": ["npx", "ohmyperf-mcp"]
}
}
}
```
### Register with Claude Desktop
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
```json
{
"mcpServers": {
"ohmyperf": {
"command": "npx",
"args": ["ohmyperf-mcp"]
}
}
}
```
### Install from Glama (MCP directory)
The OhMyPerf MCP server is listed in the [Glama MCP directory](https://glama.ai/mcp/servers/hoainho/ohmyperf) β one-click install paths for every Glama-supported client, no `npx` command required.
```bash
# Glama CLI (one-off)
npx -y @glama/mcp-server@latest install hoainho/ohmyperf
# Or just point your client at the stdio command:
command: npx
args: [-y, @ohmyperf/mcp-server]
```
The `glama.json` at the repo root pins the install command + maintainer metadata so the Glama listing stays in sync with this README. Claim your own copy at <https://glama.ai/mcp/servers/hoainho/ohmyperf/score> to edit the description, configure Docker build instructions, and receive review notifications.
### Tools exposed
The current release exposes all 17 tools and 8 prompts.
| Tool | Input | Output |
|---|---|---|
| `measure` | `{ url, runs?, mode?, plugins?, browserPath?, collectTrace? }` | Human summary + `Saved to: <path>` + `aggregated` JSON; full report saved + exposed as resource |
| `diff` | `{ baseline, candidate, failOnRegression? }` | Mann-Whitney significance table + `{ hasRegressions, metrics }` |
| `analyze_report` | `{ reportPath \| uri, insightName, limit? }` | Slice for one insight (lcp-breakdown / render-blocking / long-tasks / third-parties / opportunities / audits / resources / frames / full-load-breakdown / hotspots / remediation / perf-summary / network / javascript / errors) |
| `generate_markdown_summary` | `{ reportPath \| uri, title? }` | PR-comment-ready Markdown summary with π’/π‘/π΄ verdict block |
| `generate_html_report` | `{ reportPath \| uri, outputDir?, theme?, style? }` | Single-file HTML viewer written to disk |
| `generate_deck` | `{ reportPath \| uri, outputDir?, style?, title? }` | Multi-slide HTML presentation (βP β PDF for stakeholder distribution) |
| `find_regression_cause` | `{ baseline, candidate }` | Ranked hypotheses (new render-blocking, grown assets, new long tasks, new third-parties) with evidence |
| `enforce_budget` | `{ url, budget, mode?, runs? }` | CI-style pass/fail per metric; trust-gated (exit codes 0 / 12 / 13, where 13 = gated by low trust) |
| `track_url` | `{ url, runs?, mode?, ... }` | Measure + append to time-series + return improving/stable/regressing trend |
| `list_runs` / `list_styles` / `diff_resources` | various | Resource browsing + brand catalog + URI-based diff |
| `propose_patch` | `{ reportPath \| uri, opportunityId?, url?, maxPatches? }` | Structured `{ archetype, url, search, replace, rationale, expectedImpactMs, confidence }[]` patches an agent can apply |
| `verify_fix` | `{ baselineReportPath \| baselineUri, candidateUrl, runs?, mode? }` | Re-measures candidate + Mann-Whitney U diff vs baseline; verdict `β
no regression` / `β REGRESSION DETECTED` |
| `get_fix_plan` | `{ reportPath \| uri, limit?, applicabilityFilter? }` | Precomputed ranked, ROI-scored `fixPlan` slice only β saves the agent parsing the full 50KB+ report |
| `get_trust_score` | `{ reportPath \| uri }` | `trustScore.overall` + per-metric verdicts + `recommendedAction` so agents skip noisy measurements before acting |
| `get_servability` | `{ reportPath \| uri }` | `meta.servability` classification β `real-page` / `bot-challenge-suspected` / `error-page` / `timeout-partial` / `unknown` β so agents don't gate CI on a Cloudflare interstitial |
Saved reports surface as resources at `ohmyperf://reports/<timestamp>-<id>.json` so the agent can read them back later without re-measuring.
### Killer flow: closed agent fix loop
```
1. measure(url) β report.json + opportunities
2. propose_patch(reportPath) β { archetype: "render-blocking-script-add-defer",
search: '<script src="vendor.js"',
replace: '<script src="vendor.js" defer',
expectedImpactMs: 320,
confidence: "high" }
3. (agent applies patch + deploys to preview)
4. verify_fix(baseline, candidateUrl) β β
no regression / β REGRESSION
```
End-to-end loop time: ~5.5s against a real public URL ([commit `a41301f`](https://github.com/hoainho/ohmyperf/commit/a41301f) verified composition). Patches archetypes covering ~80% of typical opportunities (render-blocking scripts/stylesheets, LCP image fetchpriority + preload).
## Website
Live at **[hoainho.github.io/ohmyperf](https://hoainho.github.io/ohmyperf/)** (zero-credential GitHub Pages mirror, deployed via `.github/workflows/deploy-pages.yml`). Cloudflare Pages deploy at `ohmyperf.dev` is pending domain registration ([#9](https://github.com/hoainho/ohmyperf/issues/9)).
```bash
cd apps/website
pnpm build # Next.js static export to out/
OHMYPERF_BASE_PATH=/ohmyperf pnpm build # for GitHub Pages subpath
```
Routes:
- `/` β landing page (light/dark theme, no external network requests)
- `/viewer/` β drag-drop `report.json` to render in browser (no upload, no analytics, no signup)
- `/measure/` β in-browser measurement SPA (CDP via the Chrome extension when installed)
- `/report/` β local measurement history
- `/r/:id` β served by the share-server when deployed alongside
## Share-server (hosted shareable links)
Two deployment targets from the same Hono codebase:
### Cloudflare Workers + R2 + D1 (production)
```bash
cd packages/share-server
# wrangler.toml + D1 schema (D1_SCHEMA export)
wrangler d1 execute ohmyperf-db --file=schema.sql
wrangler deploy
```
### Node + filesystem (self-host)
```bash
cd packages/share-server
pnpm build
PORT=4170 OHMYPERF_SHARE_DATA_DIR=./data node dist/node.js
# listening on http://127.0.0.1:4170
```
API:
```
POST /api/share { report, password?, expiresInMs?, private? } β { id, url, expiresAt }
GET /api/r/:id β raw report JSON (with optional password gate)
GET /r/:id β rendered HTML (uses @ohmyperf/viewer)
DELETE /api/r/:id β 204
```
Per-IP rate limit (10/hour default), 10 MB body cap, mandatory security headers (`X-Content-Type-Options`, `Referrer-Policy`, `X-Frame-Options`), env-secret scrubber in the upload client.
GDPR / Privacy Policy / DPA / DSAR endpoint defer to legal review.
## CI integration
Drop-in [`templates/ci/github-actions.yml`](templates/ci/github-actions.yml):
```yaml
- run: npx ohmyperf run "$OHMYPERF_URL" --mode ci-stable --runs 5 \
--format json,html,markdown --output ./perf
- uses: actions/upload-artifact@v4
with: { name: ohmyperf-reports, path: perf/ }
- if: github.event_name == 'pull_request'
run: ohmyperf diff .ohmyperf-baseline/report.json perf/report.json
```
Auto-posts the Markdown summary as a PR comment via `actions/github-script@v7`. Mann-Whitney significance gates the merge.
## Architecture
Monorepo: pnpm workspaces + Turborepo.
```
ohmyperf/
βββ packages/
β βββ core/ # Engine, plugin runtime, calibration, diff
β βββ driver-playwright/ # Playwright + raw CDP (newCDPSession)
β βββ driver-extension/ # chrome.debugger driver
β βββ plugins-builtin/ # cwv, axe, custom-metric-example
β βββ reporter-{json,html,markdown}/
β βββ viewer/ # Pure-TS HTML report renderer
β βββ share-client/ # Upload + redaction pipeline
β βββ share-server/ # Hono backend (Workers + Node)
β βββ tests-oopif-corpus/ # Synthetic cross-origin iframe fixtures
βββ apps/
β βββ cli/ # ohmyperf binary (citty)
β βββ website/ # Static landing + drag-drop viewer
β βββ extension-chrome/ # MV3 + chrome.debugger
β βββ ide-vscode/ # Command palette + webview
β βββ mcp-server/ # @modelcontextprotocol/sdk stdio server
βββ openspec/ # OpenSpec proposal + ADRs
```
ADRs:
- [ADR-001](openspec/adrs/ADR-001-driver-abstraction.md) Driver abstraction; Playwright primary; raw CDP via `newCDPSession()`
- [ADR-002](openspec/adrs/ADR-002-oopif-deep-inspection.md) OOPIF via `Target.setAutoAttach({flatten:true})`; CLS dual reporting
- [ADR-003](openspec/adrs/ADR-003-plugin-runtime.md) Plugins in-process; npm trust; shared reports are inert JSON
- [ADR-004](openspec/adrs/ADR-004-website-chrome-extension.md) Chrome extension via `chrome.debugger`
- [ADR-005](openspec/adrs/ADR-005-share-backend.md) Cloudflare Workers + R2 + D1; Hono + S3 + Postgres self-host parity
## Capability matrix
Cross-browser deep-inspection is Chromium-only. Firefox and WebKit get CWV via the `web-vitals` polyfill + standard PerformanceObserver.
| Metric | Chromium | Firefox | WebKit |
|---|---|---|---|
| LCP / CLS / FCP / TTFB | β
| β
web-vitals | β
web-vitals |
| INP | β
| β οΈ partial | β οΈ partial |
| Cross-origin OOPIF deep inspect | β
CDP | β | β |
| Coverage (unused JS/CSS) | β
Profiler | β | β |
| Trace / heap snapshot | β
| β | β |
| HAR / network waterfall | β
| β
| β
|
| axe-core a11y | β
| β
| β
|
## Honest defer list
Documented per surface in each commit message. Not blockers for v0 dogfood:
- ~~Per-frame collector support in Chrome extension's measurement path~~ **Done (v0.2.0)**: cross-origin OOPIFs get real CDP sessions via `context.newCDPSession(frame)`.
- ~~Source-map detection on `longestScript`~~ **Done stage-1 (v0.2.0)**: schema slot + `sourceMappingURL` regex detection. Stage 2 (VLQ decode + fetch + repo-root mapping) deferred to v0.3 β depends on adding `@jridgewell/sourcemap-codec`.
- VSCode Marketplace publish **engineering ready (v0.2.0)** β `.github/workflows/publish-vscode.yml` + `vsce package` verified locally produces valid .vsix; needs anh's `VSCE_PAT` secret. See [`docs/PUBLISH-VSCODE.md`](docs/PUBLISH-VSCODE.md).
- Cloudflare Pages website deploy **engineering ready (v0.2.0)** β `.github/workflows/deploy-website.yml` ready; needs anh's `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` secrets. See [`docs/DEPLOY-WEBSITE.md`](docs/DEPLOY-WEBSITE.md).
- smithery.ai + glama.ai MCP listings **engineering ready (v0.2.0)** β `smithery.yaml` configured for stdio runtime. See [`docs/PUBLISH-MCP-LISTINGS.md`](docs/PUBLISH-MCP-LISTINGS.md).
- Chrome Web Store extension publish (requires publisher account + privacy policy URL + review cycle)
- JetBrains Marketplace + IntelliJ plugin (v0.3+)
- GDPR / Privacy Policy / DPA / Terms / DSAR endpoint (require legal review)
- Argon2id password hashing in share-server (v0 uses SHA-256; Workers doesn't expose Argon2id natively)
- Source-map decorations + CodeLens in VSCode extension (v0.3+)
- Scenario user-flow files in CLI (v0.3+ β engine assumes single-URL goto)
- TypeScript loader for `.ts` scenario files (v0.3+; v0 supports `.mjs` only)
- Cloud real-device farm (explicit non-goal per ADR-002)
- RUM SDK (different product category, explicit non-goal)
- Mobile-native apps (Android/iOS WebView remote debugging is v0.4+)
## Repository state
365 tests across 13 workspaces, all passing on Node 22 and Node 24, against real Chromium + real Hono server + mocked `chrome.debugger`/`vscode` APIs:
```
@ohmyperf/core 94
@ohmyperf/driver-playwright 6
@ohmyperf/driver-extension 6
@ohmyperf/viewer 83
@ohmyperf/reporter-markdown 8
@ohmyperf/reporter-deck 50
@ohmyperf/share-server 10
@ohmyperf/design-tokens 32
@ohmyperf/website 7
ohmyperf-vscode 2
@ohmyperf/extension-chrome 4 (+ 1 deferred-skip integration test)
@ohmyperf/mcp-server 13
@ohmyperf/tests-oopif-corpus 19
@ohmyperf/tests-visual-regression 3
@ohmyperf/eslint-plugin 7 (v0.2.0 β RuleTester)
@ohmyperf/fixers 9 (v0.2.0 β proposePatches + archetype registry)
ohmyperf-cli 10
@ohmyperf/runner 24
ββββββ
387 (+ 1 skip)
```
Quality gates wired in CI:
- `pnpm typecheck` across 31 workspaces (strict TS, exactOptionalPropertyTypes, noUncheckedIndexedAccess)
- `pnpm lint` with import-layering rules (plugins can't import core internals, viewer can't import drivers, CDP types stay inside driver packages)
- `pnpm test` (Vitest) with `OHMYPERF_CHROMIUM_PATH` for real-browser tests
- `pnpm license:audit` β 396+ packages scanned, allow-list of Apache-2.0 / MIT / ISC / BSD / MPL-2.0
- `pnpm --filter @ohmyperf/core api:check` β api-extractor enforces the frozen 1.0.0 public surface
- `actionlint v1.7.12` across all 7 workflows (0 warnings)
- `publish-stable.yml` preflight: `npm whoami` + `npm access list packages @ohmyperf` to catch misconfigured tokens before pipeline cost (skips itself in OIDC-only mode)
## Contributing
This project follows OpenSpec conventions. Architecture changes go through the multi-agent deep-design pipeline (Metis scope + Oracle architecture + Momus review) before code. See [`openspec/`](openspec/) for the proposal and ADRs.
Pull requests must:
- Pass `pnpm typecheck && pnpm lint && pnpm test && pnpm license:audit`
- Update the API contract (`packages/core/etc/core.api.md`) when changing public exports
- Match existing ESLint layering rules β no CDP types in `@ohmyperf/core`, no driver imports in `@ohmyperf/viewer`
## License
Apache-2.0. See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE) for third-party attributions (axe-core is MPL-2.0; web-vitals, Playwright, Lighthouse audit modules, tracium-equivalent are Apache-2.0).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessResponsive