MCPInstall

bim-cost-estimation-cwicr

Automated cost estimation from BIM models using DDC CWICR database (8 national bases, 78,228 positions). AI classification + vector search for accurate pricing.

Installs
133
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction --skill bim-cost-estimation-cwicr
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads bim-cost-estimation-cwicr automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

BIM Cost Estimation with DDC CWICR

Generate accurate cost estimates from BIM models using AI classification and the DDC CWICR construction cost database.

Business Case

Problem: Traditional cost estimation:

  • Manual and time-consuming (weeks for detailed estimate)
  • Subjective and inconsistent between estimators
  • Requires specialized knowledge
  • Difficult to update with design changes

Solution: Automated BIM-to-cost pipeline:

  • Extract quantities directly from model
  • AI classifies elements to work items
  • Vector search finds matching prices in CWICR
  • Complete estimate in hours, not weeks

ROI: 80% reduction in estimation time, consistent methodology

System Architecture

┌──────────────────────────────────────────────────────────────────────────┐
│                  BIM TO COST ESTIMATION PIPELINE                          │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                           │
│   ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────────────┐   │
│   │ BIM     │     │ DDC     │     │ AI      │     │ DDC CWICR       │   │
│   │ Model   │────►│Converter│────►│ LLM     │────►│ Vector Search   │   │
│   │.rvt/.ifc│     │         │     │         │     │ (Qdrant)        │   │
│   └─────────┘     └─────────┘     └─────────┘     └─────────────────┘   │
│                        │              │                    │             │
│                        ▼              ▼                    ▼             │
│                   ┌─────────┐    ┌─────────┐         ┌──────────┐       │
│                   │ .xlsx   │    │ Work    │         │ Matched  │       │
│                   │ QTO     │    │ Items   │         │ Rates    │       │
│                   └─────────┘    └─────────┘         └──────────┘       │
│                        │              │                    │             │
│                        └──────────────┼────────────────────┘             │
│                                       ▼                                  │
│                              ┌─────────────────┐                        │
│                              │ COST ESTIMATE   │                        │
│                              │                 │                        │
│                              │ • By element    │                        │
│                              │ • By trade      │                        │
│                              │ • By phase      │                        │
│                              │ • Resources     │                        │
│                              └─────────────────┘                        │
│                                                                           │
└──────────────────────────────────────────────────────────────────────────┘

DDC CWICR Database

Database Overview:
  work_items: 78228  # 8 national bases
  resources: 27,672
  languages: 9 (AR, DE, EN, ES, FR, HI, PT, RU, ZH)
  fields_per_item: 85
  embedding_model: BAAI/bge-m3 (1024d)
  vector_db: Qdrant

Collections:
  - ddc_cwicr_ar  # Arabic (Dubai prices)
  - ddc_cwicr_de  # German (Berlin prices)
  - cwicr_en_v3  # English (Toronto prices)
  - ddc_cwicr_es  # Spanish (Barcelona prices)
  - ddc_cwicr_fr  # French (Paris prices)
  - ddc_cwicr_hi  # Hindi (Mumbai prices)
  - ddc_cwicr_pt  # Portuguese (São Paulo prices)
  - ddc_cwicr_ru  # Russian (St. Petersburg prices)
  - ddc_cwicr_zh  # Chinese (Shanghai prices)

Pipeline Stages

StageNameDescription
0Collect BIM DataExtract elements from Revit/IFC
1Project DetectionAI identifies project type
2Phase GenerationAI creates construction phases
3Element AssignmentAI maps types to phases
4Work DecompositionAI breaks types into work items
5Vector SearchFind matching rates in CWICR
6Unit MappingConvert BIM units to rate units
7Cost CalculationQty × Unit Price
7.5ValidationCTO review for completeness
8AggregationSum by phases and categories
9Report GenerationHTML and Excel outputs

Python Implementation

import pandas as pd
import numpy as np
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue
from openai import OpenAI
from typing import List, Dict, Optional
from dataclasses import dataclass
import json

