Dependencies

Generating an AIBOM

Produce a CycloneDX 1.6 AI Bill of Materials with xgrep sbom --include 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 --include 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 --include aibom .

The path is optional — xgrep sbom --include aibom with no path scans the current directory, just like xgrep scan.

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 --include aibom --output aibom.cdx.json .

--include aibom selects the AI-inventory bill of materials on its own — it emits AI assets only, with no software dependencies. To get the AI inventory and your dependencies (and optionally cryptographic assets) as one merged CycloneDX document, list them together:

xgrep sbom --include sca,aibom --output bom.cdx.json .

See Combined bills of materials for the full content grid. 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.

The older xgrep sbom --aibom flag still works as a deprecated alias for --include aibom, and is slated for removal in v0.3.0.

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
observabilityan LLM tracing / observability / eval platformLangSmith, Langfuse, Arize Phoenix, TruLens
guardrailsan LLM guardrail / safety I-O-validation libraryGuardrails AI, NeMo Guardrails, LLM Guard, LlamaFirewall
evaluationan LLM evaluation / testing frameworkRagas, DeepEval, Braintrust, Patronus AI, Inspect AI
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.

Observability & tracing platforms

The observability kind inventories the LLM tracing / observability / evaluation platforms a codebase integrates — LangSmith, Langfuse, and Arize Phoenix (Python and JavaScript/TypeScript), plus Arize AX and TruLens (Python only, the languages with a first-party SDK). A traced application ships its prompts and completions to that third-party service, so its presence is a supply-chain and data-egress signal — a governance team can filter to aibom:kind=observability to see which external services receive model inputs and outputs. Detection is import-based and anchored precisely (for example, the phoenix import for Arize Phoenix is matched so the unrelated Apache phoenixdb driver is not). Tools enabled only through environment variables (LangSmith auto-tracing when LangChain is present) or a proxy/config (Helicone, promptfoo) are not import-detectable and are a documented gap.

Guardrail & safety tooling

The guardrails kind inventories the LLM guardrail / safety libraries an application uses to defend its model inputs and outputs — prompt-injection and jailbreak detection, PII redaction, content moderation, output validation. This is the inverse of the observability signal: filter to aibom:kind=guardrails to see whether — and with what — an LLM app validates its I/O. Detected today: Guardrails AI, NeMo Guardrails, LLM Guard, LlamaFirewall, and the legacy Rebuff (Python; Rebuff also JS/TS), plus OpenAI Guardrails (JavaScript/TypeScript). Detection is import-based. General-purpose tools that merely get used near an LLM (e.g. Microsoft Presidio for PII) are excluded, since an import alone is not a reliable guardrail signal; API-only services (Lakera) and models rather than libraries (Llama Guard) are out of scope.

Evaluation & testing frameworks

The evaluation kind inventories the LLM evaluation / testing frameworks an application uses to score or test model output — RAG and answer-quality metrics, faithfulness checks, pytest-style assertions, model-graded evals. It's the quality-assurance member of the AI-ops trio (alongside observability and guardrails): filter to aibom:kind=evaluation to see whether — and with what — an app's output quality is tested. Detected today: Ragas, DeepEval, Braintrust, Patronus AI (Python; DeepEval, Braintrust, and Patronus also JavaScript/TypeScript) and Inspect AI (Python). Detection is import-based; general-purpose ML tooling (Evidently, DeepChecks, HuggingFace evaluate) and config/CLI-only tools (promptfoo) are excluded, since an import alone is not a reliable LLM-evaluation signal.

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, pkg:maven/com.openai/openai-java@0.31.0), so the inventory can be matched against advisory feeds. Versions are read offline from each ecosystem's manifests and lockfiles — package.json and npm lockfiles, go.mod, requirements.txt and the Python lockfiles, Cargo.lock, Gemfile.lock, composer.lock, pubspec.lock, Maven/Gradle (pom.xml), NuGet (packages.lock.json/packages.config), mix.lock, Package.resolved, conan.lock, Manifest.toml, and renv.lock — covering every language xgrep detects AI libraries in.

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. This is not limited to chat: embedding, image, and audio model calls (embeddings.create(model="text-embedding-3-small"), images.generate(model="dall-e-3"), audio.speech.create(model="tts-1"), audio.transcriptions.create(model="whisper-1")) are captured the same way, so an inventory reflects the full set of models a codebase requests, not just chat ones. 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).

