aibomstd

The open standard for AI Bill of Materials

aibomstd

The open standard for AI Bill of Materials.

aibomstd defines how to describe, track, and govern the AI components inside any software product — models, datasets, frameworks, and API clients — across every team, tool, and compliance regime.

Schema CI License: Apache 2.0 PyPI


What is aibomstd?

Most software teams today have no clear answer to:

aibomstd solves this with a lightweight, machine-readable standard — a JSON schema that any team can adopt, any tool can generate, and any auditor can read.


Quick start

pip install aibomstd
from aibomstd import AiBomBuilder
from aibomstd.components import ModelComponent, ApiClientComponent

bom = (
    AiBomBuilder(product="my-ai-product", version="1.0.0")
    .add_component(ModelComponent(
        name="llama-3-8b-instruct",
        version="3.0",
        provider="meta",
        data_leaves_boundary=False,
        data_residency="IN"
    ))
    .add_component(ApiClientComponent(
        name="gpt-4o",
        version="2024-05-13",
        provider="openai",
        data_leaves_boundary=True,
        data_residency="US"
    ))
)

print(bom.to_json())

Four component types

Type What it covers
model Any ML model — local, fine-tuned, or hosted
dataset Training, evaluation, or retrieval datasets
framework LangChain, LlamaIndex, Hugging Face, etc
api-client External AI APIs — OpenAI, Anthropic, Gemini, etc

Novel fields vs CycloneDX

aibomstd extends existing SBOM standards with AI-specific fields:


CLI

# Scan a repo and generate an AI BOM
aibomstd scan ./my-repo

# Validate an existing BOM
aibomstd validate my-product.aibom.json

# Convert from cisco-aibom format
aibomstd convert cisco-output.json

# Export to CycloneDX v1.7
aibomstd export --format cyclonedx my-product.aibom.json

CI/CD integration

GitHub Action

# .github/workflows/aibom.yml
name: AI Bill of Materials Scan

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read
  pull-requests: write   # required for PR comments

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run aibomstd Scan
        id: aibomstd
        uses: aibomstd/aibomstd@v1
        with:
          scan-path: '.'
          output-file: 'aibom.json'

      - name: Show AIBOM path
        run: echo "AIBOM generated at $"

Inputs:

Input Description Required Default
scan-path Path to scan No .
output-file Output file name for the generated AIBOM No aibom.json
comment-on-pr Post scan results as a pull request comment No true

Outputs:

Output Description
aibom-file Path to the generated AIBOM JSON file

PR comments: when running on a pull request, the action posts a component-count summary as a PR comment (and updates it on subsequent pushes, rather than posting duplicates). This requires the calling workflow to grant pull-requests: write — see the permissions: block above. If that permission isn’t granted, the comment step is silently skipped and the rest of the scan still completes normally.

Pin to @v1 for stability, or @v1.0.0 / @v1.1.0 for an exact release. Avoid @main.

GitLab CI

Add this to your .gitlab-ci.yml:

stages:
  - test
  - report

scan:
  image: python:3.11-slim
  stage: test
  script:
    - pip install aibomstd
    - aibomstd version
    - aibomstd scan . --output aibom.json
    - cat aibom.json
  artifacts:
    paths:
      - aibom.json
    expire_in: 30 days
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

comment_mr:
  image: python:3.11-slim
  stage: report
  needs:
    - job: scan
      artifacts: true
  allow_failure: true
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
    - |
      python3 << 'PYEOF'
      import json, os, urllib.request, urllib.parse

      with open("aibom.json") as f:
          raw = json.load(f)

      doc = raw.get("aibomstd", {})
      by_type = doc.get("summary", {}).get("by-type", {})
      components = doc.get("components", [])

      marker = "<!-- aibomstd-scan-comment -->"
      body = marker + "\n## 📦 aibomstd Scan Results\n\n"
      body += "| Component Type | Count |\n|---|---|\n"
      body += "| Models | " + str(by_type.get("model", 0)) + " |\n"
      body += "| Datasets | " + str(by_type.get("dataset", 0)) + " |\n"
      body += "| Frameworks | " + str(by_type.get("framework", 0)) + " |\n"
      body += "| API Clients | " + str(by_type.get("api-client", 0)) + " |\n\n"
      if not components:
          body += "_No AI components detected in this scan._\n\n"
      body += "---\n*Generated by aibomstd*"

      api = os.environ["CI_API_V4_URL"]
      project_id = os.environ["CI_PROJECT_ID"]
      mr_iid = os.environ["CI_MERGE_REQUEST_IID"]
      token = os.environ.get("GITLAB_API_TOKEN")
      headers = {"PRIVATE-TOKEN": token} if token else {"JOB-TOKEN": os.environ["CI_JOB_TOKEN"]}
      notes_url = api + "/projects/" + str(project_id) + "/merge_requests/" + str(mr_iid) + "/notes"

      def api_get(url):
          req = urllib.request.Request(url, headers=headers)
          with urllib.request.urlopen(req) as resp:
              return json.loads(resp.read().decode())

      def api_write(url, data, method):
          req = urllib.request.Request(url, data=urllib.parse.urlencode(data).encode(), headers=headers, method=method)
          with urllib.request.urlopen(req) as resp:
              return json.loads(resp.read().decode())

      try:
          notes = api_get(notes_url + "?per_page=100")
          existing = next((n for n in notes if marker in n.get("body", "")), None)
          if existing:
              api_write(notes_url + "/" + str(existing["id"]), {"body": body}, "PUT")
          else:
              api_write(notes_url, {"body": body}, "POST")
          print("MR comment posted.")
      except Exception as e:
          print("Could not post MR comment: " + str(e))
      PYEOF

MR comments require a Personal Access Token. GitLab’s built-in $CI_JOB_TOKEN does not reliably have permission to post notes via the API. To enable MR comments:

  1. Create a Personal Access Token with the api scope
  2. In your project, go to Settings → CI/CD → Variables and add it as GITLAB_API_TOKEN
  3. Check “Mask variable”; leave “Protect variable” unchecked unless your test/merge branches are themselves protected branches

Without this token, the scan and artifact upload still work normally — only the MR comment step is skipped (it fails soft, so your pipeline won’t break).

Azure DevOps support is planned.


Schema

The schema lives at schema/v0.1/aibomstd.schema.json.

Validate any BOM against it:

npx ajv validate -s schema/v0.1/aibomstd.schema.json -d my-product.aibom.json

License

The schema, SDK, CLI, and CI plugins are licensed under Apache 2.0 — free to use, modify, distribute, and build on commercially or otherwise, with no restrictions.

You can adopt aibomstd as your internal standard, build products on top of it, integrate it into commercial tools, and contribute back — all without asking permission.

Hosted commercial use of aibomstd server-side services requires a separate license. See LICENSE-CLOUD for terms.


Contributing

Contributions to the schema, SDK, CLI, and CI plugins are welcome.

See CONTRIBUTING.md for how to get started.