SPDX 3.0 AI and Dataset Profiles, With Example
SPDX 3.0 describes an AI model as an AIPackage (AI profile) and each dataset as a DatasetPackage (Dataset profile), serialised as JSON-LD in one @graph and linked by Relationship elements: trainedOn and testedOn from the model to its data, descendantOf to the base model, dependsOn for run-time parts. The current version is 3.0.1. This guide explains every AI and Dataset property against one schema- and SHACL-valid example for a fictional support assistant, shows the gaps you hit (no service class, no signature reference type, dataset size in bytes), and says when to choose SPDX over CycloneDX.
SPDX 3.0 describes an AI model as an AIPackage from the AI profile and each dataset as a DatasetPackage from the Dataset profile. Both are software packages, so they carry the usual name, version, supplier and download location. They are joined by separate Relationship elements: trainedOn and testedOn from the model to its data, descendantOf to the base model. The current version is 3.0.1.
Who this is for: AppSec engineers whose SBOM pipeline already speaks SPDX and now has to cover models, and GRC teams who receive SPDX files as evidence and need to know what each AI field claims. For the general idea, start with what an AIBOM is; for a format-neutral field list, see the AIBOM parameters checklist.
Fictional example. Northwind Health, Triage Assistant and its datasets, services, scores and URLs are invented for illustration; the base model and open-source libraries are real.
How an SPDX 3.0 AIBOM is laid out
An SPDX 3.0 file in JSON-LD is one @context and one flat @graph of elements. Five things to know before reading one:
- Everything is an element with an
spdxId, a URI. Northwind useshttps://northwind-health.example/spdx/triage-assistant-2.3.0#…. - One shared
CreationInfosays who produced the data and when (spec version3.0.1). Every element points at it. - Profiles are declared. The
SpdxDocumentlistsprofileConformance:core,software,ai,datasetandsimpleLicensingfor Northwind. - Property names carry the profile as a prefix in JSON-LD:
ai_limitation,dataset_datasetType,software_packageVersion. Core properties such asnamehave none. - Links are elements too. “The model was trained on this dataset” is a
Relationshipnode withfrom,relationshipTypeandto, not a field inside the model. Licences work the same way, throughhasDeclaredLicense.
If you know SPDX 2.x, note that 3.0 is a new model, not an extension of 2.x documents. Tools written for 2.x will not read it.
AIPackage: the AI profile
An AIPackage must have the six package properties in the first rows. Every ai_ property is optional. Cardinality is from the SPDX 3.0.1 class page.
| Property | Cardinality | What it records | Northwind |
|---|---|---|---|
name, software_packageVersion | 1 each | Model identity | northwind/triage-assistant, 2.3.0 |
software_downloadLocation | 1 | Where the weights are | Internal model store URL |
software_primaryPurpose | 1 | What kind of package this is | model |
suppliedBy, releaseTime | 1 each | Accountable supplier and release date | Northwind Health, 2026-02-16 |
ai_typeOfModel | 0..* | Free-text model type | decoder-only transformer (causal language model) |
ai_domain | 0..* | Where the model is meant to be used | customer support |
ai_informationAboutTraining | 0..1 | How it was trained, in words | LoRA fine-tune on the ticket dataset |
ai_informationAboutApplication | 0..1 | Intended application | Drafts for human approval |
ai_limitation | 0..1 | Known limits and out-of-scope uses, as one string | Medical advice; sending without approval |
ai_metric, ai_metricDecisionThreshold | 0..* each | Metric results, and thresholds, as key/value DictionaryEntry pairs | answer-accuracy 0.87; toxicity-rate 0.002 (fictional). No thresholds. |
ai_hyperparameter | 0..* | Training settings as key/value pairs | finetuning_method = LoRA; task |
ai_modelDataPreprocessing | 0..* | Data preparation before training | De-identification |
ai_autonomyType | 0..1 | Whether it acts without a human in the loop: yes, no, noAssertion | no |
ai_safetyRiskAssessment | 0..1 | Self-assessed risk: serious, high, medium, low | medium |
ai_useSensitivePersonalInformation | 0..1 | Whether sensitive personal data was used | no |
ai_modelExplainability, ai_standardCompliance, ai_energyConsumption | 0..* / 0..* / 0..1 | Explainability notes, standards complied with, energy used in training, fine-tuning and inference | Not recorded |
Two of these are judgements, not facts. ai_safetyRiskAssessment is the supplier’s own rating on a four-level scale, and ai_useSensitivePersonalInformation is the supplier’s claim after its own de-identification. Read both as claims to test.
DatasetPackage: the Dataset profile
A DatasetPackage must have at least one dataset_datasetType, plus builtTime, releaseTime, originatedBy, a download location and a primary purpose (data).
| Property | Cardinality | What it records | Northwind training set |
|---|---|---|---|
dataset_datasetType | 1..* | text, image, audio, structured and ten more | text |
builtTime, releaseTime, originatedBy | 1 each (originatedBy at most 1) | When the data was built and released, and who created it | 2025-12-31, 2026-01-20, Northwind Health |
dataset_dataCollectionProcess | 0..1 | How the data was collected | Export from the ticketing system |
dataset_dataPreprocessing | 0..* | Steps between raw data and training data | Dropped no-reply tickets; de-identified |
dataset_anonymizationMethodUsed | 0..* | How identifiers were removed | NER plus pattern rules, sample review |
dataset_hasSensitivePersonalInformation | 0..1 | yes, no, noAssertion | no |
dataset_confidentialityLevel | 0..1 | Traffic Light Protocol style: clear, green, amber, red | amber |
dataset_intendedUse, dataset_knownBias | 0..1 / 0..* | What the data is for, and known biases | Fine-tuning the model; written channels only |
dataset_datasetUpdateMechanism | 0..1 | How the data is updated | None: static 2025 snapshot |
dataset_datasetSize | 0..1 | Size in bytes (not records) | Left out; record count is in the description |
dataset_datasetAvailability, dataset_datasetNoise, dataset_sensor | 0..1 / 0..1 / 0..* | How it can be obtained, known noise, sensors used | Not recorded (internal text data) |
Relationships that make it an AIBOM
describes: the SBOM element describes the application.dependsOn: the application depends on the model, vLLM 0.6.3, the RAG index and the MCP server; vLLM depends on its libraries.descendantOf: the fine-tune is a descendant ofmistralai/Mistral-7B-Instruct-v0.3.trainedOnandtestedOn: the model was trained onnorthwind/support-tickets-2025and tested onnorthwind/triage-eval-v4. The direction is always from the model to the data.hasDeclaredLicense: each package to asimplelicensing_LicenseExpressionelement. The base model getsApache-2.0; Northwind’s own model and data get aLicenseRef-identifier mapped to a licence URL.
The Northwind field table
| Field | Northwind value | What it tells you |
|---|---|---|
@context | https://spdx.org/rdf/3.0.1/spdx-context.jsonld | Declares SPDX 3.0.1 JSON-LD. Every node lives in one @graph. |
CreationInfo (specVersion, created, createdBy) | 3.0.1, 2026-02-16T09:00:00Z, Northwind Health | Who produced the SPDX data and when. Shared by every element. |
SpdxDocument.profileConformance | core, software, ai, dataset, simpleLicensing | Which SPDX profiles the document uses. "ai" and "dataset" are the AIBOM parts. |
software_Sbom.software_sbomType | build | Generated at build time. |
ai_AIPackage name / software_packageVersion | northwind/triage-assistant / 2.3.0 | Model identity. AIPackage requires name, version, download location, supplier, release time and primary purpose. |
software_primaryPurpose | model | Says this package is a model (datasets use "data"). |
suppliedBy / releaseTime | Northwind Health / 2026-02-16T09:00:00Z | Accountable supplier and release date. |
verifiedUsing (Hash sha256) | 3bad18cc9805… (placeholder) | Integrity check of the weights file. |
ai_typeOfModel / ai_domain | decoder-only transformer / customer support | Free-text model type and the domain it is meant for. |
ai_informationAboutTraining | LoRA fine-tune on northwind/support-tickets-2025 | How the model was trained, in words. |
ai_informationAboutApplication | Draft replies to customer support tickets for a human support agent to review, edit and approve before sending. | Intended application. |
ai_limitation | Medical advice or clinical triage of symptoms; Sending any reply to a customer without human approval | Known limitations and out-of-scope uses. One string in SPDX 3.0.1. |
ai_metric (DictionaryEntry) | answer-accuracy 0.87; toxicity-rate 0.002 (fictional) | Metric name and value as key/value pairs. |
ai_hyperparameter | finetuning_method = LoRA; task = text-generation | Training settings worth recording. |
ai_autonomyType | no | No: a human approves every output before it has effect. |
ai_safetyRiskAssessment | medium | Northwind Health's own risk rating on SPDX's four-level scale (serious, high, medium, low). Fictional. |
ai_useSensitivePersonalInformation | no | Publisher asserts no sensitive personal data was used in training, after de-identification. |
dataset_DatasetPackage (training) | northwind/support-tickets-2025, datasetType text, confidentialityLevel amber | The training data as its own element. datasetType is the one Dataset-profile field that is required. |
dataset_anonymizationMethodUsed / dataset_hasSensitivePersonalInformation | NER plus pattern rules, sample review / no | How identifiers were removed, and the resulting claim. De-identified is not the same as anonymous. |
dataset_datasetSize | (omitted) | Size in bytes, not records. The record count (48,210) goes in the description. |
Relationship descendantOf | triage-assistant → mistralai/Mistral-7B-Instruct-v0.3 | Lineage to the base model. |
Relationship trainedOn / testedOn | northwind/support-tickets-2025 / northwind/triage-eval-v4 | Which data trained the model and which tested it. |
Relationship dependsOn | Triage Assistant → model, vllm 0.6.3, northwind-helpcentre-index, ticketing-mcp | Run-time dependencies. SPDX 3.0.1 has no service class, so the RAG index is a dataset and the MCP server a package. |
Relationship hasDeclaredLicense | Apache-2.0 (base model); LicenseRef proprietary (model, data) | Licences, as simplelicensing_LicenseExpression elements. |
externalRef (model) | documentation (model card); other: Sigstore bundle; other: in-toto provenance | Links to the signature and provenance. SPDX 3.0.1 has no dedicated signature or SLSA ref type, so these use "other" with a contentType. |
The example file, excerpted
The model with its signature link, the training dataset, and the two relationships that say where the model came from and what it learned from.
{
"@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
"@graph": [
{
"type": "ai_AIPackage",
"spdxId": "https://northwind-health.example/spdx/triage-assistant-2.3.0#model",
"name": "northwind/triage-assistant",
"software_packageVersion": "2.3.0",
"software_primaryPurpose": "model",
"suppliedBy": "https://northwind-health.example/spdx/triage-assistant-2.3.0#org-northwind-health",
"releaseTime": "2026-02-16T09:00:00Z",
"ai_typeOfModel": ["decoder-only transformer (causal language model)"],
"ai_limitation": "Out of scope: Medical advice or clinical triage of symptoms; Sending any reply to a customer without human approval.",
"ai_autonomyType": "no",
"ai_safetyRiskAssessment": "medium",
"ai_useSensitivePersonalInformation": "no",
"externalRef": [
{
"type": "ExternalRef",
"externalRefType": "other",
"locator": [
"https://models.northwind-health.example/northwind/triage-assistant/2.3.0/model.sig"
],
"contentType": "application/vnd.dev.sigstore.bundle.v0.3+json",
"comment": "Sigstore model signature (OpenSSF model signing), produced in CI."
}
]
},
{
"type": "dataset_DatasetPackage",
"spdxId": "https://northwind-health.example/spdx/triage-assistant-2.3.0#dataset-support-tickets-2025",
"name": "northwind/support-tickets-2025",
"builtTime": "2025-12-31T23:59:59Z",
"originatedBy": [
"https://northwind-health.example/spdx/triage-assistant-2.3.0#org-northwind-health"
],
"dataset_datasetType": ["text"],
"dataset_anonymizationMethodUsed": [
"Named-entity detection plus pattern rules to remove names, email addresses, phone numbers, postal addresses and account or member numbers; manual review of a sample."
],
"dataset_confidentialityLevel": "amber",
"dataset_hasSensitivePersonalInformation": "no"
},
{
"type": "Relationship",
"from": "https://northwind-health.example/spdx/triage-assistant-2.3.0#model",
"relationshipType": "descendantOf",
"to": ["https://northwind-health.example/spdx/triage-assistant-2.3.0#base-model"]
},
{
"type": "Relationship",
"from": "https://northwind-health.example/spdx/triage-assistant-2.3.0#model",
"relationshipType": "trainedOn",
"to": [
"https://northwind-health.example/spdx/triage-assistant-2.3.0#dataset-support-tickets-2025"
]
}
]
}
Excerpt, 59 lines: the AIPackage (metrics and two of its three external references left out), the training DatasetPackage, and the descendantOf and trainedOn relationships. Keys and list entries not shown are left out; every value shown is exactly as in the full file, which runs to 608 lines pretty-printed.
The complete file, with the application, the base model, the evaluation set, the RAG index, the MCP server, the libraries, the licences and every relationship, is in the AIBOM Template Library (Pro).
Gaps we hit, and what we did
Building the Northwind file in SPDX 3.0.1 ran into five places where the model has no field for something an AI system needs. None makes the file invalid. All of them push facts into free text.
| Gap | Why | What the Northwind file does |
|---|---|---|
| No service class | CycloneDX has services for things called at run time. SPDX 3.0.1 does not. | The RAG index is a dataset_DatasetPackage with software_primaryPurpose: data and a weekly update mechanism; the MCP server is a software_Package with primaryPurpose: application. Authentication, trust boundary and tool permissions go into the description, where tools cannot query them. |
| No reference type for a model signature or SLSA provenance | ExternalRefType has 46 values but none for a signature bundle or build provenance. secureSoftwareAttestation exists, but it means an SSDF or CISA secure-development attestation form. | Both links use externalRefType: other with a contentType: application/vnd.dev.sigstore.bundle.v0.3+json for the signature and application/vnd.in-toto+json for the provenance, plus a comment. |
| datasetSize is bytes | The spec says the size “is to be measured in bytes”. Writing 48210 there would claim a 48 KB dataset. | dataset_datasetSize is left out; “48,210 de-identified support tickets” goes in the description. |
| ai_limitation holds one string | Maximum cardinality is 1. | The two out-of-scope uses are joined into one sentence. |
| Metrics have no slice | ai_metric is a key/value pair; there is no slot for the dataset a metric was measured on. | The dataset goes into the key (answer-accuracy (northwind/triage-eval-v4)), and a testedOn relationship links the model to the evaluation set. |
SPDX or CycloneDX?
Neither is better in general. Pick by what you need to express and who reads it.
| If… | Choose | Why |
|---|---|---|
| Your SBOM pipeline and your customers already use SPDX | SPDX | The AIBOM should come out of the same pipeline as the SBOM. |
| You need to show RAG indexes, tool servers and trust boundaries | CycloneDX | CycloneDX has services with endpoints, authentication, trust boundary and data flows. SPDX 3.0.1 has no service class. |
| Dataset facts matter most (anonymisation, confidentiality, bias, collection) | SPDX | The Dataset profile has named fields for these. CycloneDX data components have classification and sensitive-data notes only. |
| You want a structured model card inside the BOM | CycloneDX | modelCard has separate lists for use cases, limitations, trade-offs, ethical, environmental and fairness considerations. SPDX has free-text strings. |
| Licence compliance is the main use | SPDX | Licence expressions are first-class elements, linked by hasDeclaredLicense. |
| You need autonomy, safety-risk or energy fields | SPDX | autonomyType, safetyRiskAssessment and energyConsumption have no direct CycloneDX equivalent. |
| You want PlayCISO’s validator and diff | CycloneDX | The AIBOM Validator and AIBOM Diff read CycloneDX. |
The CycloneDX ML-BOM guide uses the same Northwind system, so you can compare the two files field by field. The AIBOM Format Field Map (Pro) does that comparison for every field. For how the three bill-of-materials ideas differ, see SBOM vs AIBOM vs MLBOM.
How to validate it
- Structure: the official SPDX 3.0.1 JSON schema checks that the JSON-LD has the right shape.
- Meaning: the SHACL shapes in the SPDX model file (
spdx-model.ttl) check required properties, cardinalities and enumerated values, for example with pySHACL. This is what catches a DatasetPackage without adatasetType. - Both at once: the community tool
spdx3-validateruns the schema and SHACL checks together, with some extra checks for documents that reference each other.
The Northwind file passes the official SPDX 3.0.1 JSON schema and the SHACL shapes (checked with pySHACL). As with any format, valid only means well-formed. The facts inside, such as the de-identification claim, still need evidence.
Where to go next
This guide is part of the AIBOM Library. The same Northwind system in the other formats: CycloneDX ML-BOM and Croissant RAI. To choose between formats, start with AIBOM standards and templates compared; to see one field across every format, use the AIBOM Format Field Map (Pro).
Frequently asked questions
What is the SPDX AI profile?
The part of SPDX 3.0 that describes AI models. It adds the AIPackage class, a software package with properties such as typeOfModel, informationAboutTraining, informationAboutApplication, limitation, metric, hyperparameter, autonomyType, safetyRiskAssessment, useSensitivePersonalInformation and energyConsumption. The Dataset profile adds DatasetPackage for training and test data.
What fields does an SPDX AIPackage require?
In SPDX 3.0.1 every AIPackage needs a name, packageVersion, downloadLocation, primaryPurpose, suppliedBy and releaseTime, plus the spdxId and creationInfo every element has. All the ai_ properties are optional. A DatasetPackage needs datasetType, builtTime, releaseTime, originatedBy, downloadLocation and primaryPurpose.
How do you link a model to its training data in SPDX 3.0?
With Relationship elements. A relationship from the model to a dataset with relationshipType trainedOn says the model was trained on it; testedOn says it was tested on it; descendantOf from the fine-tune to the base model records lineage. Relationships are separate nodes in the @graph, not properties nested inside the model.
Can SPDX 3.0 describe a RAG pipeline or an MCP server?
Only partly. SPDX 3.0.1 has no class for a service called at run time. You can model a retrieval index as a DatasetPackage and a tool server as a software Package, linked with dependsOn, but authentication, trust boundaries and tool permissions end up in free text. CycloneDX services hold them as fields.
Is SPDX 3.0 an ISO standard?
No. ISO/IEC 5962:2021 is SPDX 2.2.1. The AI and Dataset profiles are new in SPDX 3.0, so they are not part of that ISO text. The current SPDX version is 3.0.1; SPDX 3.1 was at release-candidate stage in October 2026.
Should I use SPDX or CycloneDX for an AIBOM?
Use the format your SBOM pipeline and your customers already use. Choose CycloneDX if you need run-time services with trust boundaries or a structured model card. Choose SPDX if your focus is licence compliance or detailed dataset facts such as anonymisation method and confidentiality level. You can produce both from one source.
Sources
- SPDX 3.0.1: AIPackage
- SPDX 3.0.1: DatasetPackage
- SPDX 3.0.1: RelationshipType (trainedOn, testedOn, descendantOf)
- SPDX 3.0.1: ExternalRefType
- SPDX 3.0.1: datasetSize (“measured in bytes”)
- SPDX 3.0.1 JSON schema
- spdx3-validate (JSON schema plus SHACL checks for SPDX 3)
- SPDX 3.1 release candidate 1
- Mistral-7B-Instruct-v0.3 on Hugging Face (the real base model in the example)
Checked on 29 October 2026. PlayCISO is not affiliated with OWASP, Ecma, the Linux Foundation or MLCommons. This is general information, not legal advice.
Ready to practise the decisions these articles describe?
Run your first War Room free →One run free with a free account · more runs with Pro