badgevet
Find retired and broken status badges in Markdown that link checkers miss.
A retired shields.io badge returns HTTP 200 with a valid SVG whose title
reads retired badge, so ordinary link checkers (lychee, markdown-link-check)
mark it OK. badgevet fetches each badge and reads the rendered SVG title
instead, so it can tell a dead badge from a healthy one.
Install
cargo install badgevet
# or a prebuilt binary, no recompile:
cargo binstall badgevet
Usage
badgevet # scan README.md in the current directory
badgevet docs/ README.md # scan files and directories (dirs recurse for *.md)
badgevet ~/Projects/mine # one command scans every README under all your local repos
badgevet --only-broken . # report only permanently broken badges
badgevet | jq . # JSON when piped
Check every repo you own
Point badgevet at an owner and it checks the canonical published README of each of their repositories - no cloning needed. It reads the same README GitHub shows the world, so it catches badge rot even in repos you rarely touch.
badgevet --github rvben # all your public, non-fork, non-archived repos
badgevet --github rvben --only-broken
Set GITHUB_TOKEN (or GH_TOKEN) to lift GitHub's unauthenticated rate limit;
required for --include-private. Widen the default scope with
--include-forks, --include-archived, --include-private.
Example:
STATE PROVIDER LOCATION BADGE
broken shields.io README.md:3 Version
-> https://vsmarketplacebadges.dev/version/rvben.rumdl.svg
3 checked · 2 ok · 1 broken · 0 unconfirmed
How it classifies
Each badge lands in one of three states:
| State | Meaning | Fails CI? |
|---|---|---|
ok |
The badge renders a real value. | no |
broken |
A deterministic dead state (retired, deprecated). |
yes (exit 1) |
unconfirmed |
Could not be verified: an ambiguous invalid / inaccessible / empty title, or a transient network failure. Retried with backoff first. |
no (unless --strict) |
The distinction is the point. shields.io renders invalid both for a genuinely
bad badge and when its upstream API is merely rate-limiting, so unconfirmed
never fails your build by default. Only an explicit, permanent dead state does.
When a known-dead pattern has a modern replacement (e.g. shields.io's retired Visual Studio Marketplace routes), badgevet prints the suggested URL.
Fixing
scan never touches your files. The separate fix command applies those
suggestions in place:
badgevet fix # rewrite broken badges in README.md
badgevet fix docs/ # ...or across a directory of Markdown
It swaps only the badge image URL (leaving the surrounding link untouched),
changes only broken badges that have a known replacement, and is idempotent.
Broken badges with no known replacement are left alone and reported as
unfixable (exit 1). fix is local-only; it does not work with --github.
Since scan is read-only and fix mutates, they are separate commands with
honest mutating markers in the schema.
Options
| Flag | Default | Description |
|---|---|---|
--github <owner> |
- | Scan an owner's GitHub repos instead of local paths. |
--include-forks |
off | With --github: include forks. |
--include-archived |
off | With --github: include archived repos. |
--include-private |
off | With --github: include private repos (needs a token). |
--only-broken |
off | Report only permanently broken badges. |
--strict |
off | Also exit 1 on unconfirmed badges. |
--retries <n> |
2 |
Re-fetch an ambiguous badge before giving up. |
--timeout <secs> |
10 |
Per-request HTTP timeout. |
-o, --output <fmt> |
auto |
auto (text on a TTY, JSON when piped), json, text. |
Exit codes
| code | meaning |
|---|---|
0 |
no broken badges |
1 |
at least one badge is permanently broken (or, with --strict, unconfirmed) |
2 |
a path could not be read, or the HTTP client failed to build |
3 |
usage error |
Exit 1 is an outcome, not an error: stdout still carries
the full report and no error envelope is written. This makes badgevet a natural
CI or pre-commit gate.
For agents (clispec)
badgevet follows The CLI Spec: structured output on
stdout, structured error envelopes on the last line of stderr, and a schema
subcommand whose output validates against clispec.dev/schema/v0.3.json
(checked by the test suite).
badgevet schema
License
MIT
Releasing
Vership owns versioning, changelog generation, release commits, and tags. See the release runbook for the verified workflow and recovery policy.
Metadata
Release files for badgevet 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| badgevet-0.1.2.tar.gz | 57.2 kB | Without provenance | Details for badgevet-0.1.2.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| badgevet-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details for badgevet-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
| badgevet-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details for badgevet-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
| badgevet-0.1.2-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details for badgevet-0.1.2-py3-none-macosx_11_0_arm64.whl |
| badgevet-0.1.2-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details for badgevet-0.1.2-py3-none-macosx_10_12_x86_64.whl |
Total release size: 7.5 MB
Release files / badgevet-0.1.2.tar.gz
| Download URL | badgevet-0.1.2.tar.gz |
|---|---|
| Size | 57.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
30e30f2cb7da0b5c88c4953eed6778fce8af5a5d28b3f7edea7d517384f801b8
|
|
BLAKE2b-256 checksum How to use checksums |
1332a537186fc23e56476083dd681d8a7b0fde10b3508968dc5bcae2b6137944
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / badgevet-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | badgevet-0.1.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
7b6bd694f83a2b51746203088b1859f542a35bade372bd816cbeb410d42a7c99
|
|
BLAKE2b-256 checksum How to use checksums |
900da5a7ac34fc6fe5bc1e836e301ece653f5eb92564623f11a17830a9052a33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / badgevet-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | badgevet-0.1.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
4bc9c913babc1e28bc9028224e909d60c61049d6d4f37b3a58b70bd8d688e24b
|
|
BLAKE2b-256 checksum How to use checksums |
ad7bc1d35ecc51492b8ea1f00c7555bfb4e320b1018cad8a90e44ec46dea347a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / badgevet-0.1.2-py3-none-macosx_11_0_arm64.whl
| Download URL | badgevet-0.1.2-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
0e0d23bc002e2bd3211c49e0cc32f51906ca1f31d5678455940944e7aec90064
|
|
BLAKE2b-256 checksum How to use checksums |
7a5598f3dfe825531911e597f131f79786aacdb5701765ad4dfa1f414c5edd00
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / badgevet-0.1.2-py3-none-macosx_10_12_x86_64.whl
| Download URL | badgevet-0.1.2-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
b8e8effd08bbfe0932c130f21e1064b4b33bc25b08e2a738530ac9503fd45bbd
|
|
BLAKE2b-256 checksum How to use checksums |
75239dadd694c3b7d662fb1d589c73983a2fe777f8d4fcf8fbff2765a1abe1a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for badgevet 0.1.2
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.