Skip to main content

slopbench — measure package hallucination in model output

Latest results: Where AI coding models invent packages (HALLUX panel, 22 Sep to 2 Oct 2026): 3.83% of 2,532 package suggestions from four model families named packages that do not exist; 0.17% on routine prompts, 5.83% on prompts about emerging tools. Full write-up.

Built by Blvkware

CI License: Apache-2.0 Python 3.9+

slopbench measures how often a language model or coding agent names a software dependency that no established package answers to, and — the part that matters — how often it names the same one twice. It covers PyPI, npm and crates.io, needs nothing beyond the Python standard library, and runs free against a local model.

pip install slopbench
slopbench run --provider ollama --model qwen2.5-coder:7b --samples 5 --report out.html

To work on slopbench itself, clone this repository and run pip install -e ".[dev]".

Why recurrence is the measurement

A hallucination rate on its own overstates the threat. A package name a model invents once and never again cannot be pre-registered by anyone, because nobody can predict it. It breaks a build, loudly, and someone fixes it.

The dangerous names are the ones that come back. A name that recurs across independent samples of the same prompt is a name an attacker can reproduce, register, and wait on. That is the entire mechanism behind slopsquatting, and it is why published hallucination rates and published risk are different numbers.

So slopbench samples every prompt several times at a real temperature, and only calls an invented name targetable once it has appeared in at least two of those samples. One-off inventions are reported, clearly labelled, and kept out of the headline.

What it reports

Status Meaning
does not exist No package by that name on the registry. Breaks the build.
exists, unadopted A package by that name exists, with no adoption behind it. The install succeeds silently. This is the serious one.
excluded The registry could not be reached for this name. Never counted as clean.

Three things that would each be easy to get wrong, and are deliberately not:

  • A registry failure never becomes a pass. Unverifiable names are excluded from every count and stated in the report, rather than quietly scored as fine.
  • exists is not reassurance. A name a model invents that also exists, with one version and no downloads, is worse than one that 404s.
  • Age does not clear a name. A package published once and never updated, still collecting almost nothing, is not established because it got old. Sitting untouched is what a planted name does while it waits.

Extraction is conservative on purpose

Every number rests on deciding what counts as "the model suggested a package," so the extractor drops anything it cannot stand behind:

  • Standard library, Node builtins, and Rust std — import asyncio is not a dependency. The Python list ships as data and unions across versions.
  • Relative and absolute imports, and modules the response defines itself. A model that writes utils.py and then imports from it wrote coherent code.
  • Import names that differ from distribution names: import yaml installs PyYAML, import cv2 installs opencv-python. Reporting yaml as invented is the fastest possible way to lose a reader.
  • Prose that happens to follow an install command. Install commands are read only from fenced blocks, inline code spans, and lines that begin with a package manager, and the package list stops at the first token that could not be a name on that registry. Reading them out of running text turned "run pip install pandas to load the data" into four PyPI packages, three of which were English words that 404, recur in every sample, and would have been reported as targetable. Flag arguments are skipped too, so pip install -r requirements.txt does not name requirements.txt as an invented package.

The counts are a floor, not a ceiling. That is the right direction for a number you intend to show someone about their own product. A package named only in running prose is missed, and that is the trade being made deliberately.

Providers

Provider Configure with Notes
ollama OLLAMA_HOST Local, free. Start here.
anthropic ANTHROPIC_API_KEY Current Claude models sample only at their own defaults and refuse a temperature. slopbench then drops it for the rest of the run and states in the report how many samples were drawn that way.
openai SLOPBENCH_BASE_URL, SLOPBENCH_API_KEY (or OPENAI_API_KEY) Any /v1/chat/completions endpoint: OpenAI, Groq, Together, OpenRouter, vLLM, LM Studio. The base URL defaults to https://api.openai.com/v1.

Every completion is cached to disk keyed by provider, model, prompt, temperature, and sample index. Generation is the only step that costs money; extraction and scoring are free and get iterated on constantly. A scoring change re-runs for nothing, and a published result stays reproducible from the cache after the endpoint behind it has moved on.

Usage

# see the corpus without running anything
slopbench prompts --ecosystem npm

# a cheap first run: one ecosystem, a few prompts
slopbench run --provider ollama --model qwen2.5-coder:7b \
  --ecosystem npm --limit 6 --samples 5 --report out.html

# full run with every output
slopbench run --provider anthropic --model claude-sonnet-5-5 \
  --samples 5 --report out.html --markdown out.md \
  --json out.json --corpus corpus.json --subject "Acme Agents"

Exits 1 when any targetable name was found, so it drops into CI as a regression gate on your own agent.

--corpus writes recurring findings in pkgguard's known-hallucination format, ready to drop in as data/known_hallucinations.json. Only names that recurred are emitted — pkgguard's own documentation warns that a padded corpus produces confident wrong blocks, and a name invented once is not evidence of anything.

