[pepe load-testing a server: the live dashboard, the request log, and the verdict]
pepe sends requests to a URL, as many at once as you ask, and shows what came back as it happens: throughput, latency percentiles and a heatmap, status codes, failures by cause, and a log you can open any request from. When the run ends it gives a verdict in plain words, and says where the time went. It takes a curl command as input, ramps load to find where a target stops keeping up, load-tests every endpoint of an OpenAPI spec, replays an access log, and runs a flow of requests where each step feeds the next. pepe ping is the same engine at one request a second: a graph of a URL's latency over time, each ping split into DNS, connect, TLS, first byte and download, with what to look at.
It is also light. One thread sends 160k requests a second on an Apple M4 Pro and 400k on Linux, for less CPU and less memory per request than wrk, a quarter to a half of oha's CPU and a tenth of its memory or less, and pepe tells you when it, rather than the target, is the limit.
Install
Windows, in PowerShell: powershell -ExecutionPolicy Bypass -c "irm https://pepe.mhaimdat.com/install.ps1 | iex". Every release also ships binaries for macOS, Linux and Windows with checksums and signed provenance, the shell completions and the man pages. pepe self-update installs the latest release; pepe looks for one once a day and says so when a run ends. All of it, with the details, on the install page.
Quick start
In the dashboard, space pauses, + and - change concurrency, tab switches view, enter inspects a request, ? lists every key, q quits and leaves the verdict in your shell.
What it does
Every flag of every command is in the command reference, and man pepe has the same.
Scripts, CI and agents
Every mode runs without a screen and is built to be called by a program:
- A versioned JSON report with
--json (schema_version: 1; pepe schema prints each report's JSON Schema), with the verdict and its findings in it. Piped without --json, the text verdict.
- Exit codes that mean something: 0 as asked, 1 couldn't start or nothing answered, 2 a usage error or a guardrail, 4 a limit crossed (
--fail-if 'p99 > 300ms', a ping's --slo).
- Guardrails checked before anything is sent:
--allow-host .example.com, --max-requests, --max-rate, --max-concurrency, and --dry-run, which says what would be sent and sends nothing. They can live in pepe.toml.
- A GitHub Action that runs a test, puts the numbers in the job summary and outputs, holds a pull request against its base branch with
pepe compare, comments the result and can fail the job: CI and Docker.
- Prometheus metrics with
--metrics :9100, for a soak run or a long ping in Grafana.
- An MCP server (
pepe mcp) that serves the modes as tools for an agent, under the guardrails it was started with; AGENTS.md is what an agent reads first.
How pepe compares
Measured with the suite in bench/ against a local server that answers from memory, so the client is the cost being measured. CPU milliseconds per 1,000 requests, peak memory, and the requests per second each tool reported:
Those are single-thread numbers for pepe on an Apple M4 Pro, where the loopback tops out near 175k requests a second. On Linux (a 4-vCPU arm64 VM, the musl build that is released), with wrk on one thread beside it:
Every workload, where pepe is level rather than ahead (a slow target at 1,000 connections, 16 KB bodies over TLS), what a glibc build changes, k6, the profiles and the method are in bench/README.md. Where a target can take more than one thread sends, pepe says so, and --threads auto adds them.
Documentation
The manual, page by page, with every option and example, is at pepe.mhaimdat.com/docs. Its sources are the Markdown files under docs/, and the command reference is generated from the command definition, so it can't drift from the binary. What changed in each release is in CHANGELOG.md; what comes next, in order, in ROADMAP.md.
Contributing
Issues and pull requests are welcome; CONTRIBUTING.md has the build, the tests, the generated files, the recordings, the benchmarks and how releases are made.
License
MIT. See LICENSE.
Acknowledgements
tokio, rustls, httparse, h2 and reqwest for the requests, ratatui and crossterm for the dashboard, clap for the command line, and oha, vegeta, wrk and k6 for being good company on the benchmark table.