Pixelperfect MIB browser — browse SNMP MIBs, beautifully.
A self-hostable, browser-based reference tool for SNMP MIB files. Drop a directory of MIBs and get a typographically-disciplined web UI that lets you search, navigate, and understand them — without sending anything to a third party.
- Search-first navigation —
⌘Kpalette over symbol names, OIDs, modules, and full-text descriptions - Semantic table rendering — SMIv2 tables show their columns inline,
with
INDEXcolumns flagged - Cross-references — every symbol page lists what indexes, augments, groups, or notifications reference it
- OpenNMS event export — modules with notifications offer a
↓ events.xmldownload (/m/{name}/events.xml): an OpenNMS eventconf document, one<event>perNOTIFICATION-TYPE/TRAP-TYPE. Scalar varbinds are referenced by OID (%parm[{oid}.0]%, robust to reordering); columnar varbinds stay position-based. UEI base overridable via?uei= - Walk decoder — paste or upload an
snmpwalk/snmpbulkwalk -Oncapture at/walk: it resolves each OID against the loaded MIBs and shows a per-module summary — one row per MIB the walk touched, with object/value counts — plus a derived list of which of them define notifications/traps. Click a module to open its workspace filtered to the walk, where rows are decorated with the decoded values. OIDs no module covers fall back to the IANA Private Enterprise Number registry for a vendor hint (PEN 2636 (Juniper Networks, Inc.) — load a vendor MIB). Download a ZIP bundle (walk.txt+README.txt+ the union import-closure MIBs + aMISSING.txtmanifest) to decode the walk offline. The walk is parsed in memory and never stored, logged, or written to disk; workspace pages decorate rows with walk values via a client-sidesessionStorageoverlay - Hot reload — drop a MIB anywhere under the watched directory and
it appears in seconds (recursive
fsnotify+ 250 ms debounce + transactional ingest) - Self-hosted — single binary, no telemetry, no phone-home
- Standard MIBs included — IETF/IANA core MIBs ship in the corpus
alongside vendor MIBs; refresh via
make fetch-standard-mibs && make ingest - Diagnostics surface — parse failures show file, line, severity, and code; failed MIBs never block successful ones
- Two interactive islands — virtualised
⌘Kpalette over the search API + inline glossary popovers withlocalStoragedismissal
The image ships the standard corpus (~322 IETF/IANA MIBs) at a
read-only path and mirrors it into the working corpus at every boot —
so upgrades refresh the standard set while your imported MIBs persist.
Everything that matters (curated tree, import/ intake, SQLite
cache) lives in ONE data volume:
docker run --rm -p 8080:8080 \
-v blittermib-data:/var/lib/blittermib/data \
ghcr.io/no42-org/blittermib:latestDrop files into the corpus's import/ directory (or use the web
upload, BLITTERMIB_UPLOAD_ENABLED=true). The import pipeline
compiles each file and routes it into the curated tree
(vendors/{PEN}-{vendor}/, ietf/{group}/, iana/) — imported
modules are browsable immediately, no restart. Files that fail land
in import/failed/, already-known content in import/duplicate/,
each with a .reason.json sidecar explaining why.
The bundled compose.yml binds ./import on the host into the
intake, so dropping and reviewing quarantined files is a plain
filesystem affair:
git clone https://github.com/no42-org/blittermib.git
cd blittermib
mkdir -p import
docker compose up
# in another shell:
cp ~/Downloads/SOME-VENDOR-MIB ./import/
ls ./import/failed ./import/duplicate # outcomes + reasonsOpen http://localhost:8080; the /import page shows pending files,
quarantines with reasons, and recent imports.
- The corpus root moved INSIDE the data directory (
<data>/mibs). Deployments that mounted a corpus at/var/lib/blittermib/mibscan keep that layout by passing-mibs /var/lib/blittermib/mibs, or migrate by copying the tree into the data volume (<data>/mibs/) and dropping the old mount. - Images no longer ship vendor MIBs or the
blittermib-ingestbinary — vendor MIBs enter throughimport/(drop your previous vendor set in once), and the old in-container ingest runbook is fully replaced by the pipeline. - A legacy
upload/directory is renamed toimport/automatically when the server's corpus root points at the old tree (i.e. with-mibs); on the relocated default a populated legacy corpus is flagged with a boot warning instead.
Requires Go 1.26+ and libsmi (smidump, smilint):
brew install libsmi # macOS
sudo apt install libsmi2-dev smitools # Debian / Ubuntu
sudo dnf install libsmi-devel # Fedora / RHEL
git clone https://github.com/no42-org/blittermib.git
cd blittermib
make build
./blittermib -mibs ./mibsThe Helm chart lives in its own repository —
no42-org/blittermib-chart —
with independent versioning: the chart's appVersion pins the
blittermib release it is tested against.
helm install blittermib oci://ghcr.io/no42-org/charts/blittermib --version <chart-version>Everything the release pipeline publishes — the container image and
the binary archives — is signed with
cosign keyless signing: the
signing identity is this repository's release.yml workflow (no
project-held keys exist), and every signature is recorded in the
public Rekor transparency log. (The Helm chart is published and
signed independently from
no42-org/blittermib-chart;
see its README for chart verification.)
<version> below is the release version with the v stripped (e.g.
0.8.0).
IDENTITY='^https://github.com/no42-org/blittermib/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'
ISSUER='https://token.actions.githubusercontent.com'
# container image — the digest signature also covers `latest`
cosign verify ghcr.io/no42-org/blittermib:<version> \
--certificate-identity-regexp="$IDENTITY" \
--certificate-oidc-issuer="$ISSUER"
# release tarballs — verify the signed checksums file (the
# .sigstore.json bundle carries signature, certificate, and
# transparency-log entry), then chain:
cosign verify-blob SHA256SUMS \
--bundle SHA256SUMS.sigstore.json \
--certificate-identity-regexp="$IDENTITY" \
--certificate-oidc-issuer="$ISSUER"
sha256sum -c SHA256SUMS --ignore-missing # macOS: shasum -a 256 -cThe identity regexp deliberately pins the repository, the workflow file, and the tag-ref shape — a signature from any other workflow (or a non-tag ref) fails verification.
Flags:
-data PATH directory for SQLite + state (./data)
-mibs PATH corpus directory override (<data>/mibs)
-standard-mibs PATH read-only standard set mirrored
into the corpus at boot (/usr/share/blittermib/mibs;
missing = skip)
-rebuild discard cache fingerprints and
recompile every MIB at boot
-listen ADDR HTTP listen address (:8080)
-v verbose logging (DEBUG level)
-version print version and exit
Environment variables:
BLITTERMIB_UPLOAD_ENABLED=true
Expose POST /api/v1/upload (drop zone on the landing page)
and DELETE /api/v1/upload/{name}. Off by default. This is an
UNAUTHENTICATED write surface — only enable on deployments
you control end-to-end (private LAN, reverse proxy with auth,
single-user dev box). Files land in mibs/import/ and load
through the same watcher pipeline as files copied with `cp`.
BLITTERMIB_WALK_DECODER_ENABLED=true
Expose the SNMP walk decoder at /walk: paste or upload an
snmpwalk/snmpbulkwalk -On capture and resolve each OID against
the loaded MIBs. Off by default. Walks are parsed in memory and
never written to disk, logged, or stored; when disabled the
routes 404 and the walk-overlay client asset is omitted.
URL surfaces:
/ landing
/m, /m/{module} module index + detail
/s/{module}::{name} canonical symbol page
/o/{oid} OID lookup → 302 to /s/...
/search?q=… search results
/diagnostics parse warnings + errors
/api/v1/search?q=… JSON for the ⌘K palette
/api/v1/symbol/{m}/{n} symbol JSON
/static/* embedded design system + JS islands
/healthz liveness (200 once the process serves)
/readyz readiness (corpus loaded + store usable)
/version build info
When BLITTERMIB_UPLOAD_ENABLED=true (off by default):
/upload management page: drop zone + file list
/api/v1/upload multi-file POST → mibs/import/, sync compile
/api/v1/upload/{name} DELETE single file from mibs/import/
When BLITTERMIB_WALK_DECODER_ENABLED=true (off by default):
/walk capture intake: paste or upload an snmpwalk
/walk/decode resolve a walk against the loaded MIBs (POST)
/walk/bundle offline decode ZIP bundle (POST)
MIB files libsmi SQLite + FTS5 templ + HTMX
───────────────── ────── ───────────── ────────────
./mibs/ ──fsnotify──► smidump XML ──► module/symbol/ Pixelperfect HTML
smilint diags reference/diagnostic ⌘K palette JS
symbol_fts (FTS5) glossary popovers
cmd/blittermib entry point, signal handling, orchestration
cmd/mib-migrate one-shot tool: flat MIB collection → PEN-vendor layout
cmd/mib-index regenerate mibs/INDEX.yaml metadata catalog
internal/compile libsmi subprocess wrappers + XML → model
internal/iana embedded IANA Private Enterprise Number registry
internal/model normalised in-memory types
internal/store SQLite schema, FTS5, transactional reload
internal/server HTTP, routes, templ, JSON API, embedded assets
internal/web templ templates and the design system CSS
internal/watch fsnotify hot-reload with debounce + recover
mibs/ curated corpus — vendors/, ietf/, iana/, experimental/, unsorted/
prototype/ static HTML/CSS source-of-truth for the visuals
- mibs/README.md — corpus directory layout
- mibs/CONTRIBUTING.md — adding a MIB: 4-step workflow, license-tag matrix, 4-tier CI expectations
- prototype/ — static HTML reference for the design system (open
prototype/index.htmldirectly)
make verify gofmt-check + vet + race tests
make build ./blittermib
make generate regenerate templ-generated files (after editing .templ)
make index regenerate mibs/INDEX.yaml from the corpus
make verify-mibs local MIB-corpus checks (lexical + naming + parse)
make refresh-pen refresh the IANA Private Enterprise Number snapshot
make dist cross-build release archives into dist/
make docker-build build the production Docker image (TAG=...)
make hooks install pre-commit git hooks
make check-tools verify libsmi (smidump/smilint) is installed
- Conventional Commits for every commit
- AI-assisted, human-reviewed — every commit carries an
Assisted-bytrailer; the human submitter is responsible for reviewing AI-generated code