← 返回 Skills 市场
604
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install estimate-builder-qmohd
功能描述
Build construction project estimates. Generate detailed cost breakdowns with labor, materials, equipment, and overhead.
使用说明 (SKILL.md)
\r \r
Estimate Builder\r
\r
Business Case\r
\r
Problem Statement\r
Estimate creation challenges:\r
- Complex cost structures\r
- Multiple cost categories\r
- Markup calculations\r
- Format requirements vary\r \r
Solution\r
Structured estimate builder that creates professional construction estimates with proper cost categorization, markups, and export capabilities.\r \r
Technical Implementation\r
\r
import pandas as pd\r
from typing import Dict, Any, List, Optional\r
from dataclasses import dataclass, field\r
from datetime import date\r
from enum import Enum\r
\r
\r
class CostCategory(Enum):\r
LABOR = "labor"\r
MATERIAL = "material"\r
EQUIPMENT = "equipment"\r
SUBCONTRACTOR = "subcontractor"\r
OTHER = "other"\r
\r
\r
@dataclass\r
class EstimateLineItem:\r
line_number: int\r
wbs_code: str\r
description: str\r
quantity: float\r
unit: str\r
unit_cost: float\r
category: CostCategory\r
notes: str = ""\r
\r
@property\r
def total_cost(self) -> float:\r
return round(self.quantity * self.unit_cost, 2)\r
\r
\r
@dataclass\r
class CostSummary:\r
labor: float = 0\r
material: float = 0\r
equipment: float = 0\r
subcontractor: float = 0\r
other: float = 0\r
\r
@property\r
def direct_cost(self) -> float:\r
return self.labor + self.material + self.equipment + self.subcontractor + self.other\r
\r
\r
@dataclass\r
class Markup:\r
name: str\r
rate: float # As decimal (0.10 = 10%)\r
base: str = "direct" # "direct" or "subtotal"\r
\r
\r
class EstimateBuilder:\r
"""Build construction project estimates."""\r
\r
def __init__(self, project_name: str, project_number: str = ""):\r
self.project_name = project_name\r
self.project_number = project_number\r
self.estimate_date = date.today()\r
self.items: List[EstimateLineItem] = []\r
self.markups: List[Markup] = []\r
self._next_line = 1\r
\r
def add_item(self,\r
wbs_code: str,\r
description: str,\r
quantity: float,\r
unit: str,\r
unit_cost: float,\r
category: CostCategory = CostCategory.OTHER,\r
notes: str = "") -> EstimateLineItem:\r
"""Add line item to estimate."""\r
\r
item = EstimateLineItem(\r
line_number=self._next_line,\r
wbs_code=wbs_code,\r
description=description,\r
quantity=quantity,\r
unit=unit,\r
unit_cost=unit_cost,\r
category=category,\r
notes=notes\r
)\r
self.items.append(item)\r
self._next_line += 1\r
return item\r
\r
def add_markup(self, name: str, rate: float, base: str = "direct"):\r
"""Add markup (overhead, profit, contingency, etc.)."""\r
self.markups.append(Markup(name=name, rate=rate, base=base))\r
\r
def set_standard_markups(self,\r
overhead: float = 0.15,\r
profit: float = 0.10,\r
contingency: float = 0.05):\r
"""Set standard construction markups."""\r
\r
self.markups = [\r
Markup("General Conditions / Overhead", overhead, "direct"),\r
Markup("Profit", profit, "subtotal"),\r
Markup("Contingency", contingency, "subtotal")\r
]\r
\r
def get_cost_summary(self) -> CostSummary:\r
"""Get cost summary by category."""\r
\r
summary = CostSummary()\r
for item in self.items:\r
cost = item.total_cost\r
if item.category == CostCategory.LABOR:\r
summary.labor += cost\r
elif item.category == CostCategory.MATERIAL:\r
summary.material += cost\r
elif item.category == CostCategory.EQUIPMENT:\r
summary.equipment += cost\r
elif item.category == CostCategory.SUBCONTRACTOR:\r
summary.subcontractor += cost\r
else:\r
summary.other += cost\r
return summary\r
\r
def calculate_total(self) -> Dict[str, Any]:\r
"""Calculate total estimate with markups."""\r
\r
summary = self.get_cost_summary()\r
direct_cost = summary.direct_cost\r
\r
markups_detail = []\r
subtotal = direct_cost\r
\r
for markup in self.markups:\r
if markup.base == "direct":\r
amount = direct_cost * markup.rate\r
else:\r
amount = subtotal * markup.rate\r
\r
markups_detail.append({\r
'name': markup.name,\r
'rate': f"{markup.rate * 100:.1f}%",\r
'amount': round(amount, 2)\r
})\r
subtotal += amount\r
\r
return {\r
'cost_summary': {\r
'labor': round(summary.labor, 2),\r
'material': round(summary.material, 2),\r
'equipment': round(summary.equipment, 2),\r
'subcontractor': round(summary.subcontractor, 2),\r
'other': round(summary.other, 2),\r
'direct_cost': round(direct_cost, 2)\r
},\r
'markups': markups_detail,\r
'total_markups': round(subtotal - direct_cost, 2),\r
'grand_total': round(subtotal, 2)\r
}\r
\r
def get_items_by_wbs(self) -> Dict[str, List[EstimateLineItem]]:\r
"""Group items by WBS code prefix."""\r
\r
by_wbs = {}\r
for item in self.items:\r
prefix = item.wbs_code.split('.')[0] if '.' in item.wbs_code else item.wbs_code\r
if prefix not in by_wbs:\r
by_wbs[prefix] = []\r
by_wbs[prefix].append(item)\r
return by_wbs\r
\r
def import_from_df(self, df: pd.DataFrame):\r
"""Import line items from DataFrame."""\r
\r
for _, row in df.iterrows():\r
self.add_item(\r
wbs_code=str(row.get('wbs_code', '')),\r
description=row['description'],\r
quantity=float(row['quantity']),\r
unit=row['unit'],\r
unit_cost=float(row['unit_cost']),\r
category=CostCategory(row.get('category', 'other').lower()),\r
notes=row.get('notes', '')\r
)\r
\r
def export_to_df(self) -> pd.DataFrame:\r
"""Export estimate to DataFrame."""\r
\r
data = []\r
for item in self.items:\r
data.append({\r
'Line': item.line_number,\r
'WBS': item.wbs_code,\r
'Description': item.description,\r
'Qty': item.quantity,\r
'Unit': item.unit,\r
'Unit Cost': item.unit_cost,\r
'Total': item.total_cost,\r
'Category': item.category.value,\r
'Notes': item.notes\r
})\r
return pd.DataFrame(data)\r
\r
def export_to_excel(self, output_path: str) -> str:\r
"""Export estimate to Excel."""\r
\r
totals = self.calculate_total()\r
\r
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:\r
# Cover sheet\r
cover_df = pd.DataFrame([{\r
'Project Name': self.project_name,\r
'Project Number': self.project_number,\r
'Estimate Date': self.estimate_date,\r
'Total Items': len(self.items),\r
'Direct Cost': totals['cost_summary']['direct_cost'],\r
'Grand Total': totals['grand_total']\r
}])\r
cover_df.to_excel(writer, sheet_name='Summary', index=False)\r
\r
# Line items\r
items_df = self.export_to_df()\r
items_df.to_excel(writer, sheet_name='Line Items', index=False)\r
\r
# Cost breakdown\r
breakdown_df = pd.DataFrame([totals['cost_summary']])\r
breakdown_df.to_excel(writer, sheet_name='Cost Breakdown', index=False)\r
\r
# Markups\r
if totals['markups']:\r
markups_df = pd.DataFrame(totals['markups'])\r
markups_df.to_excel(writer, sheet_name='Markups', index=False)\r
\r
return output_path\r
\r
def validate(self) -> List[str]:\r
"""Validate estimate for common issues."""\r
\r
issues = []\r
\r
if not self.items:\r
issues.append("Estimate has no line items")\r
\r
for item in self.items:\r
if item.quantity \x3C= 0:\r
issues.append(f"Line {item.line_number}: Invalid quantity")\r
if item.unit_cost \x3C 0:\r
issues.append(f"Line {item.line_number}: Negative unit cost")\r
if not item.description:\r
issues.append(f"Line {item.line_number}: Missing description")\r
\r
if not self.markups:\r
issues.append("No markups defined (overhead, profit)")\r
\r
return issues\r
```\r
\r
## Quick Start\r
\r
```python\r
# Create estimate\r
estimate = EstimateBuilder("Office Building A", "PRJ-2024-001")\r
\r
# Add line items\r
estimate.add_item("01.01", "Site Preparation", 5000, "SF", 2.50, CostCategory.OTHER)\r
estimate.add_item("03.01", "Concrete Foundation", 200, "CY", 350, CostCategory.MATERIAL)\r
estimate.add_item("03.02", "Foundation Formwork", 1500, "SF", 8.50, CostCategory.LABOR)\r
estimate.add_item("05.01", "Structural Steel", 50, "TON", 4500, CostCategory.SUBCONTRACTOR)\r
\r
# Set markups\r
estimate.set_standard_markups(overhead=0.15, profit=0.10, contingency=0.05)\r
\r
# Calculate total\r
result = estimate.calculate_total()\r
print(f"Direct Cost: ${result['cost_summary']['direct_cost']:,.2f}")\r
print(f"Grand Total: ${result['grand_total']:,.2f}")\r
```\r
\r
## Common Use Cases\r
\r
### 1. Cost by Category\r
```python\r
summary = estimate.get_cost_summary()\r
print(f"Labor: ${summary.labor:,.2f}")\r
print(f"Material: ${summary.material:,.2f}")\r
```\r
\r
### 2. Export to Excel\r
```python\r
estimate.export_to_excel("estimate_output.xlsx")\r
```\r
\r
### 3. Validate Estimate\r
```python\r
issues = estimate.validate()\r
for issue in issues:\r
print(f"Warning: {issue}")\r
```\r
\r
## Resources\r
- **DDC Book**: Chapter 3.1 - Cost Calculations and Estimates\r
- **Website**: https://datadrivenconstruction.io\r
安全使用建议
This skill appears to implement exactly what it claims (building estimates), but there are a few red flags to check before installing:
- Verify origin and ownership: the registry metadata and the included files contain different ownerId/slug/version values. Confirm the publisher and homepage (https://datadrivenconstruction.io) are trustworthy.
- Review the need for filesystem access: claw.json requests filesystem permission. If you don't need local export/import of estimate files, avoid granting filesystem permission. If you do grant it, prefer running in a restricted environment or sandbox.
- Inspect/preview the embedded Python code before executing it locally. The skill is instruction-only, but the agent could be instructed to execute code snippets — make sure you understand what will run.
- Because there are no required credentials, the immediate exposure of secrets is low, but arbitrary filesystem access can still leak sensitive files. Consider testing in an isolated account or VM.
If you want a safer install: ask the skill author to remove the filesystem permission (or document precisely why export requires it), and resolve the metadata inconsistencies so you can verify the publisher.
功能分析
Type: OpenClaw Skill
Name: estimate-builder-qmohd
Version: 1.0.1
The skill is classified as suspicious due to a potential arbitrary file write vulnerability. The `export_to_excel` function in `SKILL.md` takes an `output_path` argument and writes an Excel file to it. Combined with the explicit `filesystem` permission requested in `claw.json`, this allows the skill to write files to arbitrary locations on the system if the `output_path` is not properly sanitized or restricted by the OpenClaw agent, posing a risk of overwriting critical files or achieving persistence. While this is a significant vulnerability, there is no clear evidence of intentional malicious behavior such as data exfiltration or backdoor installation.
能力评估
Purpose & Capability
Name/description and the instruction content (collect line items, apply markups, produce summaries) are coherent with an estimating tool. The SKILL.md embeds Python example code and the manifest requires python3, which is reasonable for a code-based assistant. However the manifest metadata (ownerId, slug, and version) in included files does not match the registry metadata provided, which is an inconsistency worth investigating.
Instruction Scope
Runtime instructions ask the agent only to gather project details, validate line items, calculate category summaries and markups, and present results. There are no instructions to read unrelated system files, access environment secrets, or exfiltrate data to external endpoints.
Install Mechanism
This is an instruction-only skill with no install spec and no code files to run from a remote URL — lowest-risk install mechanism. It does include Python example code but does not automatically install anything.
Credentials
The skill declares a permissions entry of ["filesystem"] in claw.json, but requires no environment variables or config paths. The SKILL.md does not clearly require filesystem access (it mentions 'export capabilities' in the description but gives no explicit export instructions). Granting filesystem access would allow reading/writing files beyond the skill's evident needs; this is disproportionate unless you require local export of estimate files.
Persistence & Privilege
always is false and the skill is user-invocable; autonomous invocation is allowed (platform default). There is no request to modify other skills or system-wide configs. No extra persistence or privileged flags are present.
如何使用
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install estimate-builder-qmohd - 安装完成后,直接呼叫该 Skill 的名称或使用
/estimate-builder-qmohd触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.1
Initial release of estimate-builder.
- Build construction project estimates with detailed cost breakdowns for labor, materials, equipment, and overhead.
- Add and categorize estimate line items.
- Apply multiple markups (overhead, profit, contingency) on direct or subtotal costs.
- Group items by WBS code.
- Import and export estimates to/from pandas DataFrames.
- Export estimates to Excel for reporting and sharing.
元数据
常见问题
Estimate Builder 是什么?
Build construction project estimates. Generate detailed cost breakdowns with labor, materials, equipment, and overhead. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 604 次。
如何安装 Estimate Builder?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install estimate-builder-qmohd」即可一键安装,无需额外配置。
Estimate Builder 是免费的吗?
是的,Estimate Builder 完全免费(开源免费),可自由下载、安装和使用。
Estimate Builder 支持哪些平台?
Estimate Builder 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(darwin, linux, win32)。
谁开发了 Estimate Builder?
由 qmohd(@qmohd)开发并维护,当前版本 v1.0.1。
推荐 Skills