@dataclass
class WorkItem:
    """Matched work item from CWICR"""
    cwicr_code: str
    description: str
    unit: str
    unit_price: float
    labor_cost: float
    material_cost: float
    equipment_cost: float
    productivity: float  # units per hour
    currency: str
    confidence: float

@dataclass
class CostLineItem:
    """Single line item in estimate"""
    bim_type: str
    work_item: WorkItem
    quantity: float
    quantity_unit: str
    total_cost: float
    labor_cost: float
    material_cost: float
    equipment_cost: float
    phase: str
    trade: str


class BIMCostEstimator:
    """BIM to cost estimation using DDC CWICR"""

    def __init__(
        self,
        qdrant_url: str,
        qdrant_api_key: str = None,
        openai_api_key: str = None,
        language: str = "EN"
    ):
        self.qdrant = QdrantClient(url=qdrant_url, api_key=qdrant_api_key)
        self.openai = OpenAI(api_key=openai_api_key)
        self.language = language
        self.collection = f"ddc_cwicr_{language.lower()}"

    def get_embedding(self, text: str) -> List[float]:
        """Generate embedding for text"""
        response = self.openai.embeddings.create(
            model="BAAI/bge-m3",
            input=text,
            dimensions=1024
        )
        return response.data[0].embedding

    def search_cwicr(
        self,
        query: str,
        limit: int = 5,
        category_filter: str = None
    ) -> List[WorkItem]:
        """Search CWICR database for matching work items"""

        # Get embedding
        query_vector = self.get_embedding(query)

        # Build filter if category specified
        query_filter = None
        if category_filter:
            query_filter = Filter(
                must=[
                    FieldCondition(
                        key="category",
                        match=MatchValue(value=category_filter)
                    )
                ]
            )

        # Search
        results = self.qdrant.search(
            collection_name=self.collection,
            query_vector=query_vector,
            query_filter=query_filter,
            limit=limit
        )

        # Parse results
        work_items = []
        for r in results:
            payload = r.payload
            work_items.append(WorkItem(
                cwicr_code=payload.get('code', ''),
                description=payload.get('description', ''),
                unit=payload.get('unit', ''),
                unit_price=float(payload.get('unit_price', 0)),
                labor_cost=float(payload.get('labor_cost', 0)),
                material_cost=float(payload.get('material_cost', 0)),
                equipment_cost=float(payload.get('equipment_cost', 0)),
                productivity=float(payload.get('productivity', 1)),
                currency=payload.get('currency', 'USD'),
                confidence=r.score
            ))

        return work_items

    def decompose_bim_type(
        self,
        bim_type: str,
        category: str
    ) -> List[str]:
        """Use LLM to decompose BIM type into work items"""

        prompt = f"""
Decompose this BIM element type into construction work items:

BIM Type: {bim_type}
Category: {category}

List the individual work activities needed to construct this element.
For example, "Brick Wall 240mm" decomposes into:
- Masonry: Brick laying
- Mortar: Cement mortar for joints
- Plaster: Internal plaster finish
- Paint: Wall painting

Return a JSON array of work item descriptions.
Example: ["Brick masonry laying", "Cement mortar for brick joints", "Internal cement plaster 15mm"]
"""

        response = self.openai.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": prompt}],
            response_format={"type": "json_object"}
        )

        try:
            result = json.loads(response.choices[0].message.content)
            return result.get('work_items', [bim_type])
        except:
            return [bim_type]

    def estimate_element(
        self,
        bim_type: str,
        category: str,
        quantity: float,
        quantity_unit: str,
        phase: str = "Construction"
    ) -> List[CostLineItem]:
        """Estimate cost for single BIM element type"""

        # Decompose into work items
        work_descriptions = self.decompose_bim_type(bim_type, category)

        line_items = []

        for work_desc in work_descriptions:
            # Search CWICR for matching rate
            matches = self.search_cwicr(work_desc, limit=1)

            if not matches:
                continue

            best_match = matches[0]

            # Convert quantity if units don't match
            adjusted_qty = self._convert_units(
                quantity, quantity_unit, best_match.unit
            )

            # Calculate costs
            total = adjusted_qty * best_match.unit_price
            labor = adjusted_qty * best_match.labor_cost
            material = adjusted_qty * best_match.material_cost
            equipment = adjusted_qty * best_match.equipment_cost

            line_items.append(CostLineItem(
                bim_type=bim_type,
                work_item=best_match,
                quantity=adjusted_qty,
                quantity_unit=best_match.unit,
                total_cost=total,
                labor_cost=labor,
                material_cost=material,
                equipment_cost=equipment,
                phase=phase,
                trade=self._get_trade(category)
            ))

        return line_items

    def estimate_from_qto(
        self,
        qto_data: pd.DataFrame,
        type_column: str = "Type Name",
        category_column: str = "Category",
        quantity_column: str = "Volume"
    ) -> List[CostLineItem]:
        """Generate estimate from QTO DataFrame"""

        all_line_items = []

        # Group by type
        grouped = qto_data.groupby([category_column, type_column]).agg({
            quantity_column: 'sum'
        }).reset_index()

        for _, row in grouped.iterrows():
            items = self.estimate_element(
                bim_type=row[type_column],
                category=row[category_column],
                quantity=row[quantity_column],
                quantity_unit="m³"  # Assume volume, adjust based on category
            )
            all_line_items.extend(items)

        return all_line_items

    def _convert_units(
        self,
        value: float,
        from_unit: str,
        to_unit: str
    ) -> float:
        """Convert between units"""

        # Simplified conversion - expand as needed
        conversions = {
            ('m³', 'm³'): 1.0,
            ('m²', 'm²'): 1.0,
            ('m', 'm'): 1.0,
            ('ft³', 'm³'): 0.0283168,
            ('ft²', 'm²'): 0.092903,
            ('ft', 'm'): 0.3048,
        }

        key = (from_unit.lower(), to_unit.lower())
        factor = conversions.get(key, 1.0)

        return value * factor

    def _get_trade(self, category: str) -> str:
        """Map BIM category to trade"""
        trade_map = {
            'Walls': 'Masonry',
            'Floors': 'Concrete',
            'Structural Columns': 'Concrete',
            'Structural Framing': 'Steel',
            'Doors': 'Carpentry',
            'Windows': 'Glazing',
            'Plumbing Fixtures': 'Plumbing',
            'Electrical Equipment': 'Electrical',
            'Mechanical Equipment': 'HVAC'
        }
        return trade_map.get(category, 'General')

    def generate_estimate_report(
        self,
        line_items: List[CostLineItem],
        project_name: str,
        output_path: str
    ) -> dict:
        """Generate comprehensive estimate report"""

        # Convert to DataFrame
        records = []
        for item in line_items:
            records.append({
                'BIM Type': item.bim_type,
                'Work Item': item.work_item.description,
                'CWICR Code': item.work_item.cwicr_code,
                'Quantity': round(item.quantity, 2),
                'Unit': item.quantity_unit,
                'Unit Price': round(item.work_item.unit_price, 2),
                'Labor': round(item.labor_cost, 2),
                'Material': round(item.material_cost, 2),
                'Equipment': round(item.equipment_cost, 2),
                'Total': round(item.total_cost, 2),
                'Phase': item.phase,
                'Trade': item.trade,
                'Currency': item.work_item.currency,
                'Confidence': round(item.work_item.confidence, 2)
            })

        df = pd.DataFrame(records)

        # Calculate totals
        total_cost = df['Total'].sum()
        total_labor = df['Labor'].sum()
        total_material = df['Material'].sum()
        total_equipment = df['Equipment'].sum()

        # Summary by trade
        by_trade = df.groupby('Trade')['Total'].sum().sort_values(ascending=False)

        # Write Excel
        excel_path = f"{output_path}/{project_name}_Estimate.xlsx"
        with pd.ExcelWriter(excel_path, engine='openpyxl') as writer:
            # Summary sheet
            summary_data = {
                'Metric': ['Total Cost', 'Labor Cost', 'Material Cost', 'Equipment Cost'],
                'Value': [total_cost, total_labor, total_material, total_equipment]
            }
            pd.DataFrame(summary_data).to_excel(writer, sheet_name='Summary', index=False)

            # By Trade
            by_trade.to_frame().to_excel(writer, sheet_name='By Trade')

            # Detail
            df.to_excel(writer, sheet_name='Detail', index=False)

        return {
            'excel_path': excel_path,
            'total_cost': total_cost,
            'total_labor': total_labor,
            'total_material': total_material,
            'total_equipment': total_equipment,
            'by_trade': by_trade.to_dict(),
            'line_items': len(df),
            'currency': line_items[0].work_item.currency if line_items else 'USD'
        }


