Dependencies

Generating an AIBOM

Produce a CycloneDX 1.6 AI Bill of Materials with xgrep sbom --aibom — an inventory of the AI/LLM SDKs, frameworks, inference runtimes, and models a codebase uses, across 16 languages, fully offline.

Generating an AIBOM

xgrep sbom --aibom builds an AI Bill of Materials (AIBOM): a machine-readable inventory of the AI building blocks a codebase uses — which model providers it calls (OpenAI, Anthropic, Google Vertex/Gemini, AWS Bedrock, Together AI, …), which orchestration frameworks it is built on (LangChain, LlamaIndex, Spring AI, the Vercel AI SDK, …), which local inference runtimes it embeds (Ollama, llama.cpp, Hugging Face Transformers, ONNX Runtime), and which models it requests (gpt-4o, claude-3-5-sonnet, …).

xgrep sbom --aibom .

The scan is fully offline and reads source code, detecting AI usage with xgrep's language-aware rule engine — the AIBOM reflects what the code actually imports and calls, not what a manifest merely declares. Where a detected library also appears in the project's dependency manifests, its version and package URL (purl) are attached to the component (see Versions below); a library the code imports but no manifest pins simply stays version-less. The output is a CycloneDX 1.6 JSON document on stdout:

xgrep sbom --aibom --output aibom.cdx.json .

--aibom selects the AI-inventory bill of materials; it emits AI assets only and does not include your software dependencies — run plain xgrep sbom for those. Because AI-inventory detections are a distinct category, they never appear in a normal xgrep scan — an AIBOM is an inventory, not a list of vulnerabilities.

What it detects

Every detected asset is a CycloneDX component carrying an aibom:* property set. The aibom:kind facet classifies it, so a consumer can filter to just the providers, just the models, and so on:

aibom:kindWhat it isExamples
providera hosted/managed LLM API SDKOpenAI, Anthropic, Cohere, Together, Groq, AWS Bedrock, watsonx
frameworkan orchestration / agent frameworkLangChain, LlamaIndex, Spring AI, Vercel AI SDK, Semantic Kernel
inferencea local / self-hosted inference runtimeOllama, llama.cpp, Hugging Face Transformers, ONNX Runtime
ml-corea general ML frameworkPyTorch, TensorFlow, Candle, DJL
vector-dba RAG vector-store clientPinecone, Chroma, Qdrant, Milvus, Weaviate
modela specific model requested in codegpt-4o, claude-3-5-sonnet, gemini-1.5-pro

Other facets carried per asset:

  • aibom:provider — the canonical provider (e.g. Google Gemini for both the new and legacy Google SDKs), so distinct SDKs still roll up to one provider.
  • aibom:hostingmanaged-api, cloud-platform, or local.
  • aibom:deprecated — set on superseded SDKs (e.g. Google's legacy google-generativeai, @xenova/transformers) so legacy AI usage is surfaced, not hidden.
  • aibom:openai-compatible — set on providers reached through the OpenAI SDK with a custom endpoint (see below).

Providers, frameworks, inference runtimes, and models are emitted as CycloneDX library components; models are emitted as machine-learning-model components. The document's dependencies graph links each detected model to the provider it is served by.

Versions

When a detected library is also declared in the project's dependency manifests, its component carries the pinned version and a purl (e.g. pkg:pypi/openai@1.35.7, pkg:npm/openai@4.52.1), so the inventory can be matched against advisory feeds. Versions are read from package.json and npm lockfiles, go.mod, requirements.txt, and the common Python/Ruby/PHP/Rust/Java lockfiles — all offline.

The version is only ever attached to a library the code actually imports, never synthesized from a manifest line nothing uses. A library with no matching manifest entry stays version-less rather than guessing. Because one provider can be reached from more than one ecosystem (say openai used from both Python and JavaScript), a component whose usages resolve to different versions is left version-less — the BOM states a version only when every usage agrees, and the per-file evidence still records where each import was found.

Providers reached through a custom endpoint

Many providers are used through the OpenAI SDK pointed at a different base URL. xgrep resolves the endpoint host to the real provider:

  • a known host (api.deepseek.com, openrouter.ai, api.groq.com, NVIDIA NIM, …) resolves to that provider, marked openai-compatible;
  • the canonical OpenAI/Azure endpoint adds no duplicate (the SDK component already represents it);
  • an unknown public host becomes a generic OpenAI-compatible endpoint asset named by its host;
  • a local host (loopback, an IP, localhost, a .local/single-label name) collapses into a single self-hosted LLM endpoint asset (local inference) rather than one component per address.

AWS Bedrock

How Bedrock is reached depends on the language. In Python it has no dedicated SDK — it rides the general boto3 cloud SDK with a bedrock/bedrock-runtime service selector, so xgrep keys on that service signal: boto3.client("bedrock-runtime") is inventoried while boto3.client("s3") is not. In JavaScript/TypeScript (and other languages with a dedicated Bedrock client package — e.g. Java's software.amazon.awssdk.services.bedrockruntime, Go's .../service/bedrockruntime, .NET's Amazon.BedrockRuntime), the import itself is the signal and is matched like any other SDK.

Models

When a call passes a string-literal model id — client.chat.completions.create(model="gpt-4o"), ChatAnthropic(model="claude-3-5-sonnet-20241022") — xgrep promotes it to a machine-learning-model component. Its provider is inferred from the model name (gpt-* → OpenAI, claude-* → Anthropic, gemini-* → Google, …) rather than the call shape, since API shapes like .messages.create and .chat.completions.create are reused across SDKs; a model whose name matches no known provider is inventoried without a provider link rather than misattributed. A model passed as a variable is not turned into an asset (accuracy over recall).

Language coverage

AI-library detection ships for 16 languages:

Python · JavaScript/TypeScript · Java · Kotlin · Scala · Go · C# · Rust · Ruby · PHP · Dart · Swift · Elixir · R · Julia · C/C++

Detection is import/usage-based and precise: a rule matches an AI SDK's import (or, for C/C++, its local-inference header #include) and rejects look-alikes whose name merely shares a prefix. Depth varies with each ecosystem — Python has the widest coverage, including custom-endpoint and model-id detection; C/C++ covers local-inference runtime headers only (there are no managed-provider SDKs for it). Coverage is inherently a moving target as the AI ecosystem grows, so read the absence of a library as "not yet detected," not "no AI present."

Example output

{
  "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "components": [
    {
      "type": "library",
      "bom-ref": "ai/provider/openai",
      "name": "openai",
      "group": "OpenAI",
      "properties": [
        { "name": "aibom:kind", "value": "provider" },
        { "name": "aibom:provider", "value": "OpenAI" },
        { "name": "aibom:hosting", "value": "managed-api" },
      ],
      "evidence": { "occurrences": [{ "location": "app.py", "line": 1 }] },
    },
    {
      "type": "machine-learning-model",
      "bom-ref": "ai/model/gpt-4o",
      "name": "gpt-4o",
      "properties": [
        { "name": "aibom:kind", "value": "model" },
        { "name": "aibom:provider", "value": "OpenAI" },
      ],
    },
  ],
  "dependencies": [{ "ref": "ai/model/gpt-4o", "dependsOn": ["ai/provider/openai"] }],
}

See also

On this page