Skip to main content
Glama

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/ β€” 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.

npm ohmyperf MCP server MCP Chromium 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:

$ 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 is what LLM agents see β€” including (v0.2.0, pending publish):

  • 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

  • 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, 16 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

# 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):

{
  "mcpServers": {
    "ohmyperf": {
      "command": "npx",
      "args": ["-y", "@ohmyperf/mcp-server@latest"]
    }
  }
}

Then your LLM has 16 tools available: measure, propose_patch, verify_fix, get_fix_plan, get_trust_score, get_servability, diff, list_reports, 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          12 tools + 7 prompts (v0.1.0) β€” 17 tools in v0.2.0 [Unreleased]
        β”œβ”€β”€β–Ί 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.1.0 on npm. v0.2.0 (issue #7) ships the agent fix loop + LLM-first signals + 2 new packages, pending credential refresh.

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); 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)

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

ohmyperf run https://example.com

2

npm SDK

@ohmyperf/core

import { runEngine, measure } from "@ohmyperf/core"

3

Chrome extension

apps/extension-chrome/

Load unpacked β†’ click toolbar icon

4

Website (SPA)

apps/website/ Β· spec measurement-spa

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/

Cmd+Shift+P β†’ OhMyPerf: Measure URL

6

MCP server

apps/mcp-server/

14 tools incl. measure, propose_patch (v0.2.0), verify_fix (v0.2.0)

7

Share-server

packages/share-server/

Cloudflare Workers or node dist/node.js

8

ESLint plugin (v0.2.0)

@ohmyperf/eslint-plugin

npm i -D @ohmyperf/eslint-plugin + extends: ['plugin:ohmyperf/recommended']

9

Fixer SDK (v0.2.0)

@ohmyperf/fixers

import { proposePatches } from "@ohmyperf/fixers"

CLI quickstart

# 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 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

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 for the 45-export contract.

Chrome extension

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

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:

{
  "mcp": {
    "ohmyperf": {
      "type": "local",
      "command": ["npx", "ohmyperf-mcp"]
    }
  }
}

Register with Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
  "mcpServers": {
    "ohmyperf": {
      "command": "npx",
      "args": ["ohmyperf-mcp"]
    }
  }
}

Install from Glama (MCP directory)

The OhMyPerf MCP server is listed in the Glama MCP directory β€” one-click install paths for every Glama-supported client, no npx command required.

# 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

What's available where: @ohmyperf/mcp-server@0.1.0 currently on npm exposes the 12 tools NOT marked (v0.2.0). The 5 v0.2.0-tagged tools (propose_patch, verify_fix, get_fix_plan, get_trust_score, get_servability) are committed on main and will land when v0.2.0 publishes β€” track at issue #7. All 17 tools + 7 prompts are also available today by pointing an MCP client at npx -y @ohmyperf/mcp-server@main once v0.2.0 lands.

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)

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 with exit-code-style verdict

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 (v0.2.0)

{ reportPath | uri, opportunityId?, url?, maxPatches? }

Structured { archetype, url, search, replace, rationale, expectedImpactMs, confidence }[] patches an agent can apply

verify_fix (v0.2.0)

{ baselineReportPath | baselineUri, candidateUrl, runs?, mode? }

Re-measures candidate + Mann-Whitney U diff vs baseline; verdict βœ… no regression / ❌ REGRESSION DETECTED

get_fix_plan (v0.2.0)

{ reportPath | uri, limit?, applicabilityFilter? }

Precomputed ranked, ROI-scored fixPlan slice only β€” saves the agent parsing the full 50KB+ report

get_trust_score (v0.2.0)

{ reportPath | uri }

trustScore.overall + per-metric verdicts + recommendedAction so agents skip noisy measurements before acting

get_servability (v0.2.0)

{ 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 (v0.2.0)

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 verified composition). Patches archetypes covering ~80% of typical opportunities (render-blocking scripts/stylesheets, LCP image fetchpriority + preload).

Website

Live at 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).

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

Two deployment targets from the same Hono codebase:

Cloudflare Workers + R2 + D1 (production)

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)

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:

- 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 Driver abstraction; Playwright primary; raw CDP via newCDPSession()

  • ADR-002 OOPIF via Target.setAutoAttach({flatten:true}); CLS dual reporting

  • ADR-003 Plugins in-process; npm trust; shared reports are inert JSON

  • ADR-004 Chrome extension via chrome.debugger

  • ADR-005 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.

  • 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.

  • smithery.ai + glama.ai MCP listings engineering ready (v0.2.0) β€” smithery.yaml configured for stdio runtime. See 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/ 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 and NOTICE for third-party attributions (axe-core is MPL-2.0; web-vitals, Playwright, Lighthouse audit modules, tracium-equivalent are Apache-2.0).

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

–Maintainers
14hResponse time
1wRelease cycle
2Releases (12mo)
Commit activity

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hoainho/ohmyperf'

If you have feedback or need assistance with the MCP directory API, please join our Discord server