I build AIROM, an open-source AI Bill of Materials scanner. It finds the AI inside a codebase — models, prompts, datasets, embeddings, vector databases, frameworks — and records the evidence behind every single finding.
Most of my work is the unglamorous half of that: parsers that eat untrusted bytes without trusting them, an evidence model that survives serialization into five formats, and a release pipeline you can verify without taking my word for anything.
Unknown is not the same as safe. A scanner that guesses is worse than one that says nothing.
pip install airom && airom scan .┌──────────────────┬────────────────────────┬─────────┬──────────┬───────┬────────────────────┐
│ KIND │ NAME │ VERSION │ PROVIDER │ CONF │ LOCATION │
├──────────────────┼────────────────────────┼─────────┼──────────┼───────┼────────────────────┤
│ hosted-llm │ gpt-4.1 │ - │ openai │ 0.85 │ src/rag.py:15 │
│ embedding-model │ text-embedding-3-large │ - │ openai │ 0.85 │ src/rag.py:6 │
│ vector-db │ chroma │ 0.5.5 │ chroma │ 0.985 │ requirements.txt:4 │
│ local-model-file │ tiny.gguf │ - │ local │ 0.95 │ models/tiny.gguf │
└──────────────────┴────────────────────────┴─────────┴──────────┴───────┴────────────────────┘
That LOCATION column is the whole point. When an auditor asks "why does your AIBOM say
gpt-4.1?", there is an answer and it is in the document: the file, the line, the detector
that fired, and the arithmetic behind the confidence score.
|
~59k lines of Go, 114 test files, 29 releases. Ships as one static Detects across 9 languages, from manifests, lockfiles, installed metadata, binary model headers, and even frozen PyInstaller archives. Emits CycloneDX 1.6/1.7, SPDX 3.0.1, SARIF 2.1.0, OpenVEX, JSON, YAML, and a compliance view mapping NIST AI RMF and OWASP Agentic controls. |
Parsers are hostile input. Every binary header parser — GGUF, safetensors, ONNX, PyTorch, SavedModel, TFLite, HDF5, TensorRT — is fuzzed in CI and must return an error, never panic. Weights are identified by magic bytes. Nothing is loaded or executed, ever. Releases are verifiable. Keyless-cosign-signed, reproducible, checksummed. The rule-update channel is ed25519-signed with rollback protection. The build is the gate. Race tests, 6 cross-compile targets, fuzz campaigns, an RSS ceiling, CodeQL, govulncheck, and a benchmark gate that fails on detection regression. |
|
A traversal guard that let A rule pack that shipped twice Two packs, same keywords, different IDs. One line of Python produced four occurrences of one component, feeding the confidence calculus corroboration that did not exist. |
A lexer nothing ever fuzzed
A schema that rejected its own output
|
Each of those shipped with a test that fails without the fix. A fix without a failing test is a guess.
| airom | The scanner. Go, Apache-2.0. |
| airom-rules | Signed rule channel — new providers reach users without a new binary. |
| airom-bench | Public benchmark corpus. Detection is measured, not asserted. |
| airom-web | airom.dev and docs.airom.dev. |


