Skip to main content

bom-v1 — Bill of Materials

The Bill of Materials schema defines a standardized format for construction material takeoffs. It captures line items with quantities, materials, sizes, and provenance metadata.

JSON Schema: spec/schemas/bom-v1.json

Top-Level Fields

FieldTypeRequiredDescription
projectIdstringYesUnique project identifier
revisionstringNoDrawing revision this BOM was generated from
tradestring (enum)YesTrade this BOM covers: mechanical, electrical, plumbing, structural, civil, architectural, fire-protection, general, multi-trade
csiDivisionstringYesPrimary CSI MasterFormat division number
lineItemsarrayYesIndividual material line items (min 1)
metadataobjectYesGeneration metadata

Line Item Fields

FieldTypeRequiredDescription
idstringYesUnique line item identifier
descriptionstringYesHuman-readable material description
quantitynumberYesMeasured quantity
unitstring (enum)YesUnit of measure: EA, LF, SF, CF, CY, TON, LB, GAL, LS
sizestringNoSize specification (e.g., "4 inch")
materialstringNoMaterial type (e.g., "copper", "PVC")
specSectionstringNoSpecification section reference (e.g., "23 21 13")
sourceSheetstringNoDrawing sheet this item was taken from (e.g., "M-201")
locationstringNoLocation within the project (e.g., "Level 2 Wing B")
alternatesarrayNoAcceptable alternate materials

Alternate Fields

FieldTypeDescription
descriptionstringAlternate material description
manufacturerstringManufacturer name
partNumberstringManufacturer part number

Metadata Fields

FieldTypeRequiredDescription
generatedBystringYesAgent ID that generated this BOM
generatedAtstring (date-time)YesTimestamp of generation
confidencenumber (0-1)NoOverall confidence score
sourceDocumentsarrayNoSource document references
flaggedItemsarrayNoItems flagged for human review

Example Payload

{
"projectId": "PRJ-2026-OAKRIDGE-MEDICAL",
"revision": "Rev C",
"trade": "mechanical",
"csiDivision": "23",
"lineItems": [
{
"id": "LI-001",
"description": "Rooftop Unit, 25-ton, high-efficiency",
"quantity": 2,
"unit": "EA",
"size": "25 ton",
"material": "packaged-unit",
"specSection": "23 81 26",
"sourceSheet": "M-101",
"location": "Roof Level",
"alternates": [
{
"description": "Carrier 48HC",
"manufacturer": "Carrier",
"partNumber": "48HC-A28"
}
]
},
{
"id": "LI-002",
"description": "Copper pipe, Type L",
"quantity": 850,
"unit": "LF",
"size": "2 inch",
"material": "copper",
"specSection": "23 21 13",
"sourceSheet": "M-201",
"location": "Level 1-3 Risers"
},
{
"id": "LI-003",
"description": "Butterfly valve, lug style",
"quantity": 24,
"unit": "EA",
"size": "4 inch",
"material": "cast-iron",
"sourceSheet": "M-301"
}
],
"metadata": {
"generatedBy": "pelles-takeoff-agent-v2",
"generatedAt": "2026-02-28T10:30:00Z",
"confidence": 0.92,
"sourceDocuments": [
{
"filename": "Oakridge-Medical-HVAC-Plans.pdf",
"sheetId": "M-101",
"revision": "C"
},
{
"filename": "Oakridge-Medical-HVAC-Plans.pdf",
"sheetId": "M-201",
"revision": "C"
}
],
"flaggedItems": [
{
"lineItemId": "LI-001",
"reason": "Verify tonnage — spec says 20-ton but plan detail shows 25-ton",
"severity": "warning"
}
]
}
}

Python SDK

from taco import BOMV1

# Parse from JSON
bom = BOMV1.model_validate(json_data)

# Access with snake_case
print(bom.project_id) # "PRJ-2026-OAKRIDGE-MEDICAL"
print(bom.line_items[0].size) # "25 ton"
print(bom.metadata.confidence) # 0.92

# Serialize to camelCase JSON
output = bom.model_dump(by_alias=True, exclude_none=True)