| name | safety-inspection |
| description | Digital safety inspection system for construction sites. Checklists, hazard tracking, incident reporting, and compliance documentation. |
| homepage | https://datadrivenconstruction.io |
| metadata | {"openclaw":{"emoji":"🏗️","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":"[Truncated]"}}} |
Safety Inspection System for Construction
Comprehensive digital safety management system for construction sites with inspection checklists, hazard tracking, and incident reporting.
Business Case
Problem: Paper-based safety management leads to:
- Incomplete inspections (20-30% of items skipped)
- Lost documentation
- Delayed incident reporting
- Difficulty tracking corrective actions
- Compliance audit failures
Solution: Digital system that:
- Enforces complete checklist completion
- Photos attached to each finding
- Instant notifications for hazards
- Tracks corrective actions to closure
- Generates compliance reports
ROI: 40% reduction in recordable incidents, 100% audit compliance
Safety Inspection Types
┌──────────────────────────────────────────────────────────────────────┐
│ SAFETY INSPECTION TYPES │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ DAILY WEEKLY SPECIAL │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Pre-Work │ │ Area Walk │ │ Pre-Pour │ │
│ │ • Housekeeping│ │ • Fire ext. │ │ • Formwork │ │
│ │ • PPE │ │ • First aid │ │ • Shoring │ │
│ │ • Equipment │ │ • Scaffolds │ │ └─────────────┘ │
│ └─────────────┘ │ • Trenches │ ┌─────────────┐ │
│ ┌─────────────┐ └─────────────┘ │ Crane Setup │ │
│ │ Toolbox Talk│ ┌─────────────┐ │ • Ground │ │
│ │ • Topic │ │ Equipment │ │ • Load chart│ │
│ │ • Attendees │ │ • Cranes │ │ • Rigging │ │
│ │ • Sign-off │ │ • Lifts │ └─────────────┘ │
│ └─────────────┘ │ • Vehicles │ ┌─────────────┐ │
│ ┌─────────────┐ └─────────────┘ │ Hot Work │ │
│ │ End of Day │ │ • Permit │ │
│ │ • Secured │ │ • Fire watch│ │
│ │ • Barricades│ └─────────────┘ │
│ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
Data Structure
from dataclasses import dataclass, field
from datetime import datetime, date
from enum import Enum
from typing import List, Optional
import uuid
class HazardSeverity(Enum):
CRITICAL = "Critical"
HIGH = "High"
MEDIUM = "Medium"
LOW = "Low"
OBSERVATION = "Observation"
class HazardStatus(Enum):
OPEN = "Open"
IN_PROGRESS = "In Progress"
CORRECTED = "Corrected"
VERIFIED = "Verified Closed"
class InspectionType(Enum):
DAILY_PREWORK = "Daily Pre-Work"
TOOLBOX_TALK = "Toolbox Talk"
AREA_INSPECTION = "Area Inspection"
EQUIPMENT_INSPECTION = "Equipment Inspection"
HOT_WORK_PERMIT = "Hot Work Permit"
CONFINED_SPACE = "Confined Space Entry"
CRANE_LIFT = "Crane/Lift Inspection"
SCAFFOLD = "Scaffold Inspection"
EXCAVATION = "Excavation Inspection"
INCIDENT = "Incident Report"
:
hazard_id:
inspection_id:
description:
severity: HazardSeverity
location:
photo_urls: [] = field(default_factory=)
assigned_to: =
due_date: date =
status: HazardStatus = HazardStatus.OPEN
corrective_action: =
corrected_date: date =
corrected_by: =
verification_date: date =
verified_by: =
:
inspection_id:
inspection_type: InspectionType
project_id:
date: date
inspector:
location:
checklist_items: [] = field(default_factory=)
hazards_found: [Hazard] = field(default_factory=)
overall_rating: =
notes: =
photos: [] = field(default_factory=)
signatures: [] = field(default_factory=)
weather: =
created_at: datetime = field(default_factory=datetime.now)
:
incident_id:
project_id:
date: datetime
:
description:
location:
injured_party: =
witness_names: [] = field(default_factory=)
immediate_actions: =
root_cause: =
corrective_actions: =
reported_by: =
photos: [] = field(default_factory=)
osha_recordable: =
days_away: =
days_restricted: =
Python Implementation
import pandas as pd
from datetime import datetime, date, timedelta
from typing import List, Dict, Optional
import json
import os
class SafetyManager:
"""Construction site safety management system"""
def __init__(self, project_id: str, storage_path: str = None):
self.project_id = project_id
self.storage_path = storage_path or f"safety_{project_id}"
self.inspections: Dict[str, Inspection] = {}
self.hazards: Dict[str, Hazard] = {}
self.incidents: Dict[str, Incident] = {}
self.checklists = self._load_checklists()
def _load_checklists(self) -> Dict[str, List[dict]]:
"""Load inspection checklists"""
return {
InspectionType.DAILY_PREWORK.value: [
{"id": "DP01", : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
],
InspectionType.SCAFFOLD.value: [
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
],
InspectionType.EXCAVATION.value: [
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
{: , : , : },
],
}
() -> Inspection:
inspection_id =
checklist = .checklists.get(inspection_type.value, [])
checklist_items = [
{**item, : , : , : }
item checklist
]
inspection = Inspection(
inspection_id=inspection_id,
inspection_type=inspection_type,
project_id=.project_id,
date=date.today(),
inspector=inspector,
location=location,
checklist_items=checklist_items,
weather=weather
)
.inspections[inspection_id] = inspection
inspection
() -> Inspection:
inspection = .inspections.get(inspection_id)
inspection:
ValueError()
item inspection.checklist_items:
item[] == item_id:
item[] = result
item[] = notes
item[] = photo_url
result == :
()
inspection
() -> Hazard:
hazard_id =
due_date :
days = {
HazardSeverity.CRITICAL: ,
HazardSeverity.HIGH: ,
HazardSeverity.MEDIUM: ,
HazardSeverity.LOW: ,
HazardSeverity.OBSERVATION:
}
due_date = date.today() + timedelta(days=days.get(severity, ))
hazard = Hazard(
hazard_id=hazard_id,
inspection_id=inspection_id,
description=description,
severity=severity,
location=location,
assigned_to=assigned_to,
due_date=due_date,
photo_urls=photo_urls []
)
.hazards[hazard_id] = hazard
inspection_id .inspections:
.inspections[inspection_id].hazards_found.append(hazard)
severity [HazardSeverity.CRITICAL, HazardSeverity.HIGH]:
._notify_hazard(hazard)
hazard
() -> Hazard:
hazard = .hazards.get(hazard_id)
hazard:
ValueError()
hazard.corrective_action = corrective_action
hazard.corrected_by = corrected_by
hazard.corrected_date = date.today()
hazard.status = HazardStatus.CORRECTED
photo_url:
hazard.photo_urls.append(photo_url)
hazard
() -> Hazard:
hazard = .hazards.get(hazard_id)
hazard:
ValueError()
hazard.status != HazardStatus.CORRECTED:
ValueError()
hazard.verified_by = verified_by
hazard.verification_date = date.today()
hazard.status = HazardStatus.VERIFIED
hazard
() -> Incident:
incident_id =
incident = Incident(
incident_id=incident_id,
project_id=.project_id,
date=datetime.now(),
=incident_type,
description=description,
location=location,
injured_party=injured_party,
witness_names=witness_names [],
immediate_actions=immediate_actions,
reported_by=reported_by,
photos=photo_urls []
)
.incidents[incident_id] = incident
._notify_incident(incident)
incident
() -> [Hazard]:
[
h h .hazards.values()
h.status [HazardStatus.OPEN, HazardStatus.IN_PROGRESS]
]
() -> [Hazard]:
today = date.today()
[
h h .hazards.values()
h.status == HazardStatus.OPEN h.due_date < today
]
() -> :
cutoff = date.today() - timedelta(days=period_days)
period_inspections = [
i i .inspections.values()
i.date >= cutoff
]
period_hazards = [
h h .hazards.values()
]
period_incidents = [
i i .incidents.values()
i.date.date() >= cutoff
]
total_inspections = (period_inspections)
total_hazards = (.hazards)
open_hazards = (.get_open_hazards())
overdue_hazards = (.get_overdue_hazards())
near_misses = ([i i period_incidents i. == ])
first_aid = ([i i period_incidents i. == ])
recordables = ([i i period_incidents i.osha_recordable])
estimated_hours = * (period_days / )
trir = (recordables * / estimated_hours) estimated_hours >
{
: period_days,
: total_inspections,
: total_hazards,
: open_hazards,
: overdue_hazards,
: ._count_by_severity(),
: (period_incidents),
: near_misses,
: first_aid,
: recordables,
: (trir, ),
: ._days_since_recordable()
}
() -> :
result = {s.value: s HazardSeverity}
hazard .hazards.values():
hazard.status != HazardStatus.VERIFIED:
result[hazard.severity.value] +=
result
() -> :
recordables = [
i i .incidents.values()
i.osha_recordable
]
recordables:
last = (recordables, key= x: x.date)
(datetime.now() - last.date).days
():
()
()
()
()
()
():
()
()
()
incident.injured_party:
()
() -> :
stats = .get_statistics(period_days=)
open_hazards = .get_open_hazards()
overdue = .get_overdue_hazards()
report =
overdue:
report +=
h overdue:
report +=
critical_high = [h h open_hazards
h.severity [HazardSeverity.CRITICAL, HazardSeverity.HIGH]]
critical_high:
report +=
h critical_high:
report +=
report +=
report
__name__ == :
safety = SafetyManager(project_id=)
inspection = safety.create_inspection(
inspection_type=InspectionType.DAILY_PREWORK,
inspector=,
location=,
weather=
)
()
safety.complete_checklist_item(
inspection_id=inspection.inspection_id,
item_id=,
result=
)
safety.complete_checklist_item(
inspection_id=inspection.inspection_id,
item_id=,
result=,
notes=
)
hazard = safety.add_hazard(
inspection_id=inspection.inspection_id,
description=,
severity=HazardSeverity.CRITICAL,
location=,
assigned_to=
)
()
safety.correct_hazard(
hazard_id=hazard.hazard_id,
corrective_action=,
corrected_by=
)
safety.verify_hazard_closure(
hazard_id=hazard.hazard_id,
verified_by=
)
(safety.generate_daily_safety_report())
Mobile App Integration
name: Safety Inspection Bot
commands:
/inspection:
- Select inspection type
- Show checklist
- Record results (✅/❌)
- Capture photos
- Submit
/hazard:
- Describe hazard
- Select severity
- Take photo
- GPS location
- Assign responsible party
/incident:
- Report type
- Description
- Photos
- Witness info
- Immediate actions
"Safety is not a priority - it's a value. Priorities change, values don't."