# Usage Example
def estimate_from_bim_model(
    model_path: str,
    qdrant_url: str,
    language: str = "EN",
    output_dir: str = "."
) -> dict:
    """Complete BIM to cost estimation workflow"""

    import subprocess
    from pathlib import Path

    # Step 1: Convert BIM to Excel
    print("Converting BIM model...")
    subprocess.run([
        r"C:\DDC\RvtExporter.exe",
        model_path,
        "complete", "bbox"
    ])

    xlsx_path = Path(model_path).with_suffix('.xlsx')

    # Step 2: Load QTO data
    print("Loading quantity data...")
    df = pd.read_excel(xlsx_path)

    # Step 3: Initialize estimator
    estimator = BIMCostEstimator(
        qdrant_url=qdrant_url,
        language=language
    )

    # Step 4: Generate estimate
    print("Generating cost estimate...")
    line_items = estimator.estimate_from_qto(df)

    # Step 5: Generate report
    project_name = Path(model_path).stem
    result = estimator.generate_estimate_report(
        line_items=line_items,
        project_name=project_name,
        output_path=output_dir
    )

    print(f"\nEstimate Complete!")
    print(f"Total Cost: {result['currency']} {result['total_cost']:,.2f}")
    print(f"Excel Report: {result['excel_path']}")

    return result


