Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate automated daily progress reports from site data. Track work completed, labor hours, equipment usage, and weather conditions.
.claude/skills/datadrivenconstruction-daily-progress-report/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 236% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 542% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 311% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 167% | 0% |
Site managers spend hours creating daily reports:
Automated daily progress report generation from structured site data inputs.
pythonimport pandas as pd from datetime import datetime, date from typing import Dict, Any, List from dataclasses import dataclass from enum import Enum class WeatherCondition(Enum): CLEAR = "clear" CLOUDY = "cloudy" RAIN = "rain" SNOW = "snow" WIND = "wind" EXTREME = "extreme" class WorkStatus(Enum): COMPLETED = "completed" IN_PROGRESS = "in_progress" DELAYED = "delayed" NOT_STARTED = "not_started" @dataclass class WorkActivity: activity_id: str description: str location: str planned_qty: float actual_qty: float unit: str status: WorkStatus crew_size: int hours_worked: float notes: str = "" @dataclass class LaborEntry: trade: str company: str workers: int hours: float overtime_hours: float = 0 @dataclass class EquipmentEntry: equipment_type: str equipment_id: str hours_used: float status: str # active, idle, maintenance operator: str = "" @dataclass class DailyReport: report_date: date project_name: str project_number: str weather: WeatherCondition temperature_high: float temperature_low: float work_activities: List[WorkActivity] labor: List[LaborEntry] equipment: List[EquipmentEntry] delays: List[str] safety_incidents: int visitors: List[str] deliveries: List[str] prepared_by: str class DailyProgressReporter: """Generate daily progress reports.""" def __init__(self, project_name: str, project_number: str): self.project_name = project_name self.project_number = project_number def create_report(self, report_date: date, weather: WeatherCondition, temp_high: float, temp_low: float, prepared_by: str) -> DailyReport: """Create new daily report.""" return DailyReport( report_date=report_date, project_name=self.project_name, project_number=self.project_number, weather=weather, temperature_high=temp_high, temperature_low=temp_low, work_activities=[], labor=[], equipment=[], delays=[], safety_incidents=0, visitors=[], deliveries=[], prepared_by=prepared_by ) def add_work_activity(self, report: DailyReport, activity_id: str, description: str, location: str, planned_qty: float, actual_qty: float, unit: str, crew_size: int, hours_worked: float, notes: str = ""): """Add work activity to report.""" # Determine status if actual_qty >= planned_qty: status = WorkStatus.COMPLETED elif actual_qty > 0: status = WorkStatus.IN_PROGRESS elif actual_qty == 0 and planned_qty > 0: status = WorkStatus.DELAYED else: status = WorkStatus.NOT_STARTED activity = WorkActivity( activity_id=activity_id, description=description, location=location, planned_qty=planned_qty, actual_qty=actual_qty, unit=unit, status=status, crew_size=crew_size, hours_worked=hours_worked, notes=notes ) report.work_activities.append(activity) def add_labor(self, report: DailyReport, trade: str, company: str, workers: int, hours: float, overtime_hours: float = 0): """Add labor entry.""" report.labor.append(LaborEntry( trade=trade, company=company, workers=workers, hours=hours, overtime_hours=overtime_hours )) def add_equipment(self, report: DailyReport, equipment_type: str, equipment_id: str, hours_used: float, status: str, operator: str = ""): """Add equipment entry.""" report.equipment.append(EquipmentEntry( equipment_type=equipment_type, equipment_id=equipment_id, hours_used=hours_used, status=status, operator=operator )) def calculate_summary(self, report: DailyReport) -> Dict[str, Any]: """Calculate report summary metrics.""" total_workers = sum(l.workers for l in report.labor) total_manhours = sum(l.workers * l.hours for l in report.labor) total_overtime = sum(l.workers * l.overtime_hours for l in report.labor) equipment_hours = sum(e.hours_used for e in report.equipment) completed = sum(1 for a in report.work_activities if a.status == WorkStatus.COMPLETED) in_progress = sum(1 for a in report.work_activities if a.status == WorkStatus.IN_PROGRESS) delayed = sum(1 for a in report.work_activities if a.status == WorkStatus.DELAYED) return { 'total_workers': total_workers, 'total_manhours': round(total_manhours, 1), 'total_overtime': round(total_overtime, 1), 'equipment_hours': round(equipment_hours, 1), 'activities_completed': completed, 'activities_in_progress': in_progress, 'activities_delayed': delayed, 'safety_incidents': report.safety_incidents, 'deliveries_count': len(report.deliveries) } def export_to_excel(self, report: DailyReport, output_path: str) -> str: """Export report to Excel.""" with pd.ExcelWriter(output_path, engine='openpyxl') as writer: # Header header_df = pd.DataFrame([{ 'Project': report.project_name, 'Project #': report.project_number, 'Date': report.report_date, 'Weather': report.weather.value, 'High Temp': report.temperature_high, 'Low Temp': report.temperature_low, 'Prepared By': report.prepared_by }]) header_df.to_excel(writer, sheet_name='Summary', index=False) # Work Activities if report.work_activities: activities_df = pd.DataFrame([ { 'Activity ID': a.activity_id, 'Description': a.description, 'Location': a.location, 'Planned': a.planned_qty, 'Actual': a.actual_qty, 'Unit': a.unit, 'Status': a.status.value, 'Crew': a.crew_size, 'Hours': a.hours_worked, 'Notes': a.notes } for a in report.work_activities ]) activities_df.to_excel(writer, sheet_name='Work Activities', index=False) # Labor if report.labor: labor_df = pd.DataFrame([ { 'Trade': l.trade, 'Company': l.company, 'Workers': l.workers, 'Hours': l.hours, 'Overtime': l.overtime_hours, 'Total Hours': l.workers * (l.hours + l.overtime_hours) } for l in report.labor ]) labor_df.to_excel(writer, sheet_name='Labor', index=False) # Equipment if report.equipment: equip_df = pd.DataFrame([ { 'Type': e.equipment_type, 'ID': e.equipment_id, 'Hours': e.hours_used, 'Status': e.status, 'Operator': e.operator } for e in report.equipment ]) equip_df.to_excel(writer, sheet_name='Equipment', index=False) return output_path def generate_text_report(self, report: DailyReport) -> str: """Generate text version of report.""" summary = self.calculate_summary(report) lines = [ f"DAILY PROGRESS REPORT", f"=" * 50, f"Project: {report.project_name}", f"Project #: {report.project_number}", f"Date: {report.report_date}", f"Prepared by: {report.prepared_by}", f"", f"WEATHER CONDITIONS", f"-" * 30, f"Conditions: {report.weather.value}", f"Temperature: {report.temperature_low}°C - {report.temperature_high}°C", f"", f"SUMMARY", f"-" * 30, f"Total Workers: {summary['total_workers']}", f"Total Man-hours: {summary['total_manhours']}", f"Equipment Hours: {summary['equipment_hours']}", f"Activities Completed: {summary['activities_completed']}", f"Activities In Progress: {summary['activities_in_progress']}", f"Activities Delayed: {summary['activities_delayed']}", f"Safety Incidents: {summary['safety_incidents']}", ] if report.delays: lines.extend([f"", f"DELAYS", f"-" * 30]) for delay in report.delays: lines.append(f"• {delay}") return "\n".join(lines)
pythonfrom datetime import date # Initialize reporter reporter = DailyProgressReporter("Office Tower A", "PRJ-2024-001") # Create report report = reporter.create_report( report_date=date.today(), weather=WeatherCondition.CLEAR, temp_high=28, temp_low=18, prepared_by="John Smith" ) # Add activities reporter.add_work_activity( report, activity_id="A-101", description="Pour concrete slab Level 3", location="Level 3, Zone A", planned_qty=150, actual_qty=150, unit="m3", crew_size=8, hours_worked=10 ) # Add labor reporter.add_labor(report, "Concrete", "ABC Concrete Co", 8, 10, 2) # Export reporter.export_to_excel(report, "daily_report.xlsx")
pythontext = reporter.generate_text_report(report) print(text)
pythonreport.delays.append("Weather delay - rain from 14:00-16:00") report.delays.append("Material delivery late by 2 hours")
pythonsummary = reporter.calculate_summary(report) print(f"Productivity: {summary['total_manhours']} man-hours")
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 12,657 | 8,454 | -33% | 1 | 1 | 0% | 3,028 | 4,944 | +63% | 0 | 0 | — |
case-02 | fail→fail | 3,587 | 7,519 | +110% | 1 | 1 | 0% | 743 | 4,305 | +479% | 0 | 0 | — |
case-03 | fail→fail | 28,716 | 24,212 | -16% | 1 | 1 | 0% | 6,305 | 8,147 | +29% | 0 | 0 | — |
case-04 | pass→fail | 10,818 | 3,741 | -65% | 1 | 1 | 0% | 1,784 | 3,575 | +100% | 0 | 0 | — |
case-05 | fail→pass | 6,169 | 3,023 | -51% | 1 | 1 | 0% | 1,025 | 3,445 | +236% | 0 | 0 | — |
case-06 | fail→pass | 3,386 | 2,648 | -22% | 1 | 1 | 0% | 511 | 3,281 | +542% | 0 | 0 | — |
case-07 | fail→pass | 4,904 | 4,596 | -6% | 1 | 1 | 0% | 926 | 3,805 | +311% | 0 | 0 | — |
case-08 | fail→pass | 8,682 | 3,584 | -59% | 1 | 1 | 0% | 1,328 | 3,549 | +167% | 0 | 0 | — |
case-09 | fail→pass | 8,138 | 2,241 | -72% | 1 | 1 | 0% | 1,462 | 3,250 | +122% | 0 | 0 | — |
case-10 | pass→pass | 7,663 | 3,506 | -54% | 1 | 1 | 0% | 1,390 | 3,453 | +148% | 0 | 0 | — |
case-11 | fail→pass | 6,593 | 2,390 | -64% | 1 | 1 | 0% | 992 | 3,239 | +227% | 0 | 0 | — |
case-12 | fail→fail | 4,582 | 1,976 | -57% | 1 | 1 | 0% | 612 | 3,136 | +412% | 0 | 0 | — |
case-13 | fail→pass | 10,842 | 2,033 | -81% | 1 | 1 | 0% | 1,619 | 3,122 | +93% | 0 | 0 | — |
case-14 | pass→pass | 7,314 | 2,527 | -65% | 1 | 1 | 0% | 1,198 | 3,311 | +176% | 0 | 0 | — |
case-15 | pass→pass | 13,300 | 2,731 | -79% | 1 | 1 | 0% | 1,913 | 3,279 | +71% | 0 | 0 | — |
case-16 | fail→pass | 10,030 | 2,724 | -73% | 1 | 1 | 0% | 1,574 | 3,350 | +113% | 0 | 0 | — |
case-17 | fail→pass | 5,841 | 2,698 | -54% | 1 | 1 | 0% | 905 | 3,433 | +279% | 0 | 0 | — |
case-18 | pass→pass | 5,065 | 3,014 | -40% | 1 | 1 | 0% | 856 | 3,482 | +307% | 0 | 0 | — |
case-19 | fail→fail | 14,438 | 20,398 | +41% | 1 | 1 | 0% | 2,738 | 6,920 | +153% | 0 | 0 | — |
case-20 | pass→pass | 17,966 | 19,367 | +8% | 1 | 1 | 0% | 3,384 | 6,889 | +104% | 0 | 0 | — |
case-21 | fail→fail | 14,137 | 24,011 | +70% | 1 | 1 | 0% | 2,615 | 7,671 | +193% | 0 | 0 | — |
case-22 | fail→fail | 24,444 | 33,825 | +38% | 1 | 1 | 0% | 4,055 | 9,069 | +124% | 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. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
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.
Other measured skills in the registry, with their headline benchmark lift.