octoperf-export-bench-report-pdf
This Claude Code skill exports an OctoPerf benchmark report as a PDF by submitting an async print task, polling until the server-side Playwright render completes, and retrieving a download URL. Use it when users request a static, shareable PDF artifact of an existing report for stakeholder review or archival purposes, rather than for real-time metric analysis.
git clone --depth 1 https://github.com/OctoPerf/octoperf-claude-plugins /tmp/octoperf-export-bench-report-pdf && cp -r /tmp/octoperf-export-bench-report-pdf/plugins/octoperf/skills/octoperf-export-bench-report-pdf ~/.claude/skills/octoperf-export-bench-report-pdfSKILL.md
# OctoPerf — Export a benchReport as PDF
OctoPerf prints reports server-side with a headless Playwright render.
The work is async: the MCP tool submits the task, the LLM polls until
it settles, then pulls the PDF off the report's first bench result.
## When this applies
The user wants a static, shareable artefact of an existing bench
report — a stakeholder review, an attachment to a ticket, an offline
archive. If the user just wants to *read* metrics, use the report
value tools (`get_report_summary_values`, `get_report_table_values`,
…) instead. The PDF is for hand-off, not analysis.
## Prerequisites
- A `benchReportId` (find it with `list_bench_reports_by_project`).
- The underlying bench run is terminal (FINISHED / ABORTED / ERROR).
Printing a report whose run is still RUNNING is allowed but the
metrics inside the PDF will be partial.
## The three-step chain
### 1. Submit the print task
```
export_bench_report_pdf(benchReportId)
# returns { benchReportId, taskId }
```
The tool returns immediately with a `taskId`. Defaults are sensible
(portrait A4, empty cover page, en-US locale, UTC timezone) — no extra
parameters needed for the common case.
### 2. Poll until the task settles
```
get_task_result(taskId)
# returns { taskId, status, message }
```
`status` cycles through `PENDING` while Playwright is rendering. Stop on:
- `SUCCESS` → the PDF has been uploaded to the report's first bench
result. Continue with step 3.
- `FAILED` → `message` carries the backend stack trace. Surface it to
the user verbatim and stop.
Typical render time is 10–30 seconds; expect more on large reports
(many widgets, long trend series). For the polling cadence and the
sleep-between-polls discipline, read `octoperf-async-polling` — the
PDF task is in its table (3s between polls, ~5 min outer deadline).
### 3. Locate the PDF and hand the user a download URL
The PDF lands on the *first* benchResult of the report
(`report.benchResultIds[0]`). For SIMPLE reports that's the only one;
for TREND reports, only the anchor result carries the file.
```
get_bench_report(benchReportId)
# read .benchResultIds[0]
list_bench_result_files(benchResultId)
# find the newest `.pdf` entry — filename is derived from the report
# name with non-word chars replaced by `_`, e.g. `My_Load_Test.pdf`
download_bench_result_file(benchResultId, filename)
# returns { url, method: "GET", expiresAt, instructions }
```
Hand `url` to the user. The single-use token is consumed on the first
GET and the URL expires in ~5 minutes — re-call
`download_bench_result_file` if the user needs a fresh link.
## Gotchas
- **TREND / COMPARISON reports**: the PDF is attached to the
*anchor* bench result only, not to every result in the trend.
`list_bench_result_files` on a non-anchor benchResult won't see it.
- **Re-exporting**: re-running `export_bench_report_pdf` produces a
new file with the same sanitized filename — the previous PDF is
overwritten on the storage layer.
- **Filename collisions**: two reports with the same name (after
`\W+ → _` sanitisation) would land on the same filename if they
share a benchResult. In practice reports rarely share a benchResult
outside of trend/comparison setups, so this is mostly a curiosity.
- **Don't busy-loop on `get_task_result`.** See
`octoperf-async-polling` — insert a bounded `Bash sleep` (3s for
the PDF task) between every `get_task_result` call.
## See also
- `octoperf-async-polling` — full polling cadence + terminal conditions for `get_task_result`.
- `octoperf-bench-reports` — when the user wants the same metrics interactively rather than as a PDF.Use whenever an OctoPerf operation runs asynchronously and the LLM has to wait for it to settle — `validate_virtual_user`, `run_scenario`, `export_bench_report_pdf`, the async correlation tasks behind `apply_correlations_to_virtual_user`, or any tool that returns a `taskId` / `benchResultId` instead of the final result. Defines the cadence, the terminal conditions, and the anti-patterns so the LLM does not tight-loop the MCP server or sleep blindly for the full expected duration.
Use when an OctoPerf Virtual User imported from a HAR/Postman/JMX recording fails its validation run because dynamic values (session tokens, CSRF, signed URLs, anti-forgery inputs, auth challenges) captured at recording time are stale on replay. Triggers on requests for "auto-correlation", "correlate the VU", "fix replay errors", "401/403 on replay after import", "tokens don't match", "signature mismatch in load test". Walks the LLM through framework preset selection, async polling, and regex-rule fallback. Requires the OctoPerf MCP server to be connected.
Use when reading or interpreting an OctoPerf bench report — picking the right `get_report_*_values` tool for a given widget, understanding the difference between flat and trend reports, decoding semantic gotchas (Hits vs Hits CONTAINER, 304 cache hits skewing throughput, Playwright per-step row types, etc.). Triggers on "what's the right tool for this widget", "explain this metric", "how do I read this trend report", "what does parallelRunsSupported mean", "why is the Network row 24ms while page.goto is 364ms", "DELTA computeType". Complements `octoperf-scenario-diagnosis` — that skill walks the diagnosis workflow, this one is the widget-by-widget reading guide. Requires the OctoPerf MCP server.
Use when the user wants to run a real-browser probe alongside a JMeter HTTP load test to capture user-perceived metrics (page load time, render time, JS execution, Core Web Vitals) while JMeter generates the bulk HTTP load. Triggers on "real browser monitoring during load test", "EUM probe", "playwright probe", "synthetic monitor during bench", "convert my JMeter VU to Playwright", "RealBrowser user", "TruClient equivalent", "hybrid load test (HTTP + browser)". Walks the LLM through JMeter→Playwright VU conversion (direct translation or codegen capture) and hybrid scenario composition (N×JMeter for load + 1×Playwright probe for UX measurement). Requires the OctoPerf MCP server.
Use when an OctoPerf load-test scenario has completed (or is running) and the user wants to understand why it failed, underperformed, or behaved unexpectedly. Triggers on "the load test failed", "why are response times so high", "high error rate in the scenario", "diagnose this bench", "the run looks bad". Walks the LLM through reading global metrics, narrowing scope, comparing against validation, and surfacing the right next step (re-validate, tune scenario, fix infra). Requires the OctoPerf MCP server and a `benchResultId` to investigate.
Use when scheduling an OctoPerf scenario to run at a specific time (one-shot) or on a recurring cadence (cron), or when listing / pausing / resuming / deleting an existing schedule. Triggers on "schedule the scenario for tomorrow morning", "run this every weekday at 8am", "every night at midnight", "pause the cron job", "delete the schedule", "show scheduled jobs". Covers the unusual cron format (Unix 5-field UTC, NOT Quartz), the timezone conversion gymnastics, the pre-flight rule (a misconfigured scenario will fire failing runs forever until disabled), and the full job lifecycle. Requires the OctoPerf MCP server.
Use when an OctoPerf Virtual User validation run has produced many failing actions and the user needs to diagnose them efficiently without reading every single failure serially. Triggers on "the validation is red", "lots of errors after import", "VU validation failed, what's wrong", "triage these failures", "why is my virtual user failing". Groups failures by category, drills into one representative per group, and proposes the matching MCP-tool fix. Requires the OctoPerf MCP server.