Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Analyze weather impact on construction schedule. Predict delays and adjust activities based on forecast.
.claude/skills/datadrivenconstruction-weather-impact-scheduler/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 95% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 76% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 61% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 94% | 0% |
pythonimport pandas as pd from datetime import date, timedelta from typing import Dict, Any, List, Optional from dataclasses import dataclass, field from enum import Enum class WeatherCondition(Enum): CLEAR = "clear" CLOUDY = "cloudy" RAIN = "rain" HEAVY_RAIN = "heavy_rain" SNOW = "snow" WIND = "wind" EXTREME_HEAT = "extreme_heat" EXTREME_COLD = "extreme_cold" class ActivitySensitivity(Enum): HIGH = "high" # Concrete, painting, roofing MEDIUM = "medium" # Excavation, masonry LOW = "low" # Indoor work @dataclass class WeatherForecast: forecast_date: date condition: WeatherCondition high_temp: float low_temp: float precipitation_mm: float wind_speed_kmh: float @dataclass class ScheduleActivity: activity_id: str name: str start_date: date end_date: date sensitivity: ActivitySensitivity outdoor: bool can_work_in_rain: bool = False min_temp: float = 5.0 max_temp: float = 35.0 max_wind: float = 50.0 @dataclass class WeatherImpact: activity_id: str impact_date: date reason: str delay_hours: float recommendation: str class WeatherImpactScheduler: def __init__(self, project_name: str): self.project_name = project_name self.activities: Dict[str, ScheduleActivity] = {} self.forecasts: Dict[date, WeatherForecast] = {} self.impacts: List[WeatherImpact] = [] def add_activity(self, activity_id: str, name: str, start_date: date, end_date: date, sensitivity: ActivitySensitivity, outdoor: bool = True, can_work_in_rain: bool = False) -> ScheduleActivity: activity = ScheduleActivity( activity_id=activity_id, name=name, start_date=start_date, end_date=end_date, sensitivity=sensitivity, outdoor=outdoor, can_work_in_rain=can_work_in_rain ) self.activities[activity_id] = activity return activity def add_forecast(self, forecast_date: date, condition: WeatherCondition, high_temp: float, low_temp: float, precipitation_mm: float = 0, wind_speed_kmh: float = 0): forecast = WeatherForecast( forecast_date=forecast_date, condition=condition, high_temp=high_temp, low_temp=low_temp, precipitation_mm=precipitation_mm, wind_speed_kmh=wind_speed_kmh ) self.forecasts[forecast_date] = forecast def analyze_impacts(self) -> List[WeatherImpact]: self.impacts = [] for activity in self.activities.values(): if not activity.outdoor: continue current = activity.start_date while current <= activity.end_date: forecast = self.forecasts.get(current) if forecast: impact = self._check_impact(activity, forecast) if impact: self.impacts.append(impact) current += timedelta(days=1) return self.impacts def _check_impact(self, activity: ScheduleActivity, forecast: WeatherForecast) -> Optional[WeatherImpact]: reasons = [] delay_hours = 0 # Check precipitation if forecast.condition in [WeatherCondition.RAIN, WeatherCondition.HEAVY_RAIN]: if not activity.can_work_in_rain: if activity.sensitivity == ActivitySensitivity.HIGH: reasons.append("Rain - high sensitivity activity") delay_hours = 8 else: reasons.append("Rain delays") delay_hours = 4 # Check temperature if forecast.low_temp < activity.min_temp: reasons.append(f"Too cold ({forecast.low_temp}°C)") delay_hours = max(delay_hours, 8 if activity.sensitivity == ActivitySensitivity.HIGH else 4) if forecast.high_temp > activity.max_temp: reasons.append(f"Too hot ({forecast.high_temp}°C)") delay_hours = max(delay_hours, 4) # Check wind if forecast.wind_speed_kmh > activity.max_wind: reasons.append(f"High wind ({forecast.wind_speed_kmh} km/h)") delay_hours = max(delay_hours, 8) if reasons: return WeatherImpact( activity_id=activity.activity_id, impact_date=forecast.forecast_date, reason="; ".join(reasons), delay_hours=delay_hours, recommendation=self._get_recommendation(activity, forecast) ) return None def _get_recommendation(self, activity: ScheduleActivity, forecast: WeatherForecast) -> str: if forecast.condition in [WeatherCondition.RAIN, WeatherCondition.HEAVY_RAIN]: return "Reschedule or plan indoor work" if forecast.low_temp < activity.min_temp: return "Use heating blankets or delay start" if forecast.high_temp > activity.max_temp: return "Start early, plan heat breaks" if forecast.wind_speed_kmh > activity.max_wind: return "Secure materials, delay crane work" return "Monitor conditions" def get_total_delay_forecast(self) -> Dict[str, Any]: total_hours = sum(i.delay_hours for i in self.impacts) by_activity = {} for impact in self.impacts: act = impact.activity_id by_activity[act] = by_activity.get(act, 0) + impact.delay_hours return { 'total_impact_hours': total_hours, 'total_impact_days': round(total_hours / 8, 1), 'affected_activities': len(by_activity), 'by_activity': by_activity, 'impact_count': len(self.impacts) } def export_analysis(self, output_path: str): data = [{ 'Activity': i.activity_id, 'Date': i.impact_date, 'Reason': i.reason, 'Delay Hours': i.delay_hours, 'Recommendation': i.recommendation } for i in self.impacts] pd.DataFrame(data).to_excel(output_path, index=False)
pythonscheduler = WeatherImpactScheduler("Office Tower") # Add activities scheduler.add_activity("CONC-001", "Pour Slab L3", date(2024, 3, 15), date(2024, 3, 20), ActivitySensitivity.HIGH, outdoor=True) # Add forecasts scheduler.add_forecast(date(2024, 3, 17), WeatherCondition.RAIN, 15, 8, 25, 20) # Analyze impacts = scheduler.analyze_impacts() summary = scheduler.get_total_delay_forecast() print(f"Projected delay: {summary['total_impact_days']} days")
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-11 | fail→fail | 7,652 | 6,582 | -14% | 1 | 1 | 0% | 1,294 | 3,290 | +154% | 0 | 0 | — |
case-16 | fail→pass | 10,168 | 5,706 | -44% | 1 | 1 | 0% | 1,607 | 3,139 | +95% | 0 | 0 | — |
case-01 | fail→pass | 12,602 | 17,173 | +36% | 1 | 1 | 0% | 2,487 | 4,388 | +76% | 0 | 0 | — |
case-02 | fail→pass | 13,235 | 9,442 | -29% | 1 | 1 | 0% | 2,514 | 4,038 | +61% | 0 | 0 | — |
case-03 | fail→fail | 15,648 | 11,313 | -28% | 1 | 1 | 0% | 3,047 | 4,507 | +48% | 0 | 0 | — |
case-04 | pass→pass | 9,298 | 8,448 | -9% | 1 | 1 | 0% | 1,910 | 3,611 | +89% | 0 | 0 | — |
case-05 | pass→pass | 8,803 | 9,080 | +3% | 1 | 1 | 0% | 1,930 | 3,787 | +96% | 0 | 0 | — |
case-06 | pass→pass | 13,891 | 13,609 | -2% | 1 | 1 | 0% | 2,340 | 4,152 | +77% | 0 | 0 | — |
case-07 | fail→pass | 10,121 | 4,323 | -57% | 1 | 1 | 0% | 1,665 | 2,753 | +65% | 0 | 0 | — |
case-08 | fail→pass | 8,800 | 6,502 | -26% | 1 | 1 | 0% | 1,592 | 3,092 | +94% | 0 | 0 | — |
case-09 | fail→pass | 8,540 | 5,387 | -37% | 1 | 1 | 0% | 1,422 | 3,035 | +113% | 0 | 0 | — |
case-10 | fail→pass | 5,391 | 6,374 | +18% | 1 | 1 | 0% | 896 | 3,255 | +263% | 0 | 0 | — |
case-12 | fail→pass | 6,890 | 5,292 | -23% | 1 | 1 | 0% | 1,121 | 3,089 | +176% | 0 | 0 | — |
case-13 | pass→pass | 10,154 | 5,166 | -49% | 1 | 1 | 0% | 1,690 | 2,901 | +72% | 0 | 0 | — |
case-14 | pass→pass | 4,719 | 2,675 | -43% | 1 | 1 | 0% | 827 | 2,369 | +186% | 0 | 0 | — |
case-15 | pass→pass | 5,047 | 6,201 | +23% | 1 | 1 | 0% | 987 | 3,321 | +236% | 0 | 0 | — |
case-17 | fail→pass | 9,394 | 6,570 | -30% | 1 | 1 | 0% | 1,648 | 3,310 | +101% | 0 | 0 | — |
case-18 | pass→pass | 8,234 | 6,603 | -20% | 1 | 1 | 0% | 1,369 | 3,260 | +138% | 0 | 0 | — |
case-19 | fail→pass | 23,873 | 4,023 | -83% | 1 | 1 | 0% | 2,001 | 2,713 | +36% | 0 | 0 | — |
case-20 | fail→pass | 9,135 | 7,649 | -16% | 1 | 1 | 0% | 1,742 | 3,669 | +111% | 0 | 0 | — |
case-21 | fail→pass | 14,400 | 6,235 | -57% | 1 | 1 | 0% | 2,491 | 3,212 | +29% | 0 | 0 | — |
case-22 | fail→pass | 10,925 | 5,900 | -46% | 1 | 1 | 0% | 1,986 | 3,148 | +59% | 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 +59 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.
Other measured skills in the registry, with their headline benchmark lift.