if __name__ == "__main__":
    result = estimate_from_bim_model(
        model_path=r"C:\Projects\Building.rvt",
        qdrant_url="https://your-qdrant-instance.io",
        language="DE",
        output_dir=r"C:\Projects\Estimates"
    )

n8n Workflow

See: n8n_4_CAD_(BIM)_Cost_Estimation_Pipeline_4D_5D_with_DDC_CWICR.json

stages:
  - convert: RvtExporter → XLSX
  - detect_project: LLM identifies project type
  - generate_phases: LLM creates construction phases
  - decompose: LLM breaks types into work items
  - vector_search: Qdrant finds CWICR matches
  - calculate: Qty × Unit Price
  - validate: CTO review
  - report: HTML + Excel output

Output Example

╔══════════════════════════════════════════════════════════════╗
║                    COST ESTIMATE SUMMARY                      ║
║   Project: Office Building Berlin                             ║
║   Date: 2026-01-24                                           ║
╠══════════════════════════════════════════════════════════════╣

TOTAL PROJECT COST:                    EUR 4,523,678.00
───────────────────────────────────────────────────────────────
  Labor:                               EUR 1,847,234.00 (41%)
  Materials:                           EUR 2,312,456.00 (51%)
  Equipment:                           EUR   363,988.00 ( 8%)

BY TRADE
───────────────────────────────────────────────────────────────
  Concrete:                            EUR 1,234,567.00 (27%)
  Masonry:                             EUR   876,543.00 (19%)
  Steel Structure:                     EUR   654,321.00 (14%)
  MEP:                                 EUR   543,210.00 (12%)
  Finishes:                            EUR   432,109.00 (10%)
  Other:                               EUR   782,928.00 (18%)

CONFIDENCE ANALYSIS
───────────────────────────────────────────────────────────────
  High (>0.85):                        78%
  Medium (0.70-0.85):                  18%
  Low (<0.70):                          4%

╚══════════════════════════════════════════════════════════════╝

Resources


"Resource-based costing separates physical quantities from volatile prices, enabling transparent and auditable estimates."

FAQ

