โ† All skills
Tencent SkillHub ยท Developer Tools

Auto Estimate Generator

Automatically generate estimates from QTO data. Apply pricing rules to BIM quantities for cost estimates.

skill openclawclawhub Free
0 Downloads
0 Stars
0 Installs
0 Score
High Signal

Automatically generate estimates from QTO data. Apply pricing rules to BIM quantities for cost estimates.

โฌ‡ 0 downloads โ˜… 0 stars Unverified but indexed

Install for OpenClaw

Quick setup
  1. Download the package from Yavira.
  2. Extract the archive and review SKILL.md first.
  3. Import or place the package into your OpenClaw setup.

Requirements

Target platform
OpenClaw
Install method
Manual import
Extraction
Extract archive
Prerequisites
OpenClaw
Primary doc
SKILL.md

Package facts

Download mode
Yavira redirect
Package format
ZIP package
Source platform
Tencent SkillHub
What's included
claw.json, instructions.md, SKILL.md

Validation

  • Use the Yavira download entry.
  • Review SKILL.md after the package is downloaded.
  • Confirm the extracted package contains the expected setup assets.

Install with your agent

Agent handoff

Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.

  1. Download the package from Yavira.
  2. Extract it into a folder your agent can access.
  3. Paste one of the prompts below and point your agent at the extracted folder.
New install

I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.

Upgrade existing

I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.

Trust & source

Release facts

Source
Tencent SkillHub
Verification
Indexed source record
Version
2.1.0

Documentation

ClawHub primary doc Primary doc: SKILL.md 8 sections Open source page

Problem Statement

Manual estimate creation challenges: Time-consuming quantity mapping Inconsistent pricing rules Errors in calculations Difficulty updating estimates

Solution

Automated estimate generation from BIM/QTO data using configurable pricing rules and assembly mappings.

Technical Implementation

import pandas as pd from typing import Dict, Any, List, Optional, Callable from dataclasses import dataclass, field from enum import Enum class ElementType(Enum): WALL = "wall" FLOOR = "floor" CEILING = "ceiling" DOOR = "door" WINDOW = "window" COLUMN = "column" BEAM = "beam" FOUNDATION = "foundation" ROOF = "roof" STAIR = "stair" MEP = "mep" @dataclass class QTOItem: element_id: str element_type: ElementType name: str quantity: float unit: str properties: Dict[str, Any] = field(default_factory=dict) @dataclass class PricingRule: rule_id: str name: str element_type: ElementType conditions: Dict[str, Any] = field(default_factory=dict) unit_cost: float = 0 assembly_code: str = "" cost_breakdown: Dict[str, float] = field(default_factory=dict) @dataclass class EstimateItem: qto_element_id: str description: str quantity: float unit: str unit_cost: float total_cost: float rule_applied: str wbs_code: str = "" class AutoEstimateGenerator: """Generate estimates from QTO data automatically.""" def __init__(self, project_name: str): self.project_name = project_name self.pricing_rules: List[PricingRule] = [] self.qto_items: List[QTOItem] = [] self.estimate_items: List[EstimateItem] = [] self.unmapped_items: List[QTOItem] = [] def add_pricing_rule(self, rule: PricingRule): """Add pricing rule.""" self.pricing_rules.append(rule) def load_pricing_rules_from_df(self, df: pd.DataFrame): """Load pricing rules from DataFrame.""" for _, row in df.iterrows(): conditions = {} if 'material' in row: conditions['material'] = row['material'] if 'thickness_min' in row: conditions['thickness_min'] = row['thickness_min'] if 'thickness_max' in row: conditions['thickness_max'] = row['thickness_max'] rule = PricingRule( rule_id=row['rule_id'], name=row['name'], element_type=ElementType(row['element_type'].lower()), conditions=conditions, unit_cost=float(row['unit_cost']), assembly_code=row.get('assembly_code', ''), cost_breakdown={ 'labor': float(row.get('labor_pct', 0.4)), 'material': float(row.get('material_pct', 0.5)), 'equipment': float(row.get('equipment_pct', 0.1)) } ) self.add_pricing_rule(rule) def load_qto_from_df(self, df: pd.DataFrame): """Load QTO items from DataFrame.""" for _, row in df.iterrows(): properties = {} for col in df.columns: if col not in ['element_id', 'element_type', 'name', 'quantity', 'unit']: properties[col] = row[col] qto = QTOItem( element_id=str(row['element_id']), element_type=ElementType(row['element_type'].lower()), name=row['name'], quantity=float(row['quantity']), unit=row['unit'], properties=properties ) self.qto_items.append(qto) def find_matching_rule(self, qto_item: QTOItem) -> Optional[PricingRule]: """Find pricing rule that matches QTO item.""" matching_rules = [] for rule in self.pricing_rules: if rule.element_type != qto_item.element_type: continue # Check conditions match = True for key, value in rule.conditions.items(): if key.endswith('_min'): prop_name = key[:-4] if prop_name in qto_item.properties: if qto_item.properties[prop_name] < value: match = False elif key.endswith('_max'): prop_name = key[:-4] if prop_name in qto_item.properties: if qto_item.properties[prop_name] > value: match = False else: if key in qto_item.properties: if qto_item.properties[key] != value: match = False if match: matching_rules.append(rule) # Return most specific rule (most conditions) if matching_rules: return max(matching_rules, key=lambda r: len(r.conditions)) return None def generate_estimate(self) -> Dict[str, Any]: """Generate estimate from QTO items.""" self.estimate_items = [] self.unmapped_items = [] total_cost = 0 for qto in self.qto_items: rule = self.find_matching_rule(qto) if rule: item_cost = qto.quantity * rule.unit_cost self.estimate_items.append(EstimateItem( qto_element_id=qto.element_id, description=f"{qto.name} ({rule.name})", quantity=qto.quantity, unit=qto.unit, unit_cost=rule.unit_cost, total_cost=round(item_cost, 2), rule_applied=rule.rule_id, wbs_code=rule.assembly_code )) total_cost += item_cost else: self.unmapped_items.append(qto) return { 'project': self.project_name, 'total_qto_items': len(self.qto_items), 'mapped_items': len(self.estimate_items), 'unmapped_items': len(self.unmapped_items), 'mapping_rate': round(len(self.estimate_items) / len(self.qto_items) * 100, 1) if self.qto_items else 0, 'total_cost': round(total_cost, 2), 'items': self.estimate_items } def get_cost_by_element_type(self) -> Dict[str, float]: """Get cost breakdown by element type.""" by_type = {} for qto in self.qto_items: for est_item in self.estimate_items: if est_item.qto_element_id == qto.element_id: type_name = qto.element_type.value by_type[type_name] = by_type.get(type_name, 0) + est_item.total_cost return {k: round(v, 2) for k, v in by_type.items()} def get_unmapped_summary(self) -> pd.DataFrame: """Get summary of unmapped items.""" if not self.unmapped_items: return pd.DataFrame() data = [] for item in self.unmapped_items: data.append({ 'Element ID': item.element_id, 'Type': item.element_type.value, 'Name': item.name, 'Quantity': item.quantity, 'Unit': item.unit, 'Properties': str(item.properties) }) return pd.DataFrame(data) def export_to_excel(self, output_path: str) -> str: """Export estimate to Excel.""" result = self.generate_estimate() with pd.ExcelWriter(output_path, engine='openpyxl') as writer: # Summary summary_df = pd.DataFrame([{ 'Project': self.project_name, 'Total QTO Items': result['total_qto_items'], 'Mapped Items': result['mapped_items'], 'Unmapped Items': result['unmapped_items'], 'Mapping Rate %': result['mapping_rate'], 'Total Cost': result['total_cost'] }]) summary_df.to_excel(writer, sheet_name='Summary', index=False) # Estimate items items_df = pd.DataFrame([{ 'Element ID': item.qto_element_id, 'Description': item.description, 'Quantity': item.quantity, 'Unit': item.unit, 'Unit Cost': item.unit_cost, 'Total Cost': item.total_cost, 'WBS': item.wbs_code, 'Rule': item.rule_applied } for item in self.estimate_items]) items_df.to_excel(writer, sheet_name='Estimate', index=False) # By element type by_type_df = pd.DataFrame([ {'Element Type': k, 'Cost': v} for k, v in self.get_cost_by_element_type().items() ]) by_type_df.to_excel(writer, sheet_name='By Type', index=False) # Unmapped items unmapped_df = self.get_unmapped_summary() if not unmapped_df.empty: unmapped_df.to_excel(writer, sheet_name='Unmapped', index=False) return output_path def suggest_missing_rules(self) -> List[Dict[str, Any]]: """Suggest pricing rules for unmapped items.""" suggestions = [] seen_types = set() for item in self.unmapped_items: key = (item.element_type.value, str(item.properties)) if key not in seen_types: seen_types.add(key) suggestions.append({ 'element_type': item.element_type.value, 'sample_name': item.name, 'properties': item.properties, 'count': sum(1 for i in self.unmapped_items if i.element_type == item.element_type and str(i.properties) == str(item.properties)) }) return sorted(suggestions, key=lambda x: x['count'], reverse=True)

