Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Track and analyze historical cost data using CWICR. Compare actual vs estimated costs, build project cost database, and improve future estimates.
.claude/skills/datadrivenconstruction-cwicr-historical-cost/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 387% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 120% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 147% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 138% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 173% | 0% |
Improving estimates requires:
Track actual costs against CWICR estimates, build historical database, and use data to improve future estimating accuracy.
pythonimport pandas as pd import numpy as np from typing import Dict, Any, List, Optional from dataclasses import dataclass, field from datetime import datetime, date from enum import Enum import json class ProjectStatus(Enum): """Project status.""" ESTIMATED = "estimated" IN_PROGRESS = "in_progress" COMPLETED = "completed" CANCELLED = "cancelled" @dataclass class CostRecord: """Historical cost record.""" project_id: str project_name: str work_item_code: str quantity: float estimated_cost: float actual_cost: float variance: float variance_percent: float completion_date: date notes: str = "" @dataclass class ProjectCostSummary: """Project cost summary.""" project_id: str project_name: str project_type: str location: str status: ProjectStatus estimated_total: float actual_total: float variance: float variance_percent: float start_date: date completion_date: Optional[date] item_count: int class CWICRHistoricalCost: """Track historical costs using CWICR data.""" def __init__(self, cwicr_data: pd.DataFrame = None): self.cwicr = cwicr_data self._projects: Dict[str, ProjectCostSummary] = {} self._records: List[CostRecord] = [] if cwicr_data is not None: self._index_cwicr() def _index_cwicr(self): """Index CWICR data.""" if 'work_item_code' in self.cwicr.columns: self._cwicr_index = self.cwicr.set_index('work_item_code') else: self._cwicr_index = None def add_project(self, project_id: str, project_name: str, project_type: str, location: str, estimated_total: float, start_date: date) -> str: """Add new project to historical database.""" summary = ProjectCostSummary( project_id=project_id, project_name=project_name, project_type=project_type, location=location, status=ProjectStatus.ESTIMATED, estimated_total=estimated_total, actual_total=0, variance=0, variance_percent=0, start_date=start_date, completion_date=None, item_count=0 ) self._projects[project_id] = summary return project_id def record_actual_cost(self, project_id: str, work_item_code: str, quantity: float, actual_cost: float, completion_date: date = None, notes: str = "") -> CostRecord: """Record actual cost for work item.""" # Get estimated cost from CWICR estimated_unit_cost = 0 if self._cwicr_index is not None and work_item_code in self._cwicr_index.index: item = self._cwicr_index.loc[work_item_code] labor = float(item.get('labor_cost', 0) or 0) material = float(item.get('material_cost', 0) or 0) equipment = float(item.get('equipment_cost', 0) or 0) estimated_unit_cost = labor + material + equipment estimated_cost = estimated_unit_cost * quantity variance = actual_cost - estimated_cost variance_pct = (variance / estimated_cost * 100) if estimated_cost > 0 else 0 record = CostRecord( project_id=project_id, project_name=self._projects.get(project_id, {}).project_name if project_id in self._projects else "", work_item_code=work_item_code, quantity=quantity, estimated_cost=round(estimated_cost, 2), actual_cost=round(actual_cost, 2), variance=round(variance, 2), variance_percent=round(variance_pct, 1), completion_date=completion_date or date.today(), notes=notes ) self._records.append(record) # Update project summary if project_id in self._projects: proj = self._projects[project_id] proj.actual_total += actual_cost proj.variance = proj.actual_total - proj.estimated_total proj.variance_percent = (proj.variance / proj.estimated_total * 100) if proj.estimated_total > 0 else 0 proj.item_count += 1 proj.status = ProjectStatus.IN_PROGRESS return record def complete_project(self, project_id: str, completion_date: date = None): """Mark project as completed.""" if project_id in self._projects: self._projects[project_id].status = ProjectStatus.COMPLETED self._projects[project_id].completion_date = completion_date or date.today() def get_work_item_history(self, work_item_code: str) -> Dict[str, Any]: """Get historical data for specific work item.""" records = [r for r in self._records if r.work_item_code == work_item_code] if not records: return {'work_item_code': work_item_code, 'records': 0} variances = [r.variance_percent for r in records] actual_costs = [r.actual_cost / r.quantity if r.quantity > 0 else 0 for r in records] return { 'work_item_code': work_item_code, 'records': len(records), 'average_variance_pct': round(np.mean(variances), 1), 'variance_std': round(np.std(variances), 1), 'average_actual_unit_cost': round(np.mean(actual_costs), 2), 'min_actual_unit_cost': round(min(actual_costs), 2), 'max_actual_unit_cost': round(max(actual_costs), 2), 'projects': list(set(r.project_id for r in records)), 'trend': 'increasing' if len(records) > 2 and actual_costs[-1] > actual_costs[0] else 'stable' } def get_accuracy_metrics(self) -> Dict[str, Any]: """Calculate overall estimating accuracy metrics.""" if not self._records: return {} variances = [r.variance_percent for r in self._records] # Accuracy by category by_category = {} for record in self._records: category = record.work_item_code.split('-')[0] if '-' in record.work_item_code else 'Other' if category not in by_category: by_category[category] = [] by_category[category].append(record.variance_percent) category_accuracy = { cat: { 'average_variance': round(np.mean(vals), 1), 'count': len(vals) } for cat, vals in by_category.items() } return { 'total_records': len(self._records), 'average_variance_pct': round(np.mean(variances), 1), 'variance_std': round(np.std(variances), 1), 'within_5pct': sum(1 for v in variances if abs(v) <= 5) / len(variances) * 100, 'within_10pct': sum(1 for v in variances if abs(v) <= 10) / len(variances) * 100, 'overestimated_pct': sum(1 for v in variances if v < 0) / len(variances) * 100, 'underestimated_pct': sum(1 for v in variances if v > 0) / len(variances) * 100, 'by_category': category_accuracy } def suggest_adjustment_factors(self) -> Dict[str, float]: """Suggest adjustment factors based on historical variance.""" factors = {} for record in self._records: category = record.work_item_code.split('-')[0] if '-' in record.work_item_code else 'Other' if category not in factors: factors[category] = [] if record.estimated_cost > 0: actual_factor = record.actual_cost / record.estimated_cost factors[category].append(actual_factor) return { cat: round(np.mean(vals), 3) for cat, vals in factors.items() if len(vals) >= 3 # Require minimum data points } def compare_projects(self, project_ids: List[str] = None) -> pd.DataFrame: """Compare multiple projects.""" if project_ids: projects = [self._projects[pid] for pid in project_ids if pid in self._projects] else: projects = list(self._projects.values()) if not projects: return pd.DataFrame() return pd.DataFrame([ { 'Project ID': p.project_id, 'Project Name': p.project_name, 'Type': p.project_type, 'Location': p.location, 'Status': p.status.value, 'Estimated': p.estimated_total, 'Actual': p.actual_total, 'Variance': p.variance, 'Variance %': p.variance_percent, 'Items': p.item_count } for p in projects ]) def get_benchmarks_by_type(self, project_type: str) -> Dict[str, Any]: """Get cost benchmarks for project type.""" projects = [p for p in self._projects.values() if p.project_type == project_type] if not projects: return {} actuals = [p.actual_total for p in projects if p.status == ProjectStatus.COMPLETED] return { 'project_type': project_type, 'completed_projects': len(actuals), 'average_cost': round(np.mean(actuals), 2) if actuals else 0, 'min_cost': round(min(actuals), 2) if actuals else 0, 'max_cost': round(max(actuals), 2) if actuals else 0, 'average_variance': round(np.mean([p.variance_percent for p in projects]), 1) } def export_historical_data(self, output_path: str) -> str: """Export historical data to Excel.""" with pd.ExcelWriter(output_path, engine='openpyxl') as writer: # Projects if self._projects: projects_df = self.compare_projects() projects_df.to_excel(writer, sheet_name='Projects', index=False) # Records if self._records: records_df = pd.DataFrame([ { 'Project': r.project_id, 'Work Item': r.work_item_code, 'Quantity': r.quantity, 'Estimated': r.estimated_cost, 'Actual': r.actual_cost, 'Variance': r.variance, 'Variance %': r.variance_percent, 'Date': r.completion_date, 'Notes': r.notes } for r in self._records ]) records_df.to_excel(writer, sheet_name='Records', index=False) # Accuracy metrics metrics = self.get_accuracy_metrics() if metrics: metrics_df = pd.DataFrame([{ 'Total Records': metrics.get('total_records', 0), 'Avg Variance %': metrics.get('average_variance_pct', 0), 'Within 5%': f"{metrics.get('within_5pct', 0):.1f}%", 'Within 10%': f"{metrics.get('within_10pct', 0):.1f}%" }]) metrics_df.to_excel(writer, sheet_name='Accuracy', index=False) return output_path def save_database(self, filepath: str): """Save historical database to JSON.""" data = { 'projects': { pid: { 'project_id': p.project_id, 'project_name': p.project_name, 'project_type': p.project_type, 'location': p.location, 'status': p.status.value, 'estimated_total': p.estimated_total, 'actual_total': p.actual_total, 'start_date': p.start_date.isoformat(), 'completion_date': p.completion_date.isoformat() if p.completion_date else None } for pid, p in self._projects.items() }, 'records': [ { 'project_id': r.project_id, 'work_item_code': r.work_item_code, 'quantity': r.quantity, 'estimated_cost': r.estimated_cost, 'actual_cost': r.actual_cost, 'completion_date': r.completion_date.isoformat(), 'notes': r.notes } for r in self._records ] } with open(filepath, 'w') as f: json.dump(data, f, indent=2)
pythonfrom datetime import date # Load CWICR data cwicr = pd.read_parquet("TR_workitems_costs_resources_DDC_CWICR.parquet") # Initialize tracker tracker = CWICRHistoricalCost(cwicr) # Add project tracker.add_project( project_id="PROJ-001", project_name="Office Building A", project_type="commercial", location="New York", estimated_total=5000000, start_date=date(2024, 1, 1) ) # Record actual costs tracker.record_actual_cost( project_id="PROJ-001", work_item_code="CONC-001", quantity=200, actual_cost=32000, notes="Slightly over due to overtime" )
pythonmetrics = tracker.get_accuracy_metrics() print(f"Within 10%: {metrics['within_10pct']:.1f}%")
pythonfactors = tracker.suggest_adjustment_factors() for cat, factor in factors.items(): print(f"{cat}: {factor:.2f}x")
pythonhistory = tracker.get_work_item_history("CONC-001") print(f"Average variance: {history['average_variance_pct']}%")
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 33,875 | 57,746 | +70% | 1 | 1 | 0% | 1,413 | 10,194 | +621% | 0 | 0 | — |
case-02 | fail→pass | 11,388 | 24,199 | +112% | 1 | 1 | 0% | 1,956 | 9,516 | +387% | 0 | 0 | — |
case-03 | fail→fail | 38,545 | 37,990 | -1% | 1 | 1 | 0% | 8,261 | 12,217 | +48% | 0 | 0 | — |
case-04 | pass→pass | 7,323 | 10,616 | +45% | 1 | 1 | 0% | 1,599 | 5,256 | +229% | 0 | 0 | — |
case-05 | pass→pass | 5,538 | 8,321 | +50% | 1 | 1 | 0% | 1,130 | 5,660 | +401% | 0 | 0 | — |
case-06 | pass→pass | 13,536 | 21,726 | +61% | 1 | 1 | 0% | 2,555 | 8,230 | +222% | 0 | 0 | — |
case-07 | fail→pass | 12,884 | 4,613 | -64% | 1 | 1 | 0% | 2,178 | 4,796 | +120% | 0 | 0 | — |
case-08 | fail→pass | 11,449 | 5,929 | -48% | 1 | 1 | 0% | 2,072 | 5,125 | +147% | 0 | 0 | — |
case-09 | fail→pass | 12,738 | 7,141 | -44% | 1 | 1 | 0% | 2,238 | 5,336 | +138% | 0 | 0 | — |
case-10 | pass→pass | 10,513 | 4,739 | -55% | 1 | 1 | 0% | 1,792 | 4,865 | +171% | 0 | 0 | — |
case-11 | fail→fail | 15,454 | 16,254 | +5% | 1 | 1 | 0% | 2,540 | 6,803 | +168% | 0 | 0 | — |
case-12 | pass→pass | 13,497 | 4,572 | -66% | 1 | 1 | 0% | 2,177 | 4,930 | +126% | 0 | 0 | — |
case-13 | pass→pass | 9,615 | 9,220 | -4% | 1 | 1 | 0% | 1,833 | 5,610 | +206% | 0 | 0 | — |
case-14 | fail→pass | 15,204 | 16,566 | +9% | 1 | 1 | 0% | 2,594 | 7,090 | +173% | 0 | 0 | — |
case-15 | pass→pass | 9,601 | 4,484 | -53% | 1 | 1 | 0% | 1,619 | 4,798 | +196% | 0 | 0 | — |
case-16 | fail→pass | 14,121 | 5,477 | -61% | 1 | 1 | 0% | 2,409 | 5,180 | +115% | 0 | 0 | — |
case-17 | fail→fail | 4,990 | 3,203 | -36% | 1 | 1 | 0% | 795 | 4,603 | +479% | 0 | 0 | — |
case-18 | fail→pass | 11,198 | 11,398 | +2% | 1 | 1 | 0% | 1,783 | 5,780 | +224% | 0 | 0 | — |
case-19 | fail→pass | 11,036 | 2,584 | -77% | 1 | 1 | 0% | 1,888 | 4,422 | +134% | 0 | 0 | — |
case-20 | pass→pass | 11,154 | 4,720 | -58% | 1 | 1 | 0% | 2,012 | 4,977 | +147% | 0 | 0 | — |
case-21 | fail→pass | 13,035 | 5,770 | -56% | 1 | 1 | 0% | 2,418 | 5,117 | +112% | 0 | 0 | — |
case-22 | fail→pass | 11,330 | 3,329 | -71% | 1 | 1 | 0% | 2,030 | 4,657 | +129% | 0 | 0 | — |
case-23 | fail→pass | 18,576 | 3,024 | -84% | 1 | 1 | 0% | 3,005 | 4,525 | +51% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted, and 22 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +48 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/22/2026 | +68% |
Other measured skills in the registry, with their headline benchmark lift.