What does the bim-cost-estimation-cwicr skill do?

Automated cost estimation from BIM models using DDC CWICR database (8 national bases, 78,228 positions). AI classification + vector search for accurate pricing.

How do I install bim-cost-estimation-cwicr?

Run npx skills add https://github.com/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction --skill bim-cost-estimation-cwicr in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/bim-cost-estimation-cwicr/ (personal) or .claude/skills/bim-cost-estimation-cwicr/ (project).

Which AI agents can use bim-cost-estimation-cwicr?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is bim-cost-estimation-cwicr safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains bim-cost-estimation-cwicr?

It is published by datadrivenconstruction in datadrivenconstruction/ddc_skills_for_ai_agents_in_construction. It has 133 recorded installs.

More from datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

View all →

warranty-tracker

datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

Track and manage construction warranties. Monitor expiration dates, claims, and manufacturer documentation.

AI & Agents996 installs

cad-to-data

datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

Convert CAD/BIM files to structured data. Extract element data from Revit, IFC, DWG, DGN files.

AI & Agents333 installs

dwg-to-excel

datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

Convert AutoCAD DWG files (1983-2026) to Excel databases using DwgExporter CLI. Extract layers, blocks, attributes, and geometry data without Autodesk licenses.

Data & Databases309 installs

drawing-analyzer

datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

Open the skill to read its SKILL.md instructions.

AI & Agents259 installs

permit-tracking-automation

datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

Automate construction permit tracking and management. Monitor application status, track renewal deadlines, manage document requirements, and integrate with municipal systems.

cost-estimation-resource

datadrivenconstruction/ddc_skills_for_ai_agents_in_construction

Calculate construction costs using resource-based method. Estimate project costs from work items, physical resource norms, and current prices.

AI & Agents193 installs

Popular data & databases skills

View category →

Postgres best practices maintained by Supabase, for Postgres running anywhere. Load this skill BEFORE writing or changing anything that lives in a Postgres database: creating or altering tables and columns (including choosing column types), schema design, migrations and declarative schema files, RLS policies and the tests that verify them, indexes, triggers, database functions, queues and scheduled jobs (pgcron, pgmq), vector/semantic search (pgvector), and restoring dumps (pgrestore) or importing data. Also load it when diagnosing slow queries, high CPU, timeouts, EXPLAIN plans, connection exhaustion, locking, bloat, or rows visible to the wrong user or tenant. This is not just a performance guide — schema, migration, security, and SQL authoring tasks need these rules too, even for a one-column change or a single query.

OfficialData & Databases462.2K installs

prisma-client-api

prisma/skills

Prisma Client API reference covering model queries, filters, operators, and client methods. Use when writing database queries, using CRUD operations, filtering data, or configuring Prisma Client. Triggers on "prisma query", "findMany", "create", "update", "delete", "$transaction".

OfficialData & Databases393.5K installs

Deprecated compatibility name for prisma-orm-setup. Use only when a user or existing integration explicitly invokes prisma-database-setup; otherwise select prisma-orm-setup.

OfficialData & Databases392.3K installs

prisma-cli

prisma/skills

Prisma ORM 7 CLI reference for existing Prisma 7 applications or explicitly selected Prisma 7 workflows. Covers prisma init, generate, migrate, db, dev, studio, and mcp. For setup, connection repair, or Prisma 8, use prisma-orm-setup; not the Prisma Platform CLI.

OfficialData & Databases390.8K installs

prisma-postgres

prisma/skills

Deprecated compatibility name for prisma-postgres-setup. Use only when a user or existing integration explicitly invokes prisma-postgres; otherwise select prisma-postgres-setup.

OfficialData & Databases384.4K installs

Required reference for Prisma ORM 7 SQL driver adapter work. Use when implementing or modifying adapters, adding database drivers, or touching SqlDriverAdapter, Transaction, savepoint, result mapping, or DriverAdapterError behavior. Covers current transaction lifecycle, optional savepoint hooks, original database-error preservation, and verification.

OfficialData & Databases378.9K installs