← 返回 Skills 市场
datadrivenconstruction

Estimate Builder

作者 datadrivenconstruction · GitHub ↗ · v2.1.0
darwinlinuxwin32 ✓ 安全检测通过
1611
总下载
0
收藏
2
当前安装
4
版本数
在 OpenClaw 中安装
/install estimate-builder
功能描述
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 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 publisher whether the skill needs to read/write local files (for importing/exporting estimates). If you don't want the skill to access your files or run local Python, either disable filesystem access for the skill or request a version without that permission. Also verify the publisher/homepage if you need a higher trust level (source is listed as unknown). Overall coherence is good, but these small mismatches warrant a quick clarification.
功能分析
Type: OpenClaw Skill Name: estimate-builder Version: 2.1.0 The skill bundle is benign. The Python code in SKILL.md implements a construction estimate builder, performing calculations and exporting data to Excel. The `claw.json` requests `filesystem` permission, which is necessary for the `export_to_excel` function. There is no evidence of intentional malicious behavior such as data exfiltration, arbitrary command execution, persistence mechanisms, or prompt injection attempts against the AI agent in `SKILL.md` or `instructions.md`. The functionality aligns with the stated purpose.
能力评估
Purpose & Capability
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 publisher.
Instruction Scope
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.
Install Mechanism
No install spec is present (instruction-only). This minimizes install-time risk because nothing is downloaded or written by an installer.
Credentials
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.
Persistence & Privilege
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.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install estimate-builder
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /estimate-builder 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v2.1.0
- Added homepage and metadata fields to SKILL.md for improved documentation and integration. - Metadata specifies supported operating systems, required binaries, and includes an emoji representation. - No changes to estimate-building logic or user-facing features.
v2.0.0
Estimate Builder 2.0.0 - Added claw.json and instructions.md files for improved documentation and integration. - Updated skill manifest from legacy fields (slug, display_name) to new format (name). - Expanded documentation and guidance for skill usage. - No functional changes to code; primary changes are in metadata and documentation structure.
v1.0.1
- Improved documentation with a detailed SKILL.md explaining purpose, features, and technical implementation. - No functional code changes documented for this version.
v1.0.0
Initial release of Estimate Builder. - Generate detailed construction project estimates with categorized costs for labor, materials, equipment, subcontractors, and other expenses. - Add, import, and export estimate line items; group by WBS code. - Apply standard and custom markups (overhead, profit, contingency) with flexible calculation bases. - Export estimates and breakdowns to Excel with summary sheets.
元数据
Slug estimate-builder
版本 2.1.0
许可证
累计安装 2
当前安装数 2
历史版本数 4
常见问题

Estimate Builder 是什么?

Build construction project estimates. Generate detailed cost breakdowns with labor, materials, equipment, and overhead. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 1611 次。

如何安装 Estimate Builder?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install estimate-builder」即可一键安装,无需额外配置。

Estimate Builder 是免费的吗?

是的,Estimate Builder 完全免费(开源免费),可自由下载、安装和使用。

Estimate Builder 支持哪些平台?

Estimate Builder 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(darwin, linux, win32)。

谁开发了 Estimate Builder?

由 datadrivenconstruction(@datadrivenconstruction)开发并维护,当前版本 v2.1.0。

💬 留言讨论