If the file already exists it is merged, not overwritten: names are unioned, the date each was first seen is kept, and every run that contributed is listed in _provenance. The corpus is the part that accumulates, so a scheduled run that happened to see nothing must not erase what an earlier one found. A file that is not in pkgguard's format is refused rather than merged into nonsense — pkgguard loads a malformed corpus without error and simply finds no names in it, which is the kind of failure nobody notices.

slopbench run --provider ollama --model qwen2.5-coder:7b --samples 5 \
  --corpus path/to/pkgguard/data/known_hallucinations.json
# corpus: 2 new name(s) written to path/to/pkgguard/data/known_hallucinations.json

pkgguard is optional

If pkgguard is installed, slopbench uses it for registry scoring and gets its conflation detection and adoption-ratio typosquat confirmation. If it is not, slopbench falls back to direct registry calls with a deliberately simpler classifier. The fallback is weaker and says so: it will call some genuine squats established that pkgguard catches.

pip install "slopbench[pkgguard]"

The extra installs pkgguard's published distribution, blvkware-pkgguard, which provides the pkgguard module. Install it under that name. The bare name pkgguard is not registered on PyPI.

The prompt corpus

30 prompts (12 PyPI, 11 npm, 7 crates.io), in three tiers:

  • routine (8 prompts) — well-covered tasks. This is the control. Invention here means the problem is not confined to obscure corners.
  • niche (12) — specific integrations with real but thinner public coverage.
  • emerging (10) — areas where training data is thinnest, which is where invention concentrates.

No prompt names a package. A prompt that names a library measures instruction-following, not invention, and a test enforces this against the corpus.

Point --prompts at your own file to benchmark your own agent's real workload. The corpus is the part worth customizing.

Limits

  • One model, one date, one set of conditions. Re-running after a model update gives a different number, and it should.
  • Recurrence is measured within a prompt, so a low sample count understates it. Below --samples 2 the measurement does not exist and the CLI refuses.
  • This measures what a model says. An agent with retrieval, a lockfile, or a private registry may never act on it.
  • Finding zero targetable names is a real result and the report says so plainly rather than manufacturing a concern.

FAQ

What is slopsquatting? Registering a package name that AI models invent, so that code or an agent which installs the invented name gets the attacker's package. It works only when the invented name is predictable, which is why slopbench measures recurrence.

How often do AI coding models invent packages? In the October 2026 HALLUX panel, 3.83% of 2,532 package suggestions from four model families named packages that did not exist (95% interval 3.15% to 4.65%). The rate was 0.17% on routine prompts and 5.83% on prompts about emerging tools. The four families were statistically indistinguishable.

What makes an invented name "targetable"? It appeared in at least two independent samples of the same prompt. A name invented once cannot be predicted, so nobody can register it in advance.

Can I test my own agent or prompts? Yes. Point --prompts at a JSON file in the same shape as slopbench/data/prompts.json, and use the openai provider for any OpenAI-compatible endpoint. The CLI exits 1 when it finds a targetable name, so it can gate CI.

Does it cost anything? Only the model calls. Ollama runs locally for free, and every completion is cached, so re-scoring a run costs nothing.

Citing

If you use slopbench or the panel data, cite it with CITATION.cff (GitHub's "Cite this repository" button reads it). The panel data is CC BY 4.0. Cite https://blvkware.dev/ai-package-hallucination-data/.

License

Code: Apache 2.0. Panel data in reports/: CC BY 4.0. Built by Blvkware.

Metadata

Release files for slopbench 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for slopbench 0.1.1
File Size Uploaded Provenance Actions
slopbench-0.1.1.tar.gz 49.7 kB With provenance Details for slopbench-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for slopbench 0.1.1
File Interpreter ABI Platform Actions
slopbench-0.1.1-py3-none-any.whl Python 3 none any Details for slopbench-0.1.1-py3-none-any.whl

Total release size: 90.0 kB

Release files / slopbench-0.1.1.tar.gz

Download URL slopbench-0.1.1.tar.gz
Size 49.7 kB
Tags Source
SHA-256 checksum
How to use checksums
292942fb1955567abadc4c7539dab4394c2100147fbfc48bf8516d0c856b50a2
BLAKE2b-256 checksum
How to use checksums
200bb1726017713f3bb3b4fc9ee09daea1027915ff102b600229ca5acdbed244
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.

Transparency log

Release files / slopbench-0.1.1-py3-none-any.whl

Download URL slopbench-0.1.1-py3-none-any.whl
Size 40.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8bdc05db42fa585f2b2a5827f6415d220237b7fe6c71f82f844d733529221626
BLAKE2b-256 checksum
How to use checksums
83ba83c87480a1a050a3db1443abc779b5346c7a6750bc01448250f2a76ec2d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.

Transparency log

Security for slopbench 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for slopbench-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page