技能详情(站内镜像,无评论)
许可证:MIT-0
MIT-0 ·免费使用、修改和重新分发。无需归因。
版本:v2.1.0
统计:⭐ 0 · 1.2k · 1 current installs · 1 all-time installs
⭐ 0
安装量(当前) 1
🛡 VirusTotal :良性 · OpenClaw :良性
Package:datadrivenconstruction/estimate-builder
安全扫描(ClawHub)
- VirusTotal :良性
- OpenClaw :良性
OpenClaw 评估
The skill's stated purpose (building construction estimates) matches its instructions and has no code or network calls, but there are minor mismatches (python3 and filesystem permission declared despite being instruction-only) worth confirming before install.
目的
Name/description and the SKILL.md/instructions describe an estimate builder and the required behaviors (collect items, apply markups, calculate totals). That purpose is coherent. However, the metadata requires python3 and claw.json lists a filesystem permission even though the published package is instruction-only with no runnable code files; those requirements are disproportionate to an instructions-only skill and should be justified by the p…
说明范围
Runtime instructions are narrowly scoped to collecting project/line-item data, validating inputs, computing cost summaries and markups, and presenting results. They do not instruct reading arbitrary system files, accessing environment variables, or transmitting data to external endpoints.
安装机制
No install spec is present (instruction-only). This minimizes install-time risk because nothing is downloaded or written by an installer.
证书
The skill declares no required environment variables or credentials (good). But the claw.json lists 'permissions': ['filesystem'] and SKILL metadata lists python3 as a required binary; for an instruction-only skill with no code files, filesystem access and a python3 requirement appear excessive unless the agent/platform will execute the included Python snippets or write/read estimate files locally—this should be clarified.
持久
always is false and the skill does not request elevated or persistent platform privileges. Autonomous invocation (disable-model-invocation false) is the platform default and is not itself a concern here.
综合结论
This skill appears to do what it says: generate construction estimates from user-provided line items. Before installing, confirm two small inconsistencies: (1) why does the metadata require python3 when there are no executable code files included? If your agent platform might execute Python snippets or run local scripts, requiring python3 makes sense; otherwise it may be unnecessary. (2) claw.json declares filesystem permission — ask the publi…
安装(复制给龙虾 AI)
将下方整段复制到龙虾中文库对话中,由龙虾按 SKILL.md 完成安装。
请把本段交给龙虾中文库(龙虾 AI)执行:为本机安装 OpenClaw 技能「Estimate Builder」。简介:Build construction project estimates. Generate detailed cost breakdowns with la…。
请 fetch 以下地址读取 SKILL.md 并按文档完成安装:https://raw.githubusercontent.com/openclaw/skills/refs/heads/main/skills/datadrivenconstruction/estimate-builder/SKILL.md
(来源:yingzhi8.cn 技能库)
SKILL.md
---
name: "estimate-builder"
description: "Build construction project estimates. Generate detailed cost breakdowns with labor, materials, equipment, and overhead."
homepage: "https://datadrivenconstruction.io"
metadata: {"openclaw":{"emoji":"📊","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":["python3"]}}}
---
# Estimate Builder
## Business Case
### Problem Statement
Estimate creation challenges:
- Complex cost structures
- Multiple cost categories
- Markup calculations
- Format requirements vary
### Solution
Structured estimate builder that creates professional construction estimates with proper cost categorization, markups, and export capabilities.
## Technical Implementation
```python
import pandas as pd
from typing import Dict, Any, List, Optional
from dataclasses import dataclass, field
from datetime import date
from enum import Enum
class CostCategory(Enum):
LABOR = "labor"
MATERIAL = "material"
EQUIPMENT = "equipment"
SUBCONTRACTOR = "subcontractor"
OTHER = "other"
@dataclass
class EstimateLineItem:
line_number: int
wbs_code: str
description: str
quantity: float
unit: str
unit_cost: float
category: CostCategory
notes: str = ""
@property
def total_cost(self) -> float:
return round(self.quantity * self.unit_cost, 2)
@dataclass
class CostSummary:
labor: float = 0
material: float = 0
equipment: float = 0
subcontractor: float = 0
other: float = 0
@property
def direct_cost(self) -> float:
return self.labor + self.material + self.equipment + self.subcontractor + self.other
@dataclass
class Markup:
name: str
rate: float # As decimal (0.10 = 10%)
base: str = "direct" # "direct" or "subtotal"
class EstimateBuilder:
"""Build construction project estimates."""
def __init__(self, project_name: str, project_number: str = ""):
self.project_name = project_name
self.project_number = project_number
self.estimate_date = date.today()
self.items: List[EstimateLineItem] = []
self.markups: List[Markup] = []
self._next_line = 1
def add_item(self,
wbs_code: str,
description: str,
quantity: float,
unit: str,
unit_cost: float,
category: CostCategory = CostCategory.OTHER,
notes: str = "") -> EstimateLineItem:
"""Add line item to estimate."""
item = EstimateLineItem(
line_number=self._next_line,
wbs_code=wbs_code,
description=description,
quantity=quantity,
unit=unit,
unit_cost=unit_cost,
category=category,
notes=notes
)
self.items.append(item)
self._next_line += 1
return item
def add_markup(self, name: str, rate: float, base: str = "direct"):
"""Add markup (overhead, profit, contingency, etc.)."""
self.markups.append(Markup(name=name, rate=rate, base=base))
def set_standard_markups(self,
overhead: float = 0.15,
profit: float = 0.10,
contingency: float = 0.05):
"""Set standard construction markups."""
self.markups = [
Markup("General Conditions / Overhead", overhead, "direct"),
Markup("Profit", profit, "subtotal"),
Markup("Contingency", contingency, "subtotal")
]
def get_cost_summary(self) -> CostSummary:
"""Get cost summary by category."""
summary = CostSummary()
for item in self.items:
cost = item.total_cost
if item.category == CostCategory.LABOR:
summary.labor += cost
elif item.category == CostCategory.MATERIAL:
summary.material += cost
elif item.category == CostCategory.EQUIPMENT:
summary.equipment += cost
elif item.category == CostCategory.SUBCONTRACTOR:
summary.subcontractor += cost
else:
summary.other += cost
return summary
def calculate_total(self) -> Dict[str, Any]:
"""Calculate total estimate with markups."""
summary = self.get_cost_summary()
direct_cost = summary.direct_cost
markups_detail = []
subtotal = direct_cost
for markup in self.markups:
if markup.base == "direct":
amount = direct_cost * markup.rate
else:
amount = subtotal * markup.rate
markups_detail.append({
'name': markup.name,
'rate': f"{markup.rate * 100:.1f}%",
'amount': round(amount, 2)
})
subtotal += amount
return {
'cost_summary': {
'labor': round(summary.labor, 2),
'material': round(summary.material, 2),
'equipment': round(summary.equipment, 2),
'subcontractor': round(summary.subcontractor, 2),
'other': round(summary.other, 2),
'direct_cost': round(direct_cost, 2)
},
'markups': markups_detail,
'total_markups': round(subtotal - direct_cost, 2),
'grand_total': round(subtotal, 2)
}
def get_items_by_wbs(self) -> Dict[str, List[EstimateLineItem]]:
"""Group items by WBS code prefix."""
by_wbs = {}
for item in self.items:
prefix = item.wbs_code.split('.')[0] if '.' in item.wbs_code else item.wbs_code
if prefix not in by_wbs:
by_wbs[prefix] = []
by_wbs[prefix].append(item)
return by_wbs
def import_from_df(self, df: pd.DataFrame):
"""Import line items from DataFrame."""
for _, row in df.iterrows():
self.add_item(
wbs_code=str(row.get('wbs_code', '')),
description=row['description'],
quantity=float(row['quantity']),
unit=row['unit'],
unit_cost=float(row['unit_cost']),
category=CostCategory(row.get('category', 'other').lower()),
notes=row.get('notes', '')
)
def export_to_df(self) -> pd.DataFrame:
"""Export estimate to DataFrame."""
data = []
for item in self.items:
data.append({
'Line': item.line_number,
'WBS': item.wbs_code,
'Description': item.description,
'Qty': item.quantity,
'Unit': item.unit,
'Unit Cost': item.unit_cost,
'Total': item.total_cost,
'Category': item.category.value,
'Notes': item.notes
})
return pd.DataFrame(data)
def export_to_excel(self, output_path: str) -> str:
"""Export estimate to Excel."""
totals = self.calculate_total()
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# Cover sheet
cover_df = pd.DataFrame([{
'Project Name': self.project_name,
'Project Number': self.project_number,
'Estimate Date': self.estimate_date,
'Total Items': len(self.items),
'Direct Cost': totals['cost_summary']['direct_cost'],
'Grand Total': totals['grand_total']
}])
cover_df.to_excel(writer, sheet_name='Summary', index=False)
# Line items
items_df = self.export_to_df()
items_df.to_excel(writer, sheet_name='Line Items', index=False)
# Cost breakdown
breakdown_df = pd.DataFrame([totals['cost_summary']])
breakdown_df.to_excel(writer, sheet_name='Cost Breakdown', index=False)
# Markups
if totals['markups']:
markups_df = pd.DataFrame(totals['markups'])
markups_df.to_excel(writer, sheet_name='Markups', index=False)
return output_path
def validate(self) -> List[str]:
"""Validate estimate for common issues."""
issues = []
if not self.items:
issues.append("Estimate has no line items")
for item in self.items:
if item.quantity <= 0:
issues.append(f"Line {item.line_number}: Invalid quantity")
if item.unit_cost < 0:
issues.append(f"Line {item.line_number}: Negative unit cost")
if not item.description:
issues.append(f"Line {item.line_number}: Missing description")
if not self.markups:
issues.append("No markups defined (overhead, profit)")
return issues
```
## Quick Start
```python
# Create estimate
estimate = EstimateBuilder("Office Building A", "PRJ-2024-001")
# Add line items
estimate.add_item("01.01", "Site Preparation", 5000, "SF", 2.50, CostCategory.OTHER)
estimate.add_item("03.01", "Concrete Foundation", 200, "CY", 350, CostCategory.MATERIAL)
estimate.add_item("03.02", "Foundation Formwork", 1500, "SF", 8.50, CostCategory.LABOR)
estimate.add_item("05.01", "Structural Steel", 50, "TON", 4500, CostCategory.SUBCONTRACTOR)
# Set markups
estimate.set_standard_markups(overhead=0.15, profit=0.10, contingency=0.05)
# Calculate total
result = estimate.calculate_total()
print(f"Direct Cost: ${result['cost_summary']['direct_cost']:,.2f}")
print(f"Grand Total: ${result['grand_total']:,.2f}")
```
## Common Use Cases
### 1. Cost by Category
```python
summary = estimate.get_cost_summary()
print(f"Labor: ${summary.labor:,.2f}")
print(f"Material: ${summary.material:,.2f}")
```
### 2. Export to Excel
```python
estimate.export_to_excel("estimate_output.xlsx")
```
### 3. Validate Estimate
```python
issues = estimate.validate()
for issue in issues:
print(f"Warning: {issue}")
```
## Resources
- **DDC Book**: Chapter 3.1 - Cost Calculations and Estimates
- **Website**: https://datadrivenconstruction.io