Model-id capture is available for Python, JavaScript/TypeScript, Go, Java, Kotlin, C#, Rust, Ruby, and PHP. Where a language's SDK sets the model on an AI-specific call node (a params struct, a ModelId("…") wrapper, a new ChatClient(model: …)), any string-literal model is captured. Where it is set by a generic builder method deep in a chain (.model("…") / .modelName("…")), capture is limited to string-literal model ids whose name is a recognized AI model, so an unrelated .model("users") is never mistaken for a model asset. Model ids given as SDK enum constants rather than strings are not captured.

AWS Bedrock invocations are captured too (Python, JavaScript/TypeScript, Go, Java, and C#): the model id passed to an InvokeModel or Converse call — for example boto3's client.invoke_model(modelId="anthropic.claude-3-5-sonnet-20240620-v1:0") or new InvokeModelCommand({ modelId: "amazon.titan-text-express-v1" }) — is promoted to a model component and attributed to AWS Bedrock, the provider that serves it. Cross-region inference-profile ids (us.anthropic.claude-…) are recognized as well.

Google Gemini / Vertex AI models are captured too (Python, JavaScript/TypeScript, Go, and Java), across Google's overlapping SDKs — the unified google-genai (models.generate_content(model="gemini-2.5-flash") / generateContent({ model })), the legacy google-generativeai and Vertex vertexai (GenerativeModel("gemini-1.5-pro")), and the LangChain adapters (ChatGoogleGenerativeAI / ChatVertexAI). The model resolves by name to Google Gemini; a models/-prefixed id (models/gemini-1.5-pro) is recognized too.

Mistral AI (Python, JavaScript/TypeScript) and Cohere (Python, JavaScript/TypeScript, Go) native SDKs are covered as well — Mistral's chat.complete("mistral-large-latest") / fim.complete("codestral-latest") and Cohere's chat / embed / rerank calls (command-*, embed-*, rerank-*). Mistral's open-mistral-* / open-mixtral-* open-weight models are attributed too.

Embedding / reranking specialists — Voyage AI, Nomic, and Mixedbread (Python, JavaScript/TypeScript) — are inventoried as providers, together with the embedding models they call (embed(model="voyage-3.5"), nomic-embed-text-v1.5, mixedbread-ai/mxbai-embed-large-v1). These managed embedding + reranker APIs are a common RAG building block.

Anthropic (Claude) model capture spans the native SDKs beyond Python/JS/Go — the Ruby anthropic gem (client.messages.create(model: "claude-…")), the Kotlin anthropic-java builder (.model("claude-…")), and the .NET Anthropic.SDK (new MessageParameters { Model = "claude-…" }). Model ids given as SDK constants (AnthropicModels.…, Model.CLAUDE_*) are not captured.

Local / open models are captured too (Python, JavaScript/TypeScript): the model a codebase runs through a self-hosted runtime — Hugging Face Transformers (AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B"), pipeline(model="…")), SentenceTransformer("all-MiniLM-L6-v2"), vLLM LLM(model="…"), and Ollama ollama.chat(model="llama3.1"). An open model has no single managed provider, so it is listed as a model with no provider link (unless its name matches a known provider); tokenizer/config loads are not mistaken for models.

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; custom-endpoint detection ships for Python, JavaScript/TypeScript, Go, Kotlin, C#, Rust, Ruby, and PHP, and model-id capture ships for Python, JavaScript/TypeScript, Go, Java, Kotlin, C#, Rust, Ruby, and PHP; 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