AI Agent for Construction: Automate Project Management, Safety & Cost Estimation
The global construction industry is worth $13 trillion annually—and wastes 30% of it on rework, delays, and inefficiency. AI agents are the first technology that can tackle all three simultaneously: monitoring job sites in real-time, predicting schedule slippage before it happens, and catching cost overruns while there's still time to act.
This guide covers six production workflows where AI agents deliver measurable results in construction, with architecture patterns, code examples, and ROI calculations.
Table of Contents
- 1. Intelligent Project Scheduling & Delay Prediction
- 2. Jobsite Safety Monitoring & Compliance
- 3. AI Cost Estimation & Budget Tracking
- 4. BIM Coordination & Clash Detection
- 5. Quality Inspection & Defect Detection
- 6. Resource & Equipment Optimization
- Platform Comparison
- ROI Calculator
- Implementation Roadmap
1. Intelligent Project Scheduling & Delay Prediction
Construction projects are notoriously late—70% of projects exceed their original timeline. The root cause isn't bad planning; it's the cascade effect. One delayed trade causes a chain reaction through dependent tasks. An AI agent that monitors progress and predicts cascading delays 2-3 weeks ahead gives project managers time to mitigate.
Schedule Risk Agent
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import List, Optional
import networkx as nx
@dataclass
class Task:
id: str
name: str
planned_start: datetime
planned_end: datetime
actual_start: Optional[datetime] = None
actual_pct_complete: float = 0.0
predecessors: List[str] = field(default_factory=list)
trade: str = ""
crew_size: int = 0
class ScheduleRiskAgent:
"""Predict schedule delays and recommend recovery actions."""
def __init__(self, tasks: List[Task], weather_api, labor_api):
self.tasks = {t.id: t for t in tasks}
self.graph = self._build_dependency_graph(tasks)
self.weather = weather_api
self.labor = labor_api
def _build_dependency_graph(self, tasks: List[Task]) -> nx.DiGraph:
"""Build task dependency network."""
G = nx.DiGraph()
for task in tasks:
duration = (task.planned_end - task.planned_start).days
G.add_node(task.id, duration=duration, task=task)
for pred in task.predecessors:
G.add_edge(pred, task.id)
return G
def find_critical_path(self) -> List[str]:
"""Identify the critical path through the schedule."""
return nx.dag_longest_path(self.graph, weight='duration')
def predict_delays(self) -> dict:
"""Analyze current progress and predict future delays."""
today = datetime.now()
at_risk = []
for task_id, task in self.tasks.items():
if task.actual_pct_complete >= 100:
continue
# Calculate earned vs planned progress
if task.actual_start:
elapsed = (today - task.actual_start).days
planned_duration = (task.planned_end - task.planned_start).days
expected_pct = min(100, (elapsed / max(planned_duration, 1)) * 100)
variance = task.actual_pct_complete - expected_pct
if variance < -10: # More than 10% behind
# Estimate delay propagation
delay_days = int(abs(variance) / 100 * planned_duration)
downstream = self._get_downstream_impact(task_id, delay_days)
at_risk.append({
"task_id": task_id,
"task_name": task.name,
"trade": task.trade,
"planned_pct": round(expected_pct, 1),
"actual_pct": task.actual_pct_complete,
"variance_pct": round(variance, 1),
"estimated_delay_days": delay_days,
"on_critical_path": task_id in self.find_critical_path(),
"downstream_tasks_affected": len(downstream),
"downstream_impact": downstream,
"recovery_options": self._suggest_recovery(task, delay_days)
})
# Weather impact
weather_risks = self._assess_weather_impact()
return {
"at_risk_tasks": sorted(at_risk, key=lambda x: x["estimated_delay_days"], reverse=True),
"weather_risks": weather_risks,
"critical_path_status": self._assess_critical_path(),
"projected_completion": self._project_completion_date()
}
def _get_downstream_impact(self, task_id: str, delay_days: int) -> List[dict]:
"""Calculate cascading delay on downstream tasks."""
impacts = []
for successor in nx.descendants(self.graph, task_id):
task = self.tasks[successor]
# Propagated delay diminishes through float
float_days = self._calculate_float(successor)
net_delay = max(0, delay_days - float_days)
if net_delay > 0:
impacts.append({
"task_id": successor,
"task_name": task.name,
"trade": task.trade,
"propagated_delay_days": net_delay,
"float_consumed_days": min(float_days, delay_days)
})
return impacts
def _suggest_recovery(self, task: Task, delay_days: int) -> List[dict]:
"""Recommend schedule recovery strategies."""
options = []
# Option 1: Add crew
if task.crew_size > 0:
additional = max(1, int(task.crew_size * 0.5))
recovery = delay_days * 0.6 # Diminishing returns
options.append({
"strategy": "Add crew",
"detail": f"Add {additional} workers to {task.trade}",
"recovery_days": round(recovery),
"estimated_cost": additional * 450 * delay_days,
"feasibility": "high" if self.labor.check_availability(task.trade, additional) else "low"
})
# Option 2: Extended hours
options.append({
"strategy": "Overtime",
"detail": "Extend to 10-hour shifts, 6 days/week",
"recovery_days": round(delay_days * 0.4),
"estimated_cost": task.crew_size * 150 * delay_days,
"feasibility": "high"
})
# Option 3: Resequence
options.append({
"strategy": "Resequence work",
"detail": "Start non-dependent work packages in parallel",
"recovery_days": round(delay_days * 0.3),
"estimated_cost": 0,
"feasibility": "medium"
})
return options
def _calculate_float(self, task_id: str) -> int:
"""Calculate total float for a task."""
critical = self.find_critical_path()
if task_id in critical:
return 0
# Simplified: difference between late finish and early finish
task = self.tasks[task_id]
duration = (task.planned_end - task.planned_start).days
return max(0, duration // 5) # Simplified estimate
2. Jobsite Safety Monitoring & Compliance
Construction is the deadliest industry in the US with 1,000+ fatalities annually. OSHA's "Focus Four" hazards—falls, struck-by, electrocution, caught-between—account for 60% of deaths. AI agents monitoring camera feeds and sensor data catch violations in real-time.
Computer Vision Safety Agent
class SafetyMonitoringAgent:
"""Real-time jobsite safety monitoring via camera feeds."""
VIOLATION_TYPES = {
"no_hard_hat": {"severity": "high", "osha_ref": "1926.100"},
"no_safety_vest": {"severity": "medium", "osha_ref": "1926.201"},
"no_fall_protection": {"severity": "critical", "osha_ref": "1926.501"},
"exclusion_zone_breach": {"severity": "critical", "osha_ref": "1926.1400"},
"improper_scaffolding": {"severity": "high", "osha_ref": "1926.451"},
"missing_guardrail": {"severity": "critical", "osha_ref": "1926.502"},
"housekeeping_hazard": {"severity": "medium", "osha_ref": "1926.25"},
}
def __init__(self, vision_model, camera_feeds, alert_system):
self.model = vision_model
self.cameras = camera_feeds
self.alerts = alert_system
self.violation_log = []
def analyze_frame(self, camera_id: str, frame) -> dict:
"""Analyze a single camera frame for safety violations."""
# Detect persons and PPE
detections = self.model.detect(frame, classes=[
"person", "hard_hat", "safety_vest", "harness",
"crane", "excavator", "scaffolding", "guardrail"
])
violations = []
persons = [d for d in detections if d.class_name == "person"]
for person in persons:
# Check PPE compliance for each detected person
nearby_ppe = self._find_nearby_objects(person, detections, radius=50)
ppe_classes = [obj.class_name for obj in nearby_ppe]
if "hard_hat" not in ppe_classes:
violations.append({
"type": "no_hard_hat",
"location": person.bbox,
"confidence": person.confidence
})
if "safety_vest" not in ppe_classes:
violations.append({
"type": "no_safety_vest",
"location": person.bbox,
"confidence": person.confidence
})
# Fall protection check: person at height without harness
if self._is_at_height(person, frame) and "harness" not in ppe_classes:
violations.append({
"type": "no_fall_protection",
"location": person.bbox,
"confidence": 0.85,
"estimated_height_ft": self._estimate_height(person, frame)
})
# Equipment exclusion zones
heavy_equipment = [d for d in detections
if d.class_name in ("crane", "excavator")]
for equip in heavy_equipment:
persons_in_zone = self._persons_in_swing_radius(equip, persons)
for p in persons_in_zone:
violations.append({
"type": "exclusion_zone_breach",
"location": p.bbox,
"equipment": equip.class_name,
"estimated_distance_ft": self._estimate_distance(equip, p)
})
# Process violations
for v in violations:
info = self.VIOLATION_TYPES[v["type"]]
v["severity"] = info["severity"]
v["osha_ref"] = info["osha_ref"]
if info["severity"] == "critical":
self.alerts.send_immediate(
camera_id=camera_id,
violation=v,
frame=frame
)
return {
"camera_id": camera_id,
"persons_detected": len(persons),
"violations": violations,
"compliance_score": self._calculate_compliance(len(persons), len(violations))
}
def generate_daily_safety_report(self) -> dict:
"""Compile daily safety analytics."""
return {
"date": datetime.now().strftime("%Y-%m-%d"),
"total_violations": len(self.violation_log),
"by_type": self._group_violations_by_type(),
"by_zone": self._group_violations_by_zone(),
"trend_7day": self._calculate_trend(),
"top_repeat_offenders": self._identify_repeat_locations(),
"safety_score": self._daily_safety_score(),
"recommendations": self._generate_recommendations()
}
AI safety monitoring catches 3-5x more violations than periodic manual inspections. Companies using camera-based safety agents report 40-60% reduction in recordable incidents within 6 months.
3. AI Cost Estimation & Budget Tracking
Cost estimation in construction is part science, part art. Experienced estimators achieve 5-10% accuracy on familiar project types, but AI agents trained on historical bid data can match that accuracy while processing an estimate in hours instead of weeks.
Parametric Cost Estimation Agent
class CostEstimationAgent:
"""AI-powered construction cost estimation."""
def __init__(self, historical_db, material_api, labor_rates):
self.db = historical_db
self.materials = material_api
self.labor = labor_rates
def estimate_project(self, project_spec: dict) -> dict:
"""Generate detailed cost estimate from project specifications."""
# Find similar historical projects
comparables = self.db.find_similar(
project_type=project_spec["type"],
size_sqft=project_spec["size_sqft"],
location=project_spec["location"],
quality_level=project_spec["quality"],
limit=20
)
# Parametric baseline from comparables
avg_cost_sqft = sum(c.final_cost / c.size_sqft for c in comparables) / len(comparables)
baseline = avg_cost_sqft * project_spec["size_sqft"]
# Adjust for current conditions
adjustments = self._calculate_adjustments(project_spec, comparables)
# Detailed line-item breakdown
breakdown = self._generate_breakdown(project_spec, baseline, adjustments)
# Risk contingency
risk_analysis = self._assess_cost_risks(project_spec, comparables)
return {
"project": project_spec["name"],
"baseline_estimate": round(baseline),
"adjustments": adjustments,
"adjusted_estimate": round(baseline * (1 + sum(a["factor"] for a in adjustments))),
"breakdown": breakdown,
"contingency_pct": risk_analysis["recommended_contingency"],
"total_with_contingency": round(
baseline * (1 + sum(a["factor"] for a in adjustments))
* (1 + risk_analysis["recommended_contingency"] / 100)
),
"confidence_range": {
"low": round(baseline * 0.9),
"high": round(baseline * 1.15)
},
"comparable_projects": len(comparables),
"risks": risk_analysis["top_risks"]
}
def _calculate_adjustments(self, spec: dict, comparables: list) -> list:
"""Calculate cost adjustment factors."""
adjustments = []
# Location factor (labor + material costs vary by region)
location_factor = self.labor.get_location_factor(spec["location"])
if abs(location_factor - 1.0) > 0.02:
adjustments.append({
"name": "Location adjustment",
"factor": location_factor - 1.0,
"detail": f"{spec['location']} index: {location_factor:.2f}"
})
# Material escalation (current prices vs historical average)
material_escalation = self.materials.get_escalation_factor(
categories=["steel", "concrete", "lumber", "copper"],
vs_period="12mo_avg"
)
if abs(material_escalation - 1.0) > 0.02:
adjustments.append({
"name": "Material escalation",
"factor": material_escalation - 1.0,
"detail": f"Current vs 12-month avg: {material_escalation:.2f}"
})
# Complexity factor
if spec.get("complexity") == "high":
adjustments.append({
"name": "Complexity premium",
"factor": 0.08,
"detail": "Complex geometry/MEP/site conditions"
})
return adjustments
def track_budget_variance(self, project_id: str) -> dict:
"""Track actual costs against estimate in real-time."""
estimate = self.db.get_estimate(project_id)
actuals = self.db.get_actual_costs(project_id)
committed = self.db.get_committed_costs(project_id)
forecast = {}
for category in estimate["breakdown"]:
cat_name = category["name"]
actual = actuals.get(cat_name, 0)
commit = committed.get(cat_name, 0)
budget = category["amount"]
# Estimate at completion
pct_complete = actual / budget if budget > 0 else 0
if pct_complete > 0.1:
eac = actual / pct_complete # Simple EAC
else:
eac = budget # Too early to forecast
forecast[cat_name] = {
"budget": budget,
"actual_to_date": actual,
"committed": commit,
"estimated_at_completion": round(eac),
"variance": round(budget - eac),
"variance_pct": round((budget - eac) / budget * 100, 1) if budget > 0 else 0,
"status": "on_track" if eac <= budget * 1.05 else "over_budget"
}
return forecast
4. BIM Coordination & Clash Detection
Building Information Modeling (BIM) coordination catches design conflicts before they become expensive field changes. AI agents go beyond geometric clash detection to identify constructibility issues, code violations, and sequencing problems.
class BIMCoordinationAgent:
"""AI-enhanced BIM coordination and clash detection."""
def analyze_model(self, ifc_model) -> dict:
"""Comprehensive BIM model analysis."""
results = {
"geometric_clashes": self._detect_geometric_clashes(ifc_model),
"clearance_violations": self._check_clearances(ifc_model),
"code_compliance": self._check_building_codes(ifc_model),
"constructibility": self._assess_constructibility(ifc_model),
"cost_impact": {}
}
# Prioritize clashes by cost impact
for clash in results["geometric_clashes"]:
clash["estimated_rfi_cost"] = self._estimate_clash_cost(clash)
clash["priority"] = self._classify_priority(clash)
# Sort by priority and cost impact
results["geometric_clashes"].sort(
key=lambda c: (c["priority"] == "critical", c["estimated_rfi_cost"]),
reverse=True
)
total_avoidable = sum(c["estimated_rfi_cost"] for c in results["geometric_clashes"])
results["cost_impact"] = {
"total_rfi_cost_avoided": total_avoidable,
"critical_clashes": len([c for c in results["geometric_clashes"] if c["priority"] == "critical"]),
"total_clashes": len(results["geometric_clashes"])
}
return results
def _check_clearances(self, model) -> list:
"""Check maintenance access and code-required clearances."""
violations = []
# Check electrical panel clearance (NEC 110.26: 36" front clearance)
for panel in model.get_elements("IfcElectricDistributionBoard"):
front_clearance = model.measure_clearance(panel, direction="front")
if front_clearance < 36: # inches
violations.append({
"element": panel.id,
"type": "electrical_panel_clearance",
"code_ref": "NEC 110.26",
"required_inches": 36,
"actual_inches": round(front_clearance, 1),
"location": panel.location
})
# Check ADA door clearances
for door in model.get_elements("IfcDoor"):
if door.get_property("IsAccessible"):
clear_width = door.get_property("OverallWidth")
if clear_width and clear_width < 32:
violations.append({
"element": door.id,
"type": "ada_door_width",
"code_ref": "ADA 404.2.3",
"required_inches": 32,
"actual_inches": round(clear_width, 1)
})
return violations
def _assess_constructibility(self, model) -> list:
"""Identify constructibility issues AI can catch."""
issues = []
# Detect tight MEP routing
for space in model.get_spaces():
mep_density = model.calculate_mep_density(space)
if mep_density > 0.4: # >40% of ceiling plenum
issues.append({
"type": "high_mep_density",
"location": space.name,
"density_pct": round(mep_density * 100),
"impact": "Difficult installation, increased labor hours",
"recommendation": "Consider prefabrication or rerouting"
})
# Detect heavy lifts without crane access
for element in model.get_heavy_elements(min_weight_lbs=2000):
crane_access = model.check_crane_access(element.location)
if not crane_access:
issues.append({
"type": "no_crane_access",
"element": element.id,
"weight_lbs": element.weight,
"location": element.location,
"recommendation": "Plan rigging route or break into smaller assemblies"
})
return issues
AI-enhanced BIM coordination catches 30-40% more issues than traditional geometric-only clash detection. Each clash resolved in design saves $10-50K in field changes.
5. Quality Inspection & Defect Detection
Rework from quality defects costs the construction industry $80 billion annually in the US alone. AI agents using drone imagery, 360-degree cameras, and point cloud data catch defects during construction rather than at final inspection.
class QualityInspectionAgent:
"""Automated quality inspection using computer vision."""
def inspect_concrete_pour(self, images: list, pour_spec: dict) -> dict:
"""Inspect concrete placement quality from images."""
defects = []
for img in images:
analysis = self.vision_model.analyze(img, task="concrete_inspection")
# Check for visible defects
if analysis.get("honeycombing"):
defects.append({
"type": "honeycombing",
"severity": self._classify_honeycombing(analysis["honeycombing"]),
"location": analysis["honeycombing"]["bbox"],
"area_sqft": analysis["honeycombing"]["estimated_area"],
"remediation": "Chip loose material, apply bonding agent, patch with non-shrink grout"
})
if analysis.get("cold_joints"):
defects.append({
"type": "cold_joint",
"severity": "high",
"location": analysis["cold_joints"]["bbox"],
"remediation": "Structural engineer review required"
})
if analysis.get("surface_cracks"):
for crack in analysis["surface_cracks"]:
width_mm = crack.get("estimated_width_mm", 0)
defects.append({
"type": "surface_crack",
"severity": "high" if width_mm > 0.3 else "low",
"width_mm": width_mm,
"length_inches": crack.get("length_inches", 0),
"remediation": "Epoxy injection" if width_mm > 0.3 else "Monitor"
})
return {
"pour_id": pour_spec["id"],
"defects_found": len(defects),
"critical_defects": len([d for d in defects if d["severity"] == "high"]),
"defects": defects,
"overall_quality": "pass" if not any(d["severity"] == "high" for d in defects) else "fail",
"ncr_required": any(d["severity"] == "high" for d in defects)
}
def progress_tracking(self, drone_scan, bim_model) -> dict:
"""Compare as-built conditions to BIM model."""
point_cloud = self._process_drone_scan(drone_scan)
deviations = self._compare_to_bim(point_cloud, bim_model)
return {
"scan_date": datetime.now().isoformat(),
"elements_checked": len(deviations),
"within_tolerance": len([d for d in deviations if d["deviation_inches"] < 0.5]),
"out_of_tolerance": [d for d in deviations if d["deviation_inches"] >= 0.5],
"overall_pct_complete": self._calculate_completion(point_cloud, bim_model),
"behind_schedule_elements": self._identify_lagging_elements(point_cloud, bim_model)
}
6. Resource & Equipment Optimization
Construction equipment utilization averages just 40-60%. AI agents track equipment location, predict utilization, and optimize fleet allocation across multiple job sites.
class ResourceOptimizationAgent:
"""Optimize equipment and labor allocation across projects."""
def optimize_equipment_fleet(self, projects: list, fleet: list) -> dict:
"""Allocate equipment across projects to minimize idle time and rental costs."""
allocations = []
total_savings = 0
# Build demand matrix: project x equipment_type x week
demand = self._build_demand_matrix(projects)
available = self._build_availability_matrix(fleet)
for week in demand["weeks"]:
week_demand = demand["matrix"][week]
week_available = available["matrix"][week]
for equip_type in week_demand:
needed = week_demand[equip_type]
owned = week_available.get(equip_type, 0)
gap = needed - owned
if gap > 0:
# Need rental - find cheapest option
rental = self._find_best_rental(equip_type, gap, week)
allocations.append({
"week": week,
"type": equip_type,
"action": "rent",
"quantity": gap,
"cost": rental["cost"],
"vendor": rental["vendor"]
})
elif gap < 0:
# Excess capacity - consider sublease
sublease_value = abs(gap) * self._get_sublease_rate(equip_type)
allocations.append({
"week": week,
"type": equip_type,
"action": "sublease",
"quantity": abs(gap),
"revenue": sublease_value
})
total_savings += sublease_value
return {
"allocations": allocations,
"total_rental_cost": sum(a.get("cost", 0) for a in allocations),
"total_sublease_revenue": total_savings,
"fleet_utilization_pct": self._calculate_utilization(allocations, fleet),
"recommendations": self._generate_fleet_recommendations(allocations)
}
def optimize_labor_schedule(self, project_tasks: list, labor_pool: list) -> dict:
"""Optimize crew assignments to minimize idle time between tasks."""
assignments = []
# Sort tasks by start date
sorted_tasks = sorted(project_tasks, key=lambda t: t.planned_start)
for task in sorted_tasks:
# Find best-fit crew: right trade, available, minimal travel
candidates = [w for w in labor_pool
if w.trade == task.trade and w.is_available(task.planned_start)]
if candidates:
# Score by: skill match, travel distance, continuity bonus
scored = []
for worker in candidates:
score = (
worker.skill_rating * 0.4 +
(1 - worker.travel_distance(task.location) / 100) * 0.3 +
(1.0 if worker.current_project == task.project_id else 0) * 0.3
)
scored.append((worker, score))
scored.sort(key=lambda x: x[1], reverse=True)
best = scored[:task.crew_size]
assignments.append({
"task": task.name,
"crew": [w.id for w, _ in best],
"avg_skill": sum(w.skill_rating for w, _ in best) / len(best),
"avg_score": sum(s for _, s in best) / len(best)
})
return {"assignments": assignments}
Platform Comparison
| Platform | Best For | Safety | Scheduling | Pricing |
|---|---|---|---|---|
| OpenSpace | Progress tracking, 360° capture | Basic | Via integrations | $5K-30K/project |
| Buildots | Automated progress monitoring | No | Good (BIM-linked) | Enterprise |
| Smartvid.io | Safety monitoring, PPE detection | Excellent | No | $50K+/yr |
| ALICE Technologies | Schedule optimization | No | Excellent (AI) | Enterprise |
| Procore + AI add-ons | All-in-one project management | Via partners | Good | $500-2K/mo |
| Custom (Python + CV) | Full control, specific workflows | Build your own | Build your own | Dev time |
ROI Calculator
For a mid-size general contractor ($200M annual revenue, 10 active projects):
| Workflow | Annual Savings | Implementation Cost | Payback |
|---|---|---|---|
| Schedule risk prediction | $2-6M (avoided delays/LD) | $200-500K | 1-3 months |
| Safety monitoring | $1-3M (reduced incidents/EMR) | $100-300K | 1-4 months |
| AI cost estimation | $3-8M (better bid accuracy) | $150-400K | 1-2 months |
| BIM coordination | $1.5-4M (avoided RFIs/rework) | $100-250K | 1-2 months |
| Quality inspection | $1-3M (reduced rework) | $150-350K | 2-4 months |
| Resource optimization | $500K-2M (equipment/labor) | $100-200K | 2-4 months |
| Total | $9-26M/yr | $800K-2M | 1-3 months |
Implementation Roadmap
Phase 1: Quick Wins (Months 1-3)
- Deploy safety camera monitoring on highest-risk projects
- Implement schedule tracking dashboard with delay prediction
- Start collecting historical data for cost estimation model
Phase 2: Core Automation (Months 4-6)
- Launch AI cost estimation (requires 500+ historical projects minimum)
- Deploy BIM coordination agent for upcoming projects
- Implement equipment fleet optimization across all sites
Phase 3: Advanced (Months 7-12)
- Drone-based progress tracking with BIM comparison
- Quality inspection automation for concrete, steel, MEP
- Predictive resource planning across entire portfolio
Common Anti-Patterns
- Skipping data collection: AI cost estimation needs 500+ projects with final costs. Start collecting structured data now even if the AI model comes later.
- Camera-only safety: Cameras catch PPE violations but miss procedural issues (lockout/tagout, hot work permits). Combine with digital permit systems.
- Ignoring field adoption: The best AI system fails if superintendents don't trust it. Start with dashboards that augment their judgment, not replace it.
- Over-automating BIM: Not every clash needs AI. Focus on cross-discipline clashes (MEP vs structural) where coordination value is highest.
Build Your Construction AI Agent
Get our free AI Agent Starter Kit with templates, deployment guides, and security checklists for construction applications.
Download Starter KitAI Agents Weekly Newsletter
Stay updated on the latest in AI agents, automation, and industry applications. Free, 3x/week.
Subscribe Free