[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FJS5PX2ANRC0SNMRMNNPR9":3,"skill-same:01M6FJS5PX2ANRC0SNMRMNNPR9":60},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":27,"linkOnly":28,"markdownContent":29,"markdownBody":30,"frontMatter":31,"refName":33,"commitSha":34,"skillDirectory":35,"forksCount":36,"repositoryHtmlUrl":37,"repositoryHomepageUrl":6,"ownerHtmlUrl":38,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":39,"install":40,"resources":53},"01M6FJS5PX2ANRC0SNMRMNNPR9","cwicr-work-breakdown",null,"Break down CWICR work items into component resources. Decompose aggregate items, analyze resource composition, and generate detailed bills of resources.","kbarbel640-del\u002Fskills","kbarbel640-del","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255315490?v=4","01M6CJPPQGCCESXMG3K7BBGQ5J","01M6CJPPX2PB2BCZERFVM2C2B3",1,"MIT","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-work-breakdown\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26],"work","cwicr work breakdown","component","generate","Composition","analyze","decompose","break down","resources","2026-11-10 10:12:30",false,"---\r\nslug: \"cwicr-work-breakdown\"\r\ndisplay_name: \"CWICR Work Breakdown\"\r\ndescription: \"Break down CWICR work items into component resources. Decompose aggregate items, analyze resource composition, and generate detailed bills of resources.\"\r\n---\r\n\r\n# CWICR Work Breakdown\r\n\r\n## Business Case\r\n\r\n### Problem Statement\r\nWork items in CWICR contain aggregated resources:\r\n- What materials make up a concrete work item?\r\n- What labor categories are needed?\r\n- What equipment is involved?\r\n- How to generate detailed resource bills?\r\n\r\n### Solution\r\nDecompose CWICR work items into their constituent resources (labor, materials, equipment) with quantities and costs.\r\n\r\n### Business Value\r\n- **Transparency** - See inside aggregated items\r\n- **Procurement** - Generate material lists\r\n- **Scheduling** - Identify resource needs\r\n- **Cost control** - Track resource consumption\r\n\r\n## Technical Implementation\r\n\r\n```python\r\nimport pandas as pd\r\nimport numpy as np\r\nfrom typing import Dict, Any, List, Optional, Tuple\r\nfrom dataclasses import dataclass, field\r\nfrom datetime import datetime\r\nfrom enum import Enum\r\nfrom collections import defaultdict\r\n\r\n\r\nclass ResourceType(Enum):\r\n    \"\"\"Types of resources in work items.\"\"\"\r\n    LABOR = \"labor\"\r\n    MATERIAL = \"material\"\r\n    EQUIPMENT = \"equipment\"\r\n    OVERHEAD = \"overhead\"\r\n\r\n\r\n@dataclass\r\nclass ResourceComponent:\r\n    \"\"\"Single resource component of a work item.\"\"\"\r\n    resource_code: str\r\n    resource_type: ResourceType\r\n    description: str\r\n    unit: str\r\n    quantity_per_unit: float  # Per unit of work item\r\n    unit_rate: float\r\n    cost_per_unit: float  # Per unit of work item\r\n\r\n\r\n@dataclass\r\nclass WorkItemBreakdown:\r\n    \"\"\"Complete breakdown of a work item.\"\"\"\r\n    work_item_code: str\r\n    work_item_description: str\r\n    work_item_unit: str\r\n    components: List[ResourceComponent]\r\n    labor_cost_per_unit: float\r\n    material_cost_per_unit: float\r\n    equipment_cost_per_unit: float\r\n    total_cost_per_unit: float\r\n\r\n\r\n@dataclass\r\nclass BillOfResources:\r\n    \"\"\"Bill of resources for multiple work items.\"\"\"\r\n    project_name: str\r\n    total_labor_cost: float\r\n    total_material_cost: float\r\n    total_equipment_cost: float\r\n    total_cost: float\r\n    labor_resources: List[Dict[str, Any]]\r\n    material_resources: List[Dict[str, Any]]\r\n    equipment_resources: List[Dict[str, Any]]\r\n\r\n\r\nclass CWICRWorkBreakdown:\r\n    \"\"\"Break down work items into resources.\"\"\"\r\n\r\n    def __init__(self, cwicr_data: pd.DataFrame,\r\n                 resources_data: pd.DataFrame = None):\r\n        self.work_items = cwicr_data\r\n        self.resources = resources_data\r\n        self._index_data()\r\n\r\n    def _index_data(self):\r\n        \"\"\"Index data for fast lookup.\"\"\"\r\n        if 'work_item_code' in self.work_items.columns:\r\n            self._work_index = self.work_items.set_index('work_item_code')\r\n        else:\r\n            self._work_index = None\r\n\r\n        if self.resources is not None and 'resource_code' in self.resources.columns:\r\n            self._resource_index = self.resources.set_index('resource_code')\r\n        else:\r\n            self._resource_index = None\r\n\r\n    def breakdown_work_item(self, work_item_code: str) -> Optional[WorkItemBreakdown]:\r\n        \"\"\"Break down single work item into components.\"\"\"\r\n\r\n        if self._work_index is None or work_item_code not in self._work_index.index:\r\n            return None\r\n\r\n        item = self._work_index.loc[work_item_code]\r\n        components = []\r\n\r\n        # Extract labor component\r\n        labor_norm = float(item.get('labor_norm', 0) or 0)\r\n        labor_rate = float(item.get('labor_rate', 35) or 35)\r\n        labor_cost = float(item.get('labor_cost', labor_norm * labor_rate) or labor_norm * labor_rate)\r\n\r\n        if labor_norm > 0:\r\n            components.append(ResourceComponent(\r\n                resource_code=f\"{work_item_code}-LABOR\",\r\n                resource_type=ResourceType.LABOR,\r\n                description=f\"Labor for {item.get('description', '')}\",\r\n                unit=\"hr\",\r\n                quantity_per_unit=labor_norm,\r\n                unit_rate=labor_rate,\r\n                cost_per_unit=labor_cost\r\n            ))\r\n\r\n        # Extract material component\r\n        material_norm = float(item.get('material_norm', 1) or 1)\r\n        material_cost = float(item.get('material_cost', 0) or 0)\r\n\r\n        if material_cost > 0:\r\n            components.append(ResourceComponent(\r\n                resource_code=f\"{work_item_code}-MAT\",\r\n                resource_type=ResourceType.MATERIAL,\r\n                description=str(item.get('material_description', 'Materials')),\r\n                unit=str(item.get('material_unit', item.get('unit', 'ea'))),\r\n                quantity_per_unit=material_norm,\r\n                unit_rate=material_cost \u002F material_norm if material_norm > 0 else material_cost,\r\n                cost_per_unit=material_cost\r\n            ))\r\n\r\n        # Extract equipment component\r\n        equipment_norm = float(item.get('equipment_norm', 0) or 0)\r\n        equipment_rate = float(item.get('equipment_rate', 0) or 0)\r\n        equipment_cost = float(item.get('equipment_cost', equipment_norm * equipment_rate) or 0)\r\n\r\n        if equipment_norm > 0 or equipment_cost > 0:\r\n            components.append(ResourceComponent(\r\n                resource_code=f\"{work_item_code}-EQUIP\",\r\n                resource_type=ResourceType.EQUIPMENT,\r\n                description=str(item.get('equipment_description', 'Equipment')),\r\n                unit=\"hr\",\r\n                quantity_per_unit=equipment_norm,\r\n                unit_rate=equipment_rate,\r\n                cost_per_unit=equipment_cost\r\n            ))\r\n\r\n        return WorkItemBreakdown(\r\n            work_item_code=work_item_code,\r\n            work_item_description=str(item.get('description', '')),\r\n            work_item_unit=str(item.get('unit', '')),\r\n            components=components,\r\n            labor_cost_per_unit=labor_cost,\r\n            material_cost_per_unit=material_cost,\r\n            equipment_cost_per_unit=equipment_cost,\r\n            total_cost_per_unit=labor_cost + material_cost + equipment_cost\r\n        )\r\n\r\n    def generate_bill_of_resources(self,\r\n                                    items: List[Dict[str, Any]],\r\n                                    project_name: str = \"Project\") -> BillOfResources:\r\n        \"\"\"Generate bill of resources from work items.\"\"\"\r\n\r\n        labor_agg = defaultdict(lambda: {'hours': 0, 'cost': 0, 'work_items': []})\r\n        material_agg = defaultdict(lambda: {'quantity': 0, 'cost': 0, 'unit': '', 'work_items': []})\r\n        equipment_agg = defaultdict(lambda: {'hours': 0, 'cost': 0, 'work_items': []})\r\n\r\n        for item in items:\r\n            code = item.get('work_item_code', item.get('code'))\r\n            qty = item.get('quantity', 0)\r\n\r\n            breakdown = self.breakdown_work_item(code)\r\n            if not breakdown:\r\n                continue\r\n\r\n            for component in breakdown.components:\r\n                scaled_qty = component.quantity_per_unit * qty\r\n                scaled_cost = component.cost_per_unit * qty\r\n\r\n                if component.resource_type == ResourceType.LABOR:\r\n                    key = 'General Labor'  # Could be more specific with skill data\r\n                    labor_agg[key]['hours'] += scaled_qty\r\n                    labor_agg[key]['cost'] += scaled_cost\r\n                    labor_agg[key]['work_items'].append(code)\r\n\r\n                elif component.resource_type == ResourceType.MATERIAL:\r\n                    key = component.description\r\n                    material_agg[key]['quantity'] += scaled_qty\r\n                    material_agg[key]['cost'] += scaled_cost\r\n                    material_agg[key]['unit'] = component.unit\r\n                    material_agg[key]['work_items'].append(code)\r\n\r\n                elif component.resource_type == ResourceType.EQUIPMENT:\r\n                    key = component.description\r\n                    equipment_agg[key]['hours'] += scaled_qty\r\n                    equipment_agg[key]['cost'] += scaled_cost\r\n                    equipment_agg[key]['work_items'].append(code)\r\n\r\n        # Convert to lists\r\n        labor_resources = [\r\n            {\r\n                'resource': name,\r\n                'hours': round(data['hours'], 1),\r\n                'cost': round(data['cost'], 2),\r\n                'work_items': len(set(data['work_items']))\r\n            }\r\n            for name, data in labor_agg.items()\r\n        ]\r\n\r\n        material_resources = [\r\n            {\r\n                'resource': name,\r\n                'quantity': round(data['quantity'], 2),\r\n                'unit': data['unit'],\r\n                'cost': round(data['cost'], 2),\r\n                'work_items': len(set(data['work_items']))\r\n            }\r\n            for name, data in material_agg.items()\r\n        ]\r\n\r\n        equipment_resources = [\r\n            {\r\n                'resource': name,\r\n                'hours': round(data['hours'], 1),\r\n                'cost': round(data['cost'], 2),\r\n                'work_items': len(set(data['work_items']))\r\n            }\r\n            for name, data in equipment_agg.items()\r\n        ]\r\n\r\n        total_labor = sum(r['cost'] for r in labor_resources)\r\n        total_material = sum(r['cost'] for r in material_resources)\r\n        total_equipment = sum(r['cost'] for r in equipment_resources)\r\n\r\n        return BillOfResources(\r\n            project_name=project_name,\r\n            total_labor_cost=round(total_labor, 2),\r\n            total_material_cost=round(total_material, 2),\r\n            total_equipment_cost=round(total_equipment, 2),\r\n            total_cost=round(total_labor + total_material + total_equipment, 2),\r\n            labor_resources=labor_resources,\r\n            material_resources=material_resources,\r\n            equipment_resources=equipment_resources\r\n        )\r\n\r\n    def get_resource_composition(self, work_item_code: str) -> Dict[str, float]:\r\n        \"\"\"Get percentage composition of work item by resource type.\"\"\"\r\n\r\n        breakdown = self.breakdown_work_item(work_item_code)\r\n        if not breakdown or breakdown.total_cost_per_unit == 0:\r\n            return {'labor': 0, 'material': 0, 'equipment': 0}\r\n\r\n        total = breakdown.total_cost_per_unit\r\n        return {\r\n            'labor': round(breakdown.labor_cost_per_unit \u002F total * 100, 1),\r\n            'material': round(breakdown.material_cost_per_unit \u002F total * 100, 1),\r\n            'equipment': round(breakdown.equipment_cost_per_unit \u002F total * 100, 1)\r\n        }\r\n\r\n    def analyze_labor_intensity(self,\r\n                                 work_items: List[str]) -> pd.DataFrame:\r\n        \"\"\"Analyze labor intensity of work items.\"\"\"\r\n\r\n        data = []\r\n        for code in work_items:\r\n            breakdown = self.breakdown_work_item(code)\r\n            if breakdown:\r\n                composition = self.get_resource_composition(code)\r\n                labor_components = [c for c in breakdown.components if c.resource_type == ResourceType.LABOR]\r\n                labor_hours = sum(c.quantity_per_unit for c in labor_components)\r\n\r\n                data.append({\r\n                    'work_item_code': code,\r\n                    'description': breakdown.work_item_description,\r\n                    'labor_hours_per_unit': labor_hours,\r\n                    'labor_cost_pct': composition['labor'],\r\n                    'material_cost_pct': composition['material'],\r\n                    'equipment_cost_pct': composition['equipment'],\r\n                    'labor_intensive': composition['labor'] > 50\r\n                })\r\n\r\n        return pd.DataFrame(data).sort_values('labor_cost_pct', ascending=False)\r\n\r\n    def export_breakdown(self,\r\n                         breakdown: WorkItemBreakdown,\r\n                         output_path: str) -> str:\r\n        \"\"\"Export single work item breakdown.\"\"\"\r\n\r\n        df = pd.DataFrame([\r\n            {\r\n                'Resource Code': c.resource_code,\r\n                'Type': c.resource_type.value,\r\n                'Description': c.description,\r\n                'Unit': c.unit,\r\n                'Quantity\u002FUnit': c.quantity_per_unit,\r\n                'Rate': c.unit_rate,\r\n                'Cost\u002FUnit': c.cost_per_unit\r\n            }\r\n            for c in breakdown.components\r\n        ])\r\n\r\n        df.to_excel(output_path, index=False)\r\n        return output_path\r\n\r\n    def export_bill_of_resources(self,\r\n                                  bill: BillOfResources,\r\n                                  output_path: str) -> str:\r\n        \"\"\"Export bill of resources to Excel.\"\"\"\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Summary\r\n            summary_df = pd.DataFrame([{\r\n                'Project': bill.project_name,\r\n                'Total Labor Cost': bill.total_labor_cost,\r\n                'Total Material Cost': bill.total_material_cost,\r\n                'Total Equipment Cost': bill.total_equipment_cost,\r\n                'Grand Total': bill.total_cost\r\n            }])\r\n            summary_df.to_excel(writer, sheet_name='Summary', index=False)\r\n\r\n            # Labor\r\n            labor_df = pd.DataFrame(bill.labor_resources)\r\n            labor_df.to_excel(writer, sheet_name='Labor', index=False)\r\n\r\n            # Materials\r\n            material_df = pd.DataFrame(bill.material_resources)\r\n            material_df.to_excel(writer, sheet_name='Materials', index=False)\r\n\r\n            # Equipment\r\n            equipment_df = pd.DataFrame(bill.equipment_resources)\r\n            equipment_df.to_excel(writer, sheet_name='Equipment', index=False)\r\n\r\n        return output_path\r\n\r\n\r\nclass ResourceAggregator:\r\n    \"\"\"Aggregate resources across work items.\"\"\"\r\n\r\n    def __init__(self, breakdown_tool: CWICRWorkBreakdown):\r\n        self.breakdown = breakdown_tool\r\n\r\n    def aggregate_by_trade(self,\r\n                           items: List[Dict[str, Any]]) -> Dict[str, Dict[str, float]]:\r\n        \"\"\"Aggregate resources by trade\u002Fcategory.\"\"\"\r\n\r\n        by_trade = defaultdict(lambda: {'labor_hours': 0, 'labor_cost': 0, 'items': 0})\r\n\r\n        for item in items:\r\n            code = item.get('work_item_code', item.get('code'))\r\n            qty = item.get('quantity', 0)\r\n\r\n            # Extract trade from code prefix\r\n            trade = code.split('-')[0] if '-' in code else 'General'\r\n\r\n            breakdown = self.breakdown.breakdown_work_item(code)\r\n            if breakdown:\r\n                by_trade[trade]['labor_hours'] += breakdown.labor_cost_per_unit \u002F 35 * qty  # Estimate hours\r\n                by_trade[trade]['labor_cost'] += breakdown.labor_cost_per_unit * qty\r\n                by_trade[trade]['items'] += 1\r\n\r\n        return dict(by_trade)\r\n\r\n    def identify_critical_resources(self,\r\n                                     bill: BillOfResources,\r\n                                     threshold_pct: float = 10) -> Dict[str, List[Dict]]:\r\n        \"\"\"Identify resources that contribute significantly to cost.\"\"\"\r\n\r\n        critical = {\r\n            'labor': [],\r\n            'material': [],\r\n            'equipment': []\r\n        }\r\n\r\n        # Labor\r\n        for r in bill.labor_resources:\r\n            if bill.total_labor_cost > 0:\r\n                pct = r['cost'] \u002F bill.total_labor_cost * 100\r\n                if pct >= threshold_pct:\r\n                    critical['labor'].append({**r, 'percentage': round(pct, 1)})\r\n\r\n        # Materials\r\n        for r in bill.material_resources:\r\n            if bill.total_material_cost > 0:\r\n                pct = r['cost'] \u002F bill.total_material_cost * 100\r\n                if pct >= threshold_pct:\r\n                    critical['material'].append({**r, 'percentage': round(pct, 1)})\r\n\r\n        # Equipment\r\n        for r in bill.equipment_resources:\r\n            if bill.total_equipment_cost > 0:\r\n                pct = r['cost'] \u002F bill.total_equipment_cost * 100\r\n                if pct >= threshold_pct:\r\n                    critical['equipment'].append({**r, 'percentage': round(pct, 1)})\r\n\r\n        return critical\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\n# Load CWICR data\r\ncwicr = pd.read_parquet(\"ddc_cwicr_en.parquet\")\r\n\r\n# Initialize breakdown tool\r\nbreakdown = CWICRWorkBreakdown(cwicr)\r\n\r\n# Break down single item\r\nitem_breakdown = breakdown.breakdown_work_item(\"CONC-001\")\r\n\r\nprint(f\"Work Item: {item_breakdown.work_item_description}\")\r\nprint(f\"Labor: ${item_breakdown.labor_cost_per_unit}\")\r\nprint(f\"Material: ${item_breakdown.material_cost_per_unit}\")\r\nprint(f\"Equipment: ${item_breakdown.equipment_cost_per_unit}\")\r\n\r\nfor comp in item_breakdown.components:\r\n    print(f\"  - {comp.resource_type.value}: {comp.description}\")\r\n```\r\n\r\n## Common Use Cases\r\n\r\n### 1. Bill of Resources\r\n```python\r\nitems = [\r\n    {'work_item_code': 'CONC-001', 'quantity': 150},\r\n    {'work_item_code': 'REBAR-002', 'quantity': 5000},\r\n    {'work_item_code': 'FORM-003', 'quantity': 300}\r\n]\r\n\r\nbill = breakdown.generate_bill_of_resources(items, \"Building A\")\r\nprint(f\"Total Labor: ${bill.total_labor_cost:,.2f}\")\r\nprint(f\"Total Material: ${bill.total_material_cost:,.2f}\")\r\n```\r\n\r\n### 2. Resource Composition\r\n```python\r\ncomposition = breakdown.get_resource_composition(\"CONC-001\")\r\nprint(f\"Labor: {composition['labor']}%\")\r\nprint(f\"Material: {composition['material']}%\")\r\n```\r\n\r\n### 3. Labor Intensity Analysis\r\n```python\r\nanalysis = breakdown.analyze_labor_intensity(['CONC-001', 'EXCV-002', 'REBAR-003'])\r\nprint(analysis)\r\n```\r\n\r\n### 4. Export Report\r\n```python\r\nbreakdown.export_bill_of_resources(bill, \"bill_of_resources.xlsx\")\r\n```\r\n\r\n## Resources\r\n- **GitHub**: [OpenConstructionEstimate-DDC-CWICR](https:\u002F\u002Fgithub.com\u002Fdatadrivenconstruction\u002FOpenConstructionEstimate-DDC-CWICR)\r\n- **DDC Book**: Chapter 3.1 - Resource-Based Estimating\r\n","# CWICR Work Breakdown\r\n\r\n## Business Case\r\n\r\n### Problem Statement\r\nWork items in CWICR contain aggregated resources:\r\n- What materials make up a concrete work item?\r\n- What labor categories are needed?\r\n- What equipment is involved?\r\n- How to generate detailed resource bills?\r\n\r\n### Solution\r\nDecompose CWICR work items into their constituent resources (labor, materials, equipment) with quantities and costs.\r\n\r\n### Business Value\r\n- **Transparency** - See inside aggregated items\r\n- **Procurement** - Generate material lists\r\n- **Scheduling** - Identify resource needs\r\n- **Cost control** - Track resource consumption\r\n\r\n## Technical Implementation\r\n\r\n```python\r\nimport pandas as pd\r\nimport numpy as np\r\nfrom typing import Dict, Any, List, Optional, Tuple\r\nfrom dataclasses import dataclass, field\r\nfrom datetime import datetime\r\nfrom enum import Enum\r\nfrom collections import defaultdict\r\n\r\n\r\nclass ResourceType(Enum):\r\n    \"\"\"Types of resources in work items.\"\"\"\r\n    LABOR = \"labor\"\r\n    MATERIAL = \"material\"\r\n    EQUIPMENT = \"equipment\"\r\n    OVERHEAD = \"overhead\"\r\n\r\n\r\n@dataclass\r\nclass ResourceComponent:\r\n    \"\"\"Single resource component of a work item.\"\"\"\r\n    resource_code: str\r\n    resource_type: ResourceType\r\n    description: str\r\n    unit: str\r\n    quantity_per_unit: float  # Per unit of work item\r\n    unit_rate: float\r\n    cost_per_unit: float  # Per unit of work item\r\n\r\n\r\n@dataclass\r\nclass WorkItemBreakdown:\r\n    \"\"\"Complete breakdown of a work item.\"\"\"\r\n    work_item_code: str\r\n    work_item_description: str\r\n    work_item_unit: str\r\n    components: List[ResourceComponent]\r\n    labor_cost_per_unit: float\r\n    material_cost_per_unit: float\r\n    equipment_cost_per_unit: float\r\n    total_cost_per_unit: float\r\n\r\n\r\n@dataclass\r\nclass BillOfResources:\r\n    \"\"\"Bill of resources for multiple work items.\"\"\"\r\n    project_name: str\r\n    total_labor_cost: float\r\n    total_material_cost: float\r\n    total_equipment_cost: float\r\n    total_cost: float\r\n    labor_resources: List[Dict[str, Any]]\r\n    material_resources: List[Dict[str, Any]]\r\n    equipment_resources: List[Dict[str, Any]]\r\n\r\n\r\nclass CWICRWorkBreakdown:\r\n    \"\"\"Break down work items into resources.\"\"\"\r\n\r\n    def __init__(self, cwicr_data: pd.DataFrame,\r\n                 resources_data: pd.DataFrame = None):\r\n        self.work_items = cwicr_data\r\n        self.resources = resources_data\r\n        self._index_data()\r\n\r\n    def _index_data(self):\r\n        \"\"\"Index data for fast lookup.\"\"\"\r\n        if 'work_item_code' in self.work_items.columns:\r\n            self._work_index = self.work_items.set_index('work_item_code')\r\n        else:\r\n            self._work_index = None\r\n\r\n        if self.resources is not None and 'resource_code' in self.resources.columns:\r\n            self._resource_index = self.resources.set_index('resource_code')\r\n        else:\r\n            self._resource_index = None\r\n\r\n    def breakdown_work_item(self, work_item_code: str) -> Optional[WorkItemBreakdown]:\r\n        \"\"\"Break down single work item into components.\"\"\"\r\n\r\n        if self._work_index is None or work_item_code not in self._work_index.index:\r\n            return None\r\n\r\n        item = self._work_index.loc[work_item_code]\r\n        components = []\r\n\r\n        # Extract labor component\r\n        labor_norm = float(item.get('labor_norm', 0) or 0)\r\n        labor_rate = float(item.get('labor_rate', 35) or 35)\r\n        labor_cost = float(item.get('labor_cost', labor_norm * labor_rate) or labor_norm * labor_rate)\r\n\r\n        if labor_norm > 0:\r\n            components.append(ResourceComponent(\r\n                resource_code=f\"{work_item_code}-LABOR\",\r\n                resource_type=ResourceType.LABOR,\r\n                description=f\"Labor for {item.get('description', '')}\",\r\n                unit=\"hr\",\r\n                quantity_per_unit=labor_norm,\r\n                unit_rate=labor_rate,\r\n                cost_per_unit=labor_cost\r\n            ))\r\n\r\n        # Extract material component\r\n        material_norm = float(item.get('material_norm', 1) or 1)\r\n        material_cost = float(item.get('material_cost', 0) or 0)\r\n\r\n        if material_cost > 0:\r\n            components.append(ResourceComponent(\r\n                resource_code=f\"{work_item_code}-MAT\",\r\n                resource_type=ResourceType.MATERIAL,\r\n                description=str(item.get('material_description', 'Materials')),\r\n                unit=str(item.get('material_unit', item.get('unit', 'ea'))),\r\n                quantity_per_unit=material_norm,\r\n                unit_rate=material_cost \u002F material_norm if material_norm > 0 else material_cost,\r\n                cost_per_unit=material_cost\r\n            ))\r\n\r\n        # Extract equipment component\r\n        equipment_norm = float(item.get('equipment_norm', 0) or 0)\r\n        equipment_rate = float(item.get('equipment_rate', 0) or 0)\r\n        equipment_cost = float(item.get('equipment_cost', equipment_norm * equipment_rate) or 0)\r\n\r\n        if equipment_norm > 0 or equipment_cost > 0:\r\n            components.append(ResourceComponent(\r\n                resource_code=f\"{work_item_code}-EQUIP\",\r\n                resource_type=ResourceType.EQUIPMENT,\r\n                description=str(item.get('equipment_description', 'Equipment')),\r\n                unit=\"hr\",\r\n                quantity_per_unit=equipment_norm,\r\n                unit_rate=equipment_rate,\r\n                cost_per_unit=equipment_cost\r\n            ))\r\n\r\n        return WorkItemBreakdown(\r\n            work_item_code=work_item_code,\r\n            work_item_description=str(item.get('description', '')),\r\n            work_item_unit=str(item.get('unit', '')),\r\n            components=components,\r\n            labor_cost_per_unit=labor_cost,\r\n            material_cost_per_unit=material_cost,\r\n            equipment_cost_per_unit=equipment_cost,\r\n            total_cost_per_unit=labor_cost + material_cost + equipment_cost\r\n        )\r\n\r\n    def generate_bill_of_resources(self,\r\n                                    items: List[Dict[str, Any]],\r\n                                    project_name: str = \"Project\") -> BillOfResources:\r\n        \"\"\"Generate bill of resources from work items.\"\"\"\r\n\r\n        labor_agg = defaultdict(lambda: {'hours': 0, 'cost': 0, 'work_items': []})\r\n        material_agg = defaultdict(lambda: {'quantity': 0, 'cost': 0, 'unit': '', 'work_items': []})\r\n        equipment_agg = defaultdict(lambda: {'hours': 0, 'cost': 0, 'work_items': []})\r\n\r\n        for item in items:\r\n            code = item.get('work_item_code', item.get('code'))\r\n            qty = item.get('quantity', 0)\r\n\r\n            breakdown = self.breakdown_work_item(code)\r\n            if not breakdown:\r\n                continue\r\n\r\n            for component in breakdown.components:\r\n                scaled_qty = component.quantity_per_unit * qty\r\n                scaled_cost = component.cost_per_unit * qty\r\n\r\n                if component.resource_type == ResourceType.LABOR:\r\n                    key = 'General Labor'  # Could be more specific with skill data\r\n                    labor_agg[key]['hours'] += scaled_qty\r\n                    labor_agg[key]['cost'] += scaled_cost\r\n                    labor_agg[key]['work_items'].append(code)\r\n\r\n                elif component.resource_type == ResourceType.MATERIAL:\r\n                    key = component.description\r\n                    material_agg[key]['quantity'] += scaled_qty\r\n                    material_agg[key]['cost'] += scaled_cost\r\n                    material_agg[key]['unit'] = component.unit\r\n                    material_agg[key]['work_items'].append(code)\r\n\r\n                elif component.resource_type == ResourceType.EQUIPMENT:\r\n                    key = component.description\r\n                    equipment_agg[key]['hours'] += scaled_qty\r\n                    equipment_agg[key]['cost'] += scaled_cost\r\n                    equipment_agg[key]['work_items'].append(code)\r\n\r\n        # Convert to lists\r\n        labor_resources = [\r\n            {\r\n                'resource': name,\r\n                'hours': round(data['hours'], 1),\r\n                'cost': round(data['cost'], 2),\r\n                'work_items': len(set(data['work_items']))\r\n            }\r\n            for name, data in labor_agg.items()\r\n        ]\r\n\r\n        material_resources = [\r\n            {\r\n                'resource': name,\r\n                'quantity': round(data['quantity'], 2),\r\n                'unit': data['unit'],\r\n                'cost': round(data['cost'], 2),\r\n                'work_items': len(set(data['work_items']))\r\n            }\r\n            for name, data in material_agg.items()\r\n        ]\r\n\r\n        equipment_resources = [\r\n            {\r\n                'resource': name,\r\n                'hours': round(data['hours'], 1),\r\n                'cost': round(data['cost'], 2),\r\n                'work_items': len(set(data['work_items']))\r\n            }\r\n            for name, data in equipment_agg.items()\r\n        ]\r\n\r\n        total_labor = sum(r['cost'] for r in labor_resources)\r\n        total_material = sum(r['cost'] for r in material_resources)\r\n        total_equipment = sum(r['cost'] for r in equipment_resources)\r\n\r\n        return BillOfResources(\r\n            project_name=project_name,\r\n            total_labor_cost=round(total_labor, 2),\r\n            total_material_cost=round(total_material, 2),\r\n            total_equipment_cost=round(total_equipment, 2),\r\n            total_cost=round(total_labor + total_material + total_equipment, 2),\r\n            labor_resources=labor_resources,\r\n            material_resources=material_resources,\r\n            equipment_resources=equipment_resources\r\n        )\r\n\r\n    def get_resource_composition(self, work_item_code: str) -> Dict[str, float]:\r\n        \"\"\"Get percentage composition of work item by resource type.\"\"\"\r\n\r\n        breakdown = self.breakdown_work_item(work_item_code)\r\n        if not breakdown or breakdown.total_cost_per_unit == 0:\r\n            return {'labor': 0, 'material': 0, 'equipment': 0}\r\n\r\n        total = breakdown.total_cost_per_unit\r\n        return {\r\n            'labor': round(breakdown.labor_cost_per_unit \u002F total * 100, 1),\r\n            'material': round(breakdown.material_cost_per_unit \u002F total * 100, 1),\r\n            'equipment': round(breakdown.equipment_cost_per_unit \u002F total * 100, 1)\r\n        }\r\n\r\n    def analyze_labor_intensity(self,\r\n                                 work_items: List[str]) -> pd.DataFrame:\r\n        \"\"\"Analyze labor intensity of work items.\"\"\"\r\n\r\n        data = []\r\n        for code in work_items:\r\n            breakdown = self.breakdown_work_item(code)\r\n            if breakdown:\r\n                composition = self.get_resource_composition(code)\r\n                labor_components = [c for c in breakdown.components if c.resource_type == ResourceType.LABOR]\r\n                labor_hours = sum(c.quantity_per_unit for c in labor_components)\r\n\r\n                data.append({\r\n                    'work_item_code': code,\r\n                    'description': breakdown.work_item_description,\r\n                    'labor_hours_per_unit': labor_hours,\r\n                    'labor_cost_pct': composition['labor'],\r\n                    'material_cost_pct': composition['material'],\r\n                    'equipment_cost_pct': composition['equipment'],\r\n                    'labor_intensive': composition['labor'] > 50\r\n                })\r\n\r\n        return pd.DataFrame(data).sort_values('labor_cost_pct', ascending=False)\r\n\r\n    def export_breakdown(self,\r\n                         breakdown: WorkItemBreakdown,\r\n                         output_path: str) -> str:\r\n        \"\"\"Export single work item breakdown.\"\"\"\r\n\r\n        df = pd.DataFrame([\r\n            {\r\n                'Resource Code': c.resource_code,\r\n                'Type': c.resource_type.value,\r\n                'Description': c.description,\r\n                'Unit': c.unit,\r\n                'Quantity\u002FUnit': c.quantity_per_unit,\r\n                'Rate': c.unit_rate,\r\n                'Cost\u002FUnit': c.cost_per_unit\r\n            }\r\n            for c in breakdown.components\r\n        ])\r\n\r\n        df.to_excel(output_path, index=False)\r\n        return output_path\r\n\r\n    def export_bill_of_resources(self,\r\n                                  bill: BillOfResources,\r\n                                  output_path: str) -> str:\r\n        \"\"\"Export bill of resources to Excel.\"\"\"\r\n\r\n        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r\n            # Summary\r\n            summary_df = pd.DataFrame([{\r\n                'Project': bill.project_name,\r\n                'Total Labor Cost': bill.total_labor_cost,\r\n                'Total Material Cost': bill.total_material_cost,\r\n                'Total Equipment Cost': bill.total_equipment_cost,\r\n                'Grand Total': bill.total_cost\r\n            }])\r\n            summary_df.to_excel(writer, sheet_name='Summary', index=False)\r\n\r\n            # Labor\r\n            labor_df = pd.DataFrame(bill.labor_resources)\r\n            labor_df.to_excel(writer, sheet_name='Labor', index=False)\r\n\r\n            # Materials\r\n            material_df = pd.DataFrame(bill.material_resources)\r\n            material_df.to_excel(writer, sheet_name='Materials', index=False)\r\n\r\n            # Equipment\r\n            equipment_df = pd.DataFrame(bill.equipment_resources)\r\n            equipment_df.to_excel(writer, sheet_name='Equipment', index=False)\r\n\r\n        return output_path\r\n\r\n\r\nclass ResourceAggregator:\r\n    \"\"\"Aggregate resources across work items.\"\"\"\r\n\r\n    def __init__(self, breakdown_tool: CWICRWorkBreakdown):\r\n        self.breakdown = breakdown_tool\r\n\r\n    def aggregate_by_trade(self,\r\n                           items: List[Dict[str, Any]]) -> Dict[str, Dict[str, float]]:\r\n        \"\"\"Aggregate resources by trade\u002Fcategory.\"\"\"\r\n\r\n        by_trade = defaultdict(lambda: {'labor_hours': 0, 'labor_cost': 0, 'items': 0})\r\n\r\n        for item in items:\r\n            code = item.get('work_item_code', item.get('code'))\r\n            qty = item.get('quantity', 0)\r\n\r\n            # Extract trade from code prefix\r\n            trade = code.split('-')[0] if '-' in code else 'General'\r\n\r\n            breakdown = self.breakdown.breakdown_work_item(code)\r\n            if breakdown:\r\n                by_trade[trade]['labor_hours'] += breakdown.labor_cost_per_unit \u002F 35 * qty  # Estimate hours\r\n                by_trade[trade]['labor_cost'] += breakdown.labor_cost_per_unit * qty\r\n                by_trade[trade]['items'] += 1\r\n\r\n        return dict(by_trade)\r\n\r\n    def identify_critical_resources(self,\r\n                                     bill: BillOfResources,\r\n                                     threshold_pct: float = 10) -> Dict[str, List[Dict]]:\r\n        \"\"\"Identify resources that contribute significantly to cost.\"\"\"\r\n\r\n        critical = {\r\n            'labor': [],\r\n            'material': [],\r\n            'equipment': []\r\n        }\r\n\r\n        # Labor\r\n        for r in bill.labor_resources:\r\n            if bill.total_labor_cost > 0:\r\n                pct = r['cost'] \u002F bill.total_labor_cost * 100\r\n                if pct >= threshold_pct:\r\n                    critical['labor'].append({**r, 'percentage': round(pct, 1)})\r\n\r\n        # Materials\r\n        for r in bill.material_resources:\r\n            if bill.total_material_cost > 0:\r\n                pct = r['cost'] \u002F bill.total_material_cost * 100\r\n                if pct >= threshold_pct:\r\n                    critical['material'].append({**r, 'percentage': round(pct, 1)})\r\n\r\n        # Equipment\r\n        for r in bill.equipment_resources:\r\n            if bill.total_equipment_cost > 0:\r\n                pct = r['cost'] \u002F bill.total_equipment_cost * 100\r\n                if pct >= threshold_pct:\r\n                    critical['equipment'].append({**r, 'percentage': round(pct, 1)})\r\n\r\n        return critical\r\n```\r\n\r\n## Quick Start\r\n\r\n```python\r\n# Load CWICR data\r\ncwicr = pd.read_parquet(\"ddc_cwicr_en.parquet\")\r\n\r\n# Initialize breakdown tool\r\nbreakdown = CWICRWorkBreakdown(cwicr)\r\n\r\n# Break down single item\r\nitem_breakdown = breakdown.breakdown_work_item(\"CONC-001\")\r\n\r\nprint(f\"Work Item: {item_breakdown.work_item_description}\")\r\nprint(f\"Labor: ${item_breakdown.labor_cost_per_unit}\")\r\nprint(f\"Material: ${item_breakdown.material_cost_per_unit}\")\r\nprint(f\"Equipment: ${item_breakdown.equipment_cost_per_unit}\")\r\n\r\nfor comp in item_breakdown.components:\r\n    print(f\"  - {comp.resource_type.value}: {comp.description}\")\r\n```\r\n\r\n## Common Use Cases\r\n\r\n### 1. Bill of Resources\r\n```python\r\nitems = [\r\n    {'work_item_code': 'CONC-001', 'quantity': 150},\r\n    {'work_item_code': 'REBAR-002', 'quantity': 5000},\r\n    {'work_item_code': 'FORM-003', 'quantity': 300}\r\n]\r\n\r\nbill = breakdown.generate_bill_of_resources(items, \"Building A\")\r\nprint(f\"Total Labor: ${bill.total_labor_cost:,.2f}\")\r\nprint(f\"Total Material: ${bill.total_material_cost:,.2f}\")\r\n```\r\n\r\n### 2. Resource Composition\r\n```python\r\ncomposition = breakdown.get_resource_composition(\"CONC-001\")\r\nprint(f\"Labor: {composition['labor']}%\")\r\nprint(f\"Material: {composition['material']}%\")\r\n```\r\n\r\n### 3. Labor Intensity Analysis\r\n```python\r\nanalysis = breakdown.analyze_labor_intensity(['CONC-001', 'EXCV-002', 'REBAR-003'])\r\nprint(analysis)\r\n```\r\n\r\n### 4. Export Report\r\n```python\r\nbreakdown.export_bill_of_resources(bill, \"bill_of_resources.xlsx\")\r\n```\r\n\r\n## Resources\r\n- **GitHub**: [OpenConstructionEstimate-DDC-CWICR](https:\u002F\u002Fgithub.com\u002Fdatadrivenconstruction\u002FOpenConstructionEstimate-DDC-CWICR)\r\n- **DDC Book**: Chapter 3.1 - Resource-Based Estimating\r\n",{"slug":5,"description":7,"display_name":32},"CWICR Work Breakdown","main","e7e336ac628c3e3bd771aff1aaa469c93778f94a","skills\u002Fdatadrivenconstruction\u002Fcwicr-work-breakdown",0,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del","2026-08-23 22:39:37",{"source":8,"skillName":5,"commands":41,"prompt":51,"zipAvailable":52},[42,45,48],{"tool":43,"command":44},"npx","npx skills add kbarbel640-del\u002Fskills --skill cwicr-work-breakdown",{"tool":46,"command":47},"bunx","bunx skills add kbarbel640-del\u002Fskills --skill cwicr-work-breakdown",{"tool":49,"command":50},"pnpm","pnpm dlx skills add kbarbel640-del\u002Fskills --skill cwicr-work-breakdown","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-work-breakdown\u002FSKILL.md",true,[54],{"path":55,"resourceType":56,"resourceTypeDesc":57,"sizeBytes":58,"sourceHtmlUrl":59},"_meta.json","REFERENCE","参考文档",308,"https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fdatadrivenconstruction\u002Fcwicr-work-breakdown\u002F_meta.json",[61,92,120,141,147,167],{"skillNo":62,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":72,"publishedAt":27},"01M6G8J55967D6281ACMKAKTEQ","crowd-prompting","A marketplace where AI agents improve prompts, system instructions, tool descriptions, and other text-based content with domain expertise from real-world operations — and earn tokens for valuable contributions.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzzadrian\u002Fcrowd-prompting\u002FSKILL.md",[67],{"categoryNo":68,"categoryName":69,"taxonomyType":70,"taxonomyTypeDesc":71},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91],"crowd prompting","prompting","api","with","tokens","domain","world","prompts","operations","instructions","text","tool","system","improve","productivity","marketplace","https","content","ai agents",{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":103,"publishedAt":27},"01M6G8J0PKPAYVET6BWE8W4C26","dilemm-ai","Compete in DilemmAI, the prisoner's dilemma AI arena at dilemm.ai. Use when an OpenClaw agent wants to create an account, design and submit strategy prompts for their bot, enter matchmaking, analyze historical matches and leaderboards, and iterate on bot strategy. Requires headless browser automation (no API available yet).","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzyori\u002Fdilemm-ai\u002FSKILL.md",[98],{"categoryNo":99,"categoryName":100,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[104,75,105,23,106,107,108,109,110,111,112,113,114,115,116,117,118,80,119],"dilemm ai","arena","browser","openclaw agent","create","automation","browser automation","bot","openclaw","design","strategy","headless","compete","submit","matchmaking","use",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":129,"publishedAt":27},"01M6G8HWAF3K9SW7NP3Z83CPJ6","arxiv-paper-reviews","Interact with arXiv Crawler API to fetch papers, read reviews, and submit comments. Use when working with arXiv papers, fetching paper lists by date\u002Fcategory\u002Finterest, viewing paper details with comments, or submitting paper reviews via API at http:\u002F\u002F150.158.152.82:8000.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Fweak-accept\u002FSKILL.md",[126],{"categoryNo":127,"categoryName":128,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000021","资料检索与研究",[130,131,132,133,134,135,136,76,137,117,119,138,75,139,140],"arxiv paper reviews","reviews","arxiv","paper","crawler","papers","comments","fetch","read","http","via",{"skillNo":142,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":146,"publishedAt":27},"01M6G8HQJ7N7WMY6YV7D7SSJ16","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzxrys\u002Farxiv-paper-reviews\u002FSKILL.md",[145],{"categoryNo":127,"categoryName":128,"taxonomyType":101,"taxonomyTypeDesc":102},[133,132,131,130,140,135,136,76,134,117,119,137,138,75,139],{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":27},"01M6G8HM95Y64JNVFC2HN4E2BG","git-summary","Get a quick summary of the current Git repository including status, recent commits, branches, and contributors.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzweack\u002Fgit-summary\u002FSKILL.md",[],[154,155,156,157,158,159,160,161,162,163,164,165,166],"git","summary","git summary","commits","repository","win32","status","linux","contributors","true","quick","get","branches",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":177,"publishedAt":27},"01M6G8HGEGF05CNEJCGVYFSC4R","agent-constitution","Interact with AgentConstitution governance contracts on Base Sepolia. Check compliance, read rules, log actions, query governance state.","https:\u002F\u002Fgithub.com\u002Fkbarbel640-del\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fztsalexey\u002Fagent-constitution\u002FSKILL.md",[173,174],{"categoryNo":99,"categoryName":100,"taxonomyType":101,"taxonomyTypeDesc":102},{"categoryNo":175,"categoryName":176,"taxonomyType":70,"taxonomyTypeDesc":71},"01JBSEEDCAT000000000000037","律师与法务",[178,179,180,181,76,182,183,33,184,138,185,186,187,188,189,89,190,191,192],"agent constitution","constitution","contracts","tree","query","base","log","check","Rules","projects","compliance","actions","state","governance","github"]