Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add jdmorag97-rgb/DDC_Skills_for_AI_Agents_in_Construction --skill equipment-telematicsgit clone --depth 1 https://github.com/jdmorag97-rgb/DDC_Skills_for_AI_Agents_in_ConstructionWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/equipment-telematics)<a href="https://agentmods.dev/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/equipment-telematics"><img src="https://agentmods.dev/badge/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/equipment-telematics/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/equipment-telematics"><img src="https://agentmods.dev/badge/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/equipment-telematics.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00032 | $0.05248 |
| Opus 5 | $0.00016 | $0.02624 |
| Sonnet 5 | $0.00006 | $0.01050 |
| Haiku 4.5 | $0.00003 | $0.00525 |
Grade A, and why
equipment-telematics scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 9d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 667 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Equipment Telematics
Overview
Integrate telematics data from heavy construction equipment (excavators, cranes, loaders, trucks) to monitor utilization, track location, analyze fuel efficiency, predict maintenance needs, and ensure safe operation.
Telematics Data Flow
┌─────────────────────────────────────────────────────────────────┐
│ EQUIPMENT TELEMATICS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ EQUIPMENT TELEMATICS ANALYTICS │
│ ───────── ────────── ───────── │
│ │
│ 🚜 Excavator ────┐ 📍 Location 📊 Utilization│
│ 🏗️ Crane ────┼──────→ 🔧 Engine Hours ────────→ ⛽ Fuel │
│ 🚛 Truck ────┤ ⛽ Fuel Level 🔧 Maintenance│
│ 🚧 Loader ────┘ ⚡ Performance 👷 Operator │
│ │
│ METRICS TRACKED: │
│ • GPS location and geofencing │
│ • Engine hours and idle time │
│ • Fuel consumption rate │
│ • Load cycles and productivity │
│ • Fault codes and diagnostics │
│ • Operator behavior and safety │
│ │
└─────────────────────────────────────────────────────────────────┘
Technical Implementation
from dataclasses import dataclass, field
from typing import List, Dict, Optional, Tuple
from datetime import datetime, timedelta
from enum import Enum
import statistics
import math
class EquipmentType(Enum):
EXCAVATOR = "excavator"
CRANE = "crane"
LOADER = "loader"
BULLDOZER = "bulldozer"
DUMP_TRUCK = "dump_truck"
CONCRETE_MIXER = "concrete_mixer"
FORKLIFT = "forklift"
COMPACTOR = "compactor"
GRADER = "grader"
TELEHANDLER = "telehandler"
class OperatingStatus(Enum):
OPERATING = "operating"
IDLE = "idle"
OFF = "off"
MAINTENANCE = "maintenance"
FAULT = "fault"
class FaultSeverity(Enum):
INFO = "info"
WARNING = "warning"
CRITICAL = "critical"
SHUTDOWN = "shutdown"
@dataclass
class GPSLocation:
latitude: float
longitude: float
altitude: float = 0.0
speed: float = 0.0
heading: float = 0.0
timestamp: datetime = field(default_factory=datetime.now)
@dataclass
class TelematicsReading:
equipment_id: str
timestamp: datetime
location: GPSLocation
engine_hours: float
fuel_level: float # Percentage
fuel_rate: float # L/hr
engine_rpm: int
hydraulic_temp: float
coolant_temp: float
operating_status: OperatingStatus
load_percentage: float = 0.0
operator_id: str = ""
@dataclass
class FaultCode:
code: str
description: str
severity: FaultSeverity
timestamp: datetime
equipment_id: str
resolved: bool = False
@dataclass
class Equipment:
id: str
name: str
equipment_type: EquipmentType
make: str
model: str
year: int
serial_number: str
hourly_rate: float = 0.0
fuel_capacity: float = 0.0 # Liters
current_hours: float = 0.0
next_service_hours: float = 0.0
assigned_site: str = ""
assigned_operator: str = ""
@dataclass
class Geofence:
id: str
name: str
center_lat: float
center_lon: float
radius_meters: float
allowed_equipment: List[str] = field(default_factory=list)
@dataclass
class UtilizationReport:
equipment_id: str
period_start: datetime
period_end: datetime
total_hours: float
operating_hours: float
idle_hours: float
off_hours: float
utilization_pct: float
idle_pct: float
fuel_consumed: float
fuel_efficiency: float # L/operating hour
cycles: int
class EquipmentTelematics:
"""Integrate and analyze equipment telematics data."""
# Maintenance intervals by type (hours)
SERVICE_INTERVALS = {
EquipmentType.EXCAVATOR: 250,
EquipmentType.CRANE: 200,
EquipmentType.LOADER: 250,
EquipmentType.BULLDOZER: 250,
EquipmentType.DUMP_TRUCK: 300,
}
# Typical fuel rates (L/hr)
TYPICAL_FUEL_RATES = {
EquipmentType.EXCAVATOR: 15,
EquipmentType.CRANE: 12,
EquipmentType.LOADER: 18,
EquipmentType.BULLDOZER: 25,
EquipmentType.DUMP_TRUCK: 20,
}
def __init__(self, fleet_name: str):
self.fleet_name = fleet_name
self.equipment: Dict[str, Equipment] = {}
self.readings: List[TelematicsReading] = []
self.faults: List[FaultCode] = []
self.geofences: Dict[str, Geofence] = {}
def register_equipment(self, id: str, name: str, equipment_type: EquipmentType,
make: str, model: str, year: int, serial_number: str,
hourly_rate: float = 0, fuel_capacity: float = 0) -> Equipment:
"""Register equipment in fleet."""
equipment = Equipment(
id=id,
name=name,
equipment_type=equipment_type,
make=make,
model=model,
year=year,
serial_number=serial_number,
hourly_rate=hourly_rate,
fuel_capacity=fuel_capacity
)
self.equipment[id] = equipment
return equipment
def add_geofence(self, id: str, name: str, center_lat: float,
center_lon: float, radius_meters: float,
allowed_equipment: List[str] = None) -> Geofence:
"""Add geofence boundary."""
geofence = Geofence(
id=id,
name=name,
center_lat=center_lat,
center_lon=center_lon,
radius_meters=radius_meters,
allowed_equipment=allowed_equipment or []
)
self.geofences[id] = geofence
return geofence
def ingest_reading(self, equipment_id: str, location: GPSLocation,
engine_hours: float, fuel_level: float, fuel_rate: float,
engine_rpm: int, hydraulic_temp: float, coolant_temp: float,
load_percentage: float = 0, operator_id: str = "") -> TelematicsReading:
"""Ingest telematics reading from equipment."""
if equipment_id not in self.equipment:
raise ValueError(f"Unknown equipment: {equipment_id}")
# Determine operating status
if engine_rpm == 0:
status = OperatingStatus.OFF
elif engine_rpm < 800 or load_percentage < 10:
status = OperatingStatus.IDLE
else:
status = OperatingStatus.OPERATING
reading = TelematicsReading(
equipment_id=equipment_id,
timestamp=location.timestamp,
location=location,
engine_hours=engine_hours,
fuel_level=fuel_level,
fuel_rate=fuel_rate,
engine_rpm=engine_rpm,
hydraulic_temp=hydraulic_temp,
coolant_temp=coolant_temp,
operating_status=status,
load_percentage=load_percentage,
operator_id=operator_id
)
self.readings.append(reading)
# Update equipment status
equip = self.equipment[equipment_id]
equip.current_hours = engine_hours
# Check for issues
self._check_diagnostics(equipment_id, reading)
self._check_geofence(equipment_id, location)
return reading
def _check_diagnostics(self, equipment_id: str, reading: TelematicsReading):
"""Check for diagnostic issues."""
equip = self.equipment[equipment_id]
# High temperature warning
if reading.hydraulic_temp > 90:
self._add_fault(equipment_id, "HYD_TEMP_HIGH",
"Hydraulic temperature high", FaultSeverity.WARNING)
if reading.coolant_temp > 100:
self._add_fault(equipment_id, "COOLANT_TEMP_HIGH",
"Coolant temperature critical", FaultSeverity.CRITICAL)
# Low fuel warning
if reading.fuel_level < 15:
self._add_fault(equipment_id, "FUEL_LOW",
"Fuel level below 15%", FaultSeverity.WARNING)
# Service due
service_interval = self.SERVICE_INTERVALS.get(equip.equipment_type, 250)
hours_to_service = equip.next_service_hours - reading.engine_hours
if hours_to_service < 0:
self._add_fault(equipment_id, "SERVICE_OVERDUE",
"Maintenance service overdue", FaultSeverity.WARNING)
elif hours_to_service < 50:
self._add_fault(equipment_id, "SERVICE_DUE",
f"Service due in {hours_to_service:.0f} hours", FaultSeverity.INFO)
def _check_geofence(self, equipment_id: str, location: GPSLocation):
"""Check geofence violations."""
for geofence in self.geofences.values():
# Calculate distance from center
distance = self._haversine_distance(
location.latitude, location.longitude,
geofence.center_lat, geofence.center_lon
)
if distance > geofence.radius_meters:
if (not geofence.allowed_equipment or
equipment_id in geofence.allowed_equipment):
self._add_fault(equipment_id, "GEOFENCE_EXIT",
f"Equipment left {geofence.name} boundary",
FaultSeverity.WARNING)
def _haversine_distance(self, lat1: float, lon1: float,
lat2: float, lon2: float) -> float:
"""Calculate distance between two coordinates in meters."""
R = 6371000 # Earth radius in meters
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
delta_phi = math.radians(lat2 - lat1)
delta_lambda = math.radians(lon2 - lon1)
a = (math.sin(delta_phi/2)**2 +
math.cos(phi1) * math.cos(phi2) * math.sin(delta_lambda/2)**2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return R * c
def _add_fault(self, equipment_id: str, code: str,
description: str, severity: FaultSeverity):
"""Add fault code."""
# Check if same fault already active
existing = [f for f in self.faults
if f.equipment_id == equipment_id
and f.code == code
and not f.resolved]
if existing:
return
fault = FaultCode(
code=code,
description=description,
severity=severity,
timestamp=datetime.now(),
equipment_id=equipment_id
)
self.faults.append(fault)
def get_current_status(self, equipment_id: str) -> Dict:
"""Get current status of equipment."""
if equipment_id not in self.equipment:
raise ValueError(f"Unknown equipment: {equipment_id}")
equip = self.equipment[equipment_id]
# Get latest reading
readings = [r for r in self.readings if r.equipment_id == equipment_id]
if not readings:
return {"equipment": equip, "status": "no_data"}
latest = max(readings, key=lambda r: r.timestamp)
# Active faults
active_faults = [f for f in self.faults
if f.equipment_id == equipment_id and not f.resolved]
return {
"equipment_id": equip.id,
"name": equip.name,
"type": equip.equipment_type.value,
"status": latest.operating_status.value,
"location": {
"lat": latest.location.latitude,
"lon": latest.location.longitude,
"speed": latest.location.speed
},
"engine_hours": latest.engine_hours,
"fuel_level": latest.fuel_level,
"fuel_rate": latest.fuel_rate,
"temps": {
"hydraulic": latest.hydraulic_temp,
"coolant": latest.coolant_temp
},
"operator": latest.operator_id,
"active_faults": len(active_faults),
"last_update": latest.timestamp
}
def calculate_utilization(self, equipment_id: str,
start_date: datetime,
end_date: datetime) -> UtilizationReport:
"""Calculate utilization metrics for equipment."""
readings = [r for r in self.readings
if r.equipment_id == equipment_id
and start_date <= r.timestamp <= end_date]
if not readings:
return None
readings.sort(key=lambda r: r.timestamp)
total_hours = (end_date - start_date).total_seconds() / 3600
operating_hours = 0
idle_hours = 0
fuel_consumed = 0
# Calculate from readings
for i in range(1, len(readings)):
prev = readings[i-1]
curr = readings[i]
interval_hours = (curr.timestamp - prev.timestamp).total_seconds() / 3600
if prev.operating_status == OperatingStatus.OPERATING:
operating_hours += interval_hours
fuel_consumed += prev.fuel_rate * interval_hours
elif prev.operating_status == OperatingStatus.IDLE:
idle_hours += interval_hours
fuel_consumed += prev.fuel_rate * interval_hours * 0.3 # Idle uses ~30% fuel
off_hours = total_hours - operating_hours - idle_hours
utilization_pct = (operating_hours / total_hours * 100) if total_hours > 0 else 0
idle_pct = (idle_hours / (operating_hours + idle_hours) * 100) if (operating_hours + idle_hours) > 0 else 0
fuel_efficiency = (fuel_consumed / operating_hours) if operating_hours > 0 else 0
return UtilizationReport(
equipment_id=equipment_id,
period_start=start_date,
period_end=end_date,
total_hours=total_hours,
operating_hours=operating_hours,
idle_hours=idle_hours,
off_hours=off_hours,
utilization_pct=utilization_pct,
idle_pct=idle_pct,
fuel_consumed=fuel_consumed,
fuel_efficiency=fuel_efficiency,
cycles=0 # Would need load cycle detection
)
def get_fleet_summary(self) -> Dict:
"""Get summary of entire fleet."""
summary = {
"total_equipment": len(self.equipment),
"by_status": {},
"by_type": {},
"active_faults": 0,
"service_due": []
}
for equip in self.equipment.values():
# Count by type
eq_type = equip.equipment_type.value
summary["by_type"][eq_type] = summary["by_type"].get(eq_type, 0) + 1
# Get current status
try:
status = self.get_current_status(equip.id)
op_status = status.get("status", "unknown")
summary["by_status"][op_status] = summary["by_status"].get(op_status, 0) + 1
# Check service due
service_interval = self.SERVICE_INTERVALS.get(equip.equipment_type, 250)
hours_to_service = equip.next_service_hours - equip.current_hours
if hours_to_service < 50:
summary["service_due"].append({
"equipment": equip.name,
"hours_remaining": hours_to_service
})
except Exception:
summary["by_status"]["unknown"] = summary["by_status"].get("unknown", 0) + 1
# Count active faults
summary["active_faults"] = len([f for f in self.faults if not f.resolved])
return summary
def predict_maintenance(self, equipment_id: str) -> Dict:
"""Predict maintenance needs based on usage patterns."""
if equipment_id not in self.equipment:
raise ValueError(f"Unknown equipment: {equipment_id}")
equip = self.equipment[equipment_id]
# Calculate average daily hours
week_ago = datetime.now() - timedelta(days=7)
recent_readings = [r for r in self.readings
if r.equipment_id == equipment_id
and r.timestamp > week_ago]
if len(recent_readings) < 2:
return {"prediction": "insufficient_data"}
hours_start = min(r.engine_hours for r in recent_readings)
hours_end = max(r.engine_hours for r in recent_readings)
days = (max(r.timestamp for r in recent_readings) -
min(r.timestamp for r in recent_readings)).days or 1
daily_hours = (hours_end - hours_start) / days
# Predict service date
service_interval = self.SERVICE_INTERVALS.get(equip.equipment_type, 250)
hours_to_service = equip.next_service_hours - equip.current_hours
if daily_hours > 0:
days_to_service = hours_to_service / daily_hours
service_date = datetime.now() + timedelta(days=days_to_service)
else:
service_date = None
return {
"equipment_id": equipment_id,
"current_hours": equip.current_hours,
"next_service_hours": equip.next_service_hours,
"hours_to_service": hours_to_service,
"avg_daily_hours": daily_hours,
"predicted_service_date": service_date,
"service_type": "Routine maintenance",
"estimated_downtime_hours": 8
}
def generate_report(self) -> str:
"""Generate fleet telematics report."""
summary = self.get_fleet_summary()
lines = [
"# Equipment Telematics Report",
"",
f"**Fleet:** {self.fleet_name}",
f"**Report Date:** {datetime.now().strftime('%Y-%m-%d %H:%M')}",
"",
"## Fleet Summary",
"",
f"| Metric | Value |",
f"|--------|-------|",
f"| Total Equipment | {summary['total_equipment']} |",
f"| Active Faults | {summary['active_faults']} |",
f"| Service Due | {len(summary['service_due'])} |",
"",
"## Status Distribution",
""
]
for status, count in summary["by_status"].items():
lines.append(f"- {status}: {count}")
# Equipment details
lines.extend([
"",
"## Equipment Status",
"",
"| Equipment | Type | Status | Hours | Fuel | Faults |",
"|-----------|------|--------|-------|------|--------|"
])
for equip in self.equipment.values():
try:
status = self.get_current_status(equip.id)
status_icon = "✅" if status['status'] == 'operating' else "⏸️" if status['status'] == 'idle' else "⏹️"
lines.append(
f"| {equip.name} | {equip.equipment_type.value} | "
f"{status_icon} {status['status']} | {status['engine_hours']:.0f} | "
f"{status['fuel_level']:.0f}% | {status['active_faults']} |"
)
except Exception:
lines.append(
f"| {equip.name} | {equip.equipment_type.value} | ⚠️ No data | - | - | - |"
)
# Service due
if summary["service_due"]:
lines.extend([
"",
"## Service Due Soon",
"",
"| Equipment | Hours Remaining |",
"|-----------|-----------------|"
])
for svc in summary["service_due"]:
lines.append(f"| {svc['equipment']} | {svc['hours_remaining']:.0f} |")
# Active faults
active_faults = [f for f in self.faults if not f.resolved]
if active_faults:
lines.extend([
"",
"## Active Faults",
"",
"| Equipment | Code | Description | Severity |",
"|-----------|------|-------------|----------|"
])
for fault in active_faults[:10]:
sev_icon = "🔴" if fault.severity == FaultSeverity.CRITICAL else "🟡"
equip = self.equipment.get(fault.equipment_id)
lines.append(
f"| {equip.name if equip else fault.equipment_id} | "
f"{fault.code} | {fault.description} | {sev_icon} {fault.severity.value} |"
)
return "\n".join(lines)
What ships with it
2 files beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 9d ago First seen · 667 lines · 32 tokens per session scan A 6470447e61f9
equipment-telematics is a skill published in the GitHub repository jdmorag97-rgb/DDC_Skills_for_AI_Agents_in_Construction (2 stars, last pushed 6mo ago), licensed MIT. It adds 32 tokens to every session and 5,248 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-03.
Other skills, from other repositories
gke-compute-classes
Configures, optimizes, and troubleshoots GKE ComputeClasses. Use when configuring Spot VMs with on-demand fallback, targeting specific accelerators (GPUs/TPUs) or machine families, restricting ComputeClass access, or debugging pending pods related to node pool auto-creation. Do not use for cluster-level Node Auto…
jetson-diagnostic
Read-only Jetson health snapshot for identity, memory, GPU, thermal, power, storage, services, and top processes.
doca-socket-relay
Use this skill when the operator is driving the DOCA Socket Relay to bridge a socket-oriented host application onto a BlueField DPU peer without rewriting it — picking the deployment shape (in-process, sidecar, or BlueField service container), configuring the host-side socket and the DPU-side forwarding endpoint…
offensive-z-wave
Z-Wave attack methodology — sniffing with Z-Force / EZ-Wave / RTL-SDR + ZniffMobile, S0 (legacy) network-key derivation flaw and key reuse, S2 (modern) ECDH commissioning analysis, replay/injection on unauthenticated nodes, default-key brute-force on test deployments, and home-automation hub pivots. Use when targeting…
hsb-flash
Flash the FPGA on an HSB board connected to an NVIDIA devkit. Supports HSB Lattice boards (FPGA versions 2407, 2412, 2507, 2510) and Leopard Imaging VB1940 "all-in-one" cameras (FPGA versions 2507, 2510). Uses release-specific YAML manifests and board-type-specific program commands. Lattice and VB1940 commands must…
jetson-validate-image
Use after jetson-flash-image to run static BSP checks, on-target smoke/regression tests on a flashed DUT, or both. Not for build or flash steps. Triggers: validate bsp, on-target validation.