Quick Start

# Initialize generator generator = AutoEstimateGenerator("Office Building A") # Add pricing rules generator.add_pricing_rule(PricingRule( rule_id="W-001", name="Interior Wall - Drywall", element_type=ElementType.WALL, conditions={"material": "Drywall"}, unit_cost=45.00, assembly_code="09.29.10" )) generator.add_pricing_rule(PricingRule( rule_id="W-002", name="Exterior Wall - Masonry", element_type=ElementType.WALL, conditions={"material": "Masonry"}, unit_cost=125.00, assembly_code="04.21.13" )) # Load QTO data generator.qto_items = [ QTOItem("W-001", ElementType.WALL, "Interior Wall L1", 500, "SF", {"material": "Drywall"}), QTOItem("W-002", ElementType.WALL, "Exterior Wall", 1200, "SF", {"material": "Masonry"}) ] # Generate estimate result = generator.generate_estimate() print(f"Total Cost: ${result['total_cost']:,.2f}") print(f"Mapping Rate: {result['mapping_rate']}%")

1. Cost by Element Type

by_type = generator.get_cost_by_element_type() for element_type, cost in by_type.items(): print(f"{element_type}: ${cost:,.2f}")

2. Unmapped Items

unmapped = generator.get_unmapped_summary() print(unmapped)

3. Rule Suggestions

suggestions = generator.suggest_missing_rules() for s in suggestions: print(f"Need rule for: {s['element_type']} ({s['count']} items)")

Resources

DDC Book: Chapter 3.2 - QTO and Automated Estimates Website: https://datadrivenconstruction.io

Category context

Code helpers, APIs, CLIs, browser automation, testing, and developer operations.

Source: Tencent SkillHub

Largest current source with strong distribution and engagement signals.

Package contents

Included in package
2 Docs1 Config
  • SKILL.md Primary doc
  • instructions.md Docs
  • claw.json Config