
Security News
OpenCode User Hit with Hostile Backlash After Reporting Free AI Loophole
An OpenCode user faced harassment after reporting a free AI usage loophole, drawing a bitter backlash in a GitHub thread that has since been deleted.
@wendellresearch-ai/benchwarmers
Advanced tools
Self-hosted panel gateway for LLMs: ask a collection of models at once, keep every answer side by side, rotate explorer models in, and let your verdicts pick the next panel.
Put me in, coach.
Every model on your bench gets its minutes.
Benchwarmers is a self-hosted panel gateway for LLMs. Your app asks for one of your collections, and the whole panel answers: the models you picked for that kind of work, plus explorer seats that rotate in the models you have used least. Every answer comes back side by side, labelled by model and seat. You check them against the real work and record a verdict, and those verdicts decide who sits on the next panel.
What it is best at:
| Related tools | Examples | What they do | What Benchwarmers does differently |
|---|---|---|---|
| Gateways and routers | LiteLLM, OpenRouter, Portkey | One request to one model, with fallback | Fans one prompt out to a panel and returns every answer; for agents, routes to one member by its record |
| Councils and ensembles | LLM Council, Mixture-of-Agents | Several models merged into one answer | Keeps every answer, because who said what is the evidence; one merged summary only if you ask |
| Side-by-side chat | Open WebUI, LMArena | Several answers shown together | Records a verdict per answer and uses them to pick the next panel |
| Evaluation harnesses | promptfoo, Inspect, SWE-bench | Score models offline on fixed test sets | Scores them on your real work and your own code, and keeps rotating new models in |
Day-to-day use (the dashboard's pages, connecting apps, onboarding in bulk) is in USAGE.md. Running it on a server or a hosting platform is in HOSTING.md. A coding agent setting it up for someone should start with AGENTS.md.
v0.3, early. It runs with Python 3.11 or later on Windows, macOS and Linux, from PyPI, npm, a checkout or Docker. Expect rough edges, and read the code where these pages are thin.
Quickest, with Python 3.11+ installed, from PyPI:
pipx install benchwarmers # or: uv tool install benchwarmers
benchwarmers # or try it first, without installing: uvx benchwarmers
or from npm, with Node 18+ as well:
npx @wendellresearch-ai/benchwarmers
Either way you get the same two commands, benchwarmers and its short name
bench. It keeps your data in your user profile (BENCHWARMERS_HOME to
choose another folder), sets it up on the first run, and opens the dashboard
on http://localhost:8122, where steps 3 to 5 below continue. The built-in
model client makes every call, so nothing else needs installing. No
dependencies either way: the app is the Python standard library.
From source:
Get the code and a Python 3.11+ environment:
git clone https://github.com/WendellResearch-AI/benchwarmers
cd benchwarmers
python -m venv .venv # nothing to pip install: the standard library is enough
The built-in model client (metrics/client.py) makes every call. The
llm CLI is an alternative for its plugins:
install it in the venv and choose it on Settings (or BENCH_CLIENT=llm,
which wins).
Make a data folder. Everything that is yours (endpoints, model registrations, collections, verdicts, probe history, task answers) lives there, never in the code:
python scripts/init.py # or: python scripts/init.py <folder>
It starts the folder from examples/ (in your OS's per-user data folder
unless you name one) and points the checkout at it with a
.benchwarmers-home file; BENCHWARMERS_HOME overrides that. With
--endpoint NAME BASE_URL --key it also adds a first endpoint and asks for
its key, which goes to the key file in llm's user folder (keys.json,
shared with the llm CLI if you have it, not needed otherwise), never into
the data folder. BENCHWARMERS_KEY_<NAME> in the environment works too.
Start the dashboard. With no endpoint yet it opens on adding one: sign
in with a provider on its own page (OpenRouter, NanoGPT, Hugging Face,
Pollinations, your ChatGPT plan, GitHub Models, or a local Ollama), or paste
an API key for any OpenAI-compatible API, a hub such as Open WebUI or
LiteLLM included. Anthropic and Gemini keys can also be called through
those providers' own APIs (the API choice in the same dialog). Only providers that publish a sign-in for other apps are
offered; adding one is an entry in metrics/connect.py (its docstring says
how).
python serve.py # http://localhost:8122
Onboard a few models from it ("Onboard a model"): tick one or several; each is registered, probed and run through the suite, one at a time, with the progress beside the button. Quick probes now and leaves the suite to the scheduled passes; Quick + ad hoc also keeps the bench from ever calling the model on its own, for a metered or trial key. Tick Vision model for one that reads images and little else: it sits only for questions about images, and is tested on the vision tasks, not the code ones.
Make a collection on the Collections page (the models a panel always
includes, and what it is for). The dashboard answers the gateway's routes on
its own port (http://127.0.0.1:8122/v1); python gateway.py runs the
gateway alone on http://127.0.0.1:8123/v1.
Any OpenAI-compatible client works: ask for the model bench/<collection>.
curl http://127.0.0.1:8122/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "bench/<collection>", "messages": [{"role": "user", "content": "Where can this function return a stale value? ..."}]}'
The reply carries every seat's answer in the message, and the same seats as
data in a bench field: model, seat, status, seconds and a call id. For a chat
window that shows one answer, ask for bench/<collection>:merged: a merger
model writes one answer saying where the seats agreed and disagreed, and every
seat is still in bench. Record a verdict per call once you have checked it:
curl http://127.0.0.1:8122/bench/verdict -H "Content-Type: application/json" \
-d '{"call": "<call id>", "useful": true, "note": "found the real bug", "real": ["..."], "false": ["..."]}'
or from the dashboard. See GATEWAY.md for the full contract: images, prompt sizes, who may call, and the reply's shape.
Other clients. The same panel answers in other APIs' shapes, so a client that speaks one of them works with the server's address as its base URL:
| Format | Route | For |
|---|---|---|
| OpenAI chat completions | POST /v1/chat/completions | OpenAI SDKs, most chat apps |
| OpenAI Responses | POST /v1/responses | responses.create clients (nothing is stored) |
| OpenAI legacy completions | POST /v1/completions | tools that send a prompt |
| Anthropic Messages | POST /v1/messages | Anthropic SDKs with base_url |
| Ollama | POST /api/chat, /api/generate, GET /api/tags | Open WebUI's Ollama connection, Ollama apps |
| Gemini | POST /v1beta/models/bench/<collection>:generateContent | Google GenAI SDKs with base_url |
curl http://127.0.0.1:8122/v1/messages -H "Content-Type: application/json" \
-d '{"model": "bench/<collection>", "max_tokens": 1024, "messages": [{"role": "user", "content": "..."}]}'
Each streams when asked: the reply starts at once, and each seat's answer
arrives as that seat finishes. A panel answers with text, so a request
carrying tools is refused with a 400 that points to route mode
(bench/<collection>:route, one member with its tools; see
below). GATEWAY.md, "Other API formats",
has a curl for each and what is refused or ignored.
bench (or benchwarmers, the same program) does what the dashboard does,
without it: ask and judge, and run the bench itself. It is a client of a
running server, so the same commands work against one on another machine.
bench status what is running, and where
bench collections what you can ask
bench ask core "Where can this return a stale value?" -f cache.py
git diff | bench ask core "Review this diff" a pipe is the prompt
bench verdict <call id> --useful --real "the race in refresh()" --false "the SQL injection"
bench models --find mercury the roster, with each model's status
bench candidates --new what your endpoints serve that is not on the bench
bench onboard <served name> --wait onboard it (registered, probed, scored)
bench model retire <alias> --reason "..." and back: bench model restore <alias>
bench collection save reviewers --members a,b,c --description "adversarial review"
bench collection save reviewers --add d --remove a
bench endpoint add openrouter --base https://openrouter.ai/api/v1 (asks for the key, hidden)
bench key create my-app --collections core --rpm 30
bench settings scheduler run --off perf
--help on any command lists its options with examples, and --json prints
what the server answered, for scripts. --url points one command at another
server. ask prints every seat's answer on stdout and the table of call ids to
judge them by on stderr, so bench ask core "..." > review.md keeps only the
answers. Retiring a model, deleting a collection or an endpoint and revoking a
key ask first; --yes answers for a script. A key is never an argument (others
on the machine can read those): endpoint add prompts for it, or reads it
from stdin with --key-stdin.
Another program called bench (the Frappe framework's) may come first on your
PATH; type benchwarmers instead, which takes the same commands.
| Variable | Meaning |
|---|---|
BENCHWARMERS_URL | the server, default http://127.0.0.1:8122 |
BENCHWARMERS_ADMIN_TOKEN | the server's admin token, where it has one; sent as Authorization: Bearer for every command but ask, collections and verdict |
BENCHWARMERS_KEY | a gateway key, for ask, collections and verdict, where keys are required |
BENCHWARMERS_TIMEOUT | seconds to wait for a panel, default 900 |
Exit codes: 0 done, 1 refused or failed (the reason on stderr), 2 bad usage, 3
no server at BENCHWARMERS_URL.
A running Benchwarmers is an MCP server at /mcp on its own port
(http://127.0.0.1:8122/mcp; /v1/mcp works too), over streamable HTTP,
with three tools: list_collections, ask (a collection, a prompt,
optionally merged, with and system) and verdict. Nothing to start per
client: every agent session shares the one server, behind the same Host,
Origin and gateway-key checks as /v1. The tool descriptions carry the
rules: ask a collection, not a favourite model; verify before acting; name
every seat; send a verdict per seat you judged.
Claude Code plugin. The plugin connects to that /mcp and adds a
/benchwarmers:ask <collection> <what to ask> command and a benchwarmers
skill saying when a panel helps (adversarial review, exhaustive enumeration
over real files) and how to judge it:
/plugin marketplace add WendellResearch-AI/benchwarmers
/plugin install benchwarmers@benchwarmers
It finds the server through BENCHWARMERS_URL (default
http://127.0.0.1:8122; set it if you changed BENCH_PORT) and sends
BENCHWARMERS_KEY where keys are required. It also adds a Stop hook: at
the end of a turn it asks the server (the pending_verdicts tool, so nothing
extra runs on your machine) which seats of that session's panels have no
verdict yet, and reminds Claude of them once, as hook feedback. The server
finds the session's panels in its transcript, so the reminder needs a server
on the same machine; with one elsewhere the hook stays silent. A verdict sent
any way counts, the dashboard's included. With the plugin enabled and no
Benchwarmers running, the hook shows a hook-error notice at the end of each
turn, as /mcp shows the server as failed; start the server, or disable the
plugin for that session.
Cursor and Antigravity plugins. The same skill, with the stdio server below (so they need Node and Python 3.11 or later): Cursor's is on cursor.directory, and Antigravity's installs from the repository:
agy plugin install https://github.com/WendellResearch-AI/benchwarmers
Any other MCP client that speaks HTTP:
{"mcpServers": {"benchwarmers": {"type": "http", "url": "http://127.0.0.1:8122/mcp"}}}
with "headers": {"Authorization": "Bearer <gateway key>"} where keys are
required. A client that only speaks stdio: run benchwarmers mcp once
installed, uvx benchwarmers mcp or
npx -y @wendellresearch-ai/benchwarmers mcp without installing, or python mcp_server.py from a
checkout, a small process per client that calls the same server. For example:
{"mcpServers": {"benchwarmers": {"command": "npx", "args": ["-y", "@wendellresearch-ai/benchwarmers", "mcp"],
"env": {"BENCHWARMERS_URL": "http://127.0.0.1:8122"}}}}
On native Windows, a client that cannot start npx itself needs
"command": "cmd", "args": ["/c", "npx", "-y", "@wendellresearch-ai/benchwarmers", "mcp"].
| Variable | Meaning |
|---|---|
BENCHWARMERS_URL | the server, default http://127.0.0.1:8122 (a /v1 on the end is fine) |
BENCHWARMERS_KEY | a gateway key from Settings, sent as Authorization: Bearer; needed for a server on another machine, or where keys are required |
BENCHWARMERS_TIMEOUT | seconds to wait for a panel, default 900 |
Behind an MCP aggregator (1mcp, MetaMCP, mcp-proxy, Docker's MCP Gateway
and the like): add http://127.0.0.1:8122/mcp as an HTTP (streamable HTTP)
upstream, with the Authorization header where keys are required; an
aggregator that only runs stdio servers takes benchwarmers mcp as above.
Give it a request timeout of a few minutes or more, as a panel takes that
long; 1mcp's default of 60 seconds ends most of them. With 1mcp, for example:
1mcp mcp add benchwarmers --type http --url http://127.0.0.1:8122/mcp --timeout 900000
The aggregator prefixes the tool names (1mcp's are
benchwarmers_1mcp_ask and so on). If you also use the Claude Code plugin,
disable the plugin's own benchwarmers server in /mcp so the tools are not
listed twice; the skill and /benchwarmers:ask keep working, though the
command then asks before each tool call, since its pre-approved tools carry
the plugin's names. The plugin's verdict hook calls the plugin's own server,
so it does not work through an aggregator: with that server disabled it only
shows a hook-error notice at the end of each turn.
An agent running on a collection. The MCP tools ask a panel for a
second opinion; an agent can also be driven by a collection, in route
mode (bench/<collection>:route): one member, picked by its record, gets
each turn with its tools, stays on for the whole conversation, and is
replaced by the next member if it fails before answering. Claude Code
points at it with ANTHROPIC_BASE_URL=http://127.0.0.1:8122 and
ANTHROPIC_MODEL=bench/core:route; Codex, opencode, Cline and other
OpenAI-, Responses- or Ollama-speaking agents with the same base URL.
GATEWAY.md, "Route mode", has the set-up and the limits.
Models are scored on review work: find the faulty line, or say whether a claim about some code is true. The repository ships a starter pack:
suite/tasks/rebench-*): recent fixes from public projects,
drawn from the SWE-rebench-V2 dataset, each paired with a control.suite/tasks/claim-*): true and false statements about this
project's own code, with the code attached.Add your own from your repositories (config/repos.json in the data folder
maps a name to a folder): python suite/seed.py --repo <name> plants
realistic bugs in your real functions, each with a clean control. Private
code makes the best tasks, because no model has trained on it. See
suite/README.md, suite/REBENCH.md and
BENCHMARKS.md.
One container runs the dashboard, the gateway (on the same port, at /v1)
and the scheduler, with the data folder as a volume and no llm CLI (the
built-in client makes every call). Put the secrets in a .env file beside
compose.yaml:
BENCHWARMERS_ADMIN_TOKEN=<16 or more characters>
BENCHWARMERS_KEY_OPENROUTER=sk-or-...
then docker compose up -d and open http://127.0.0.1:8122. The compose file
publishes on this machine only; see its comments for a proxy.
Hosted, always on: HOSTING.md compares Fly.io, Railway, Render and a VPS with Caddy (cost, sleep, disks, HTTPS), with a template for each under deploy/.
Render is one click: a paid instance with a 1 GB disk and a generated admin
token. Fly.io is four commands from a checkout (cp deploy/fly.toml .,
fly launch --copy-config --no-deploy, fly secrets set BENCHWARMERS_ADMIN_TOKEN=..., fly deploy). Railway is a few steps in its CLI
or browser, in HOSTING.md.
Benchwarmers has no account, no telemetry and no server of its own; nothing reaches Wendell Research. What it sends, and where:
suite/rebench.py: the
SWE-rebench-V2 rows from Hugging Face and the files from GitHub.Keys stay in the environment or llm's key file (keys.json in its user
folder), never in the data folder. PRIVACY.md and SECURITY.md have the
detail.
llm CLI, when you choose it, are neither paced nor counted.runs/.Both servers listen on 127.0.0.1 by default and accept only same-origin writes
for their own host name, so a web page in your browser cannot drive them. To
listen anywhere else, set BENCHWARMERS_ADMIN_TOKEN first; without it they
refuse to start. With it, the dashboard asks for a login and the gateway takes
named, revocable gateway keys. Settings, under Server and access, shows how
this stands (whether a secret is set, never its value).
SECURITY.md has the whole model and how to report a vulnerability.
python scripts/check.py # every self-check and test (--quick skips the slow one)
The core is the Python standard library only. CI runs the checks on Linux and Windows for Python 3.11 to 3.13, and on macOS.
Benchwarmers isn't taking outside contributions yet; that opens once it is more established. A security problem goes through SECURITY.md.
MIT, Copyright (c) 2026 Wendell Research (LICENSE). The starter tasks and bundled fonts carry their own licences, listed in NOTICE. Use is also covered by TERMS.md.
FAQs
Self-hosted panel gateway for LLMs: ask a collection of models at once, keep every answer side by side, rotate explorer models in, and let your verdicts pick the next panel.
The npm package @wendellresearch-ai/benchwarmers receives a total of 0 weekly downloads. As such, @wendellresearch-ai/benchwarmers popularity was classified as not popular.
We found that @wendellresearch-ai/benchwarmers demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
An OpenCode user faced harassment after reporting a free AI usage loophole, drawing a bitter backlash in a GitHub thread that has since been deleted.

Threat Research
/Security News
319 browser extensions installed by 13.4 million users hijack searches, capture queries, and collect referral payments from Yahoo and Bing.

Threat Research
Malicious Firefox extensions mimic Phantom, Jupiter, and Bitget wallets to steal recovery phrases and private keys, with one fetching its payload remotely.