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 ml-model-buildergit 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/ml-model-builder)<a href="https://agentmods.dev/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/ml-model-builder"><img src="https://agentmods.dev/badge/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/ml-model-builder/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/ml-model-builder"><img src="https://agentmods.dev/badge/skills/jdmorag97-rgb/ddc_skills_for_ai_agents_in_construction/ml-model-builder.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.00025 | $0.03698 |
| Opus 5 | $0.00013 | $0.01849 |
| Sonnet 5 | $0.00005 | $0.00740 |
| Haiku 4.5 | $0.00003 | $0.00370 |
Grade A, and why
ml-model-builder 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 8d 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.
This is a copy
100% identical to ml-model-builder — 0 lines differ, which has more behind it and is treated as the original. This page carries a canonical link to it rather than competing with it.
How it starts
The opening of the file, as written. The whole thing — 499 lines — stays where its author put it; the contents beside it link to each section on GitHub.
ML Model Builder
Business Case
Problem Statement
Construction prediction challenges:
- Complex relationships between variables
- Limited historical data utilization
- Need for multiple prediction targets
- Model validation and deployment
Solution
Comprehensive ML model building framework for construction predictions with data preprocessing, model training, evaluation, and export capabilities.
Technical Implementation
import pandas as pd
import numpy as np
from typing import Dict, Any, List, Optional, Tuple, Callable
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
import json
import math
class PredictionTarget(Enum):
COST = "cost"
DURATION = "duration"
RISK_SCORE = "risk_score"
PRODUCTIVITY = "productivity"
QUALITY = "quality"
class AlgorithmType(Enum):
LINEAR_REGRESSION = "linear_regression"
RIDGE_REGRESSION = "ridge_regression"
KNN = "knn"
DECISION_TREE = "decision_tree"
ENSEMBLE = "ensemble"
class FeatureType(Enum):
NUMERIC = "numeric"
CATEGORICAL = "categorical"
BOOLEAN = "boolean"
DATE = "date"
@dataclass
class Feature:
name: str
feature_type: FeatureType
importance: float = 0.0
categories: List[str] = field(default_factory=list)
@dataclass
class ModelMetrics:
mae: float
mape: float
rmse: float
r_squared: float
samples: int
@dataclass
class TrainedModel:
model_id: str
target: PredictionTarget
algorithm: AlgorithmType
features: List[Feature]
metrics: ModelMetrics
coefficients: Dict[str, float]
intercept: float
trained_at: datetime
training_samples: int
class MLModelBuilder:
"""Build and train ML models for construction predictions."""
def __init__(self, project_name: str = "Construction ML"):
self.project_name = project_name
self.models: Dict[str, TrainedModel] = {}
self.feature_stats: Dict[str, Dict[str, float]] = {}
self.categorical_encodings: Dict[str, Dict[str, int]] = {}
def prepare_data(self, df: pd.DataFrame,
target_column: str,
feature_columns: List[str],
test_size: float = 0.2) -> Tuple[np.ndarray, np.ndarray,
np.ndarray, np.ndarray]:
"""Prepare and split data for training."""
# Handle missing values
df = df.dropna(subset=[target_column] + feature_columns)
# Encode categorical features
X_processed = []
for col in feature_columns:
if df[col].dtype == 'object':
# Categorical encoding
if col not in self.categorical_encodings:
unique_vals = df[col].unique()
self.categorical_encodings[col] = {v: i for i, v in enumerate(unique_vals)}
encoded = df[col].map(self.categorical_encodings[col]).fillna(0)
X_processed.append(encoded.values)
else:
# Numeric - normalize
values = df[col].values
if col not in self.feature_stats:
self.feature_stats[col] = {
'mean': np.mean(values),
'std': np.std(values) or 1
}
normalized = (values - self.feature_stats[col]['mean']) / self.feature_stats[col]['std']
X_processed.append(normalized)
X = np.column_stack(X_processed)
y = df[target_column].values
# Train-test split
n = len(df)
indices = np.random.permutation(n)
test_n = int(n * test_size)
test_indices = indices[:test_n]
train_indices = indices[test_n:]
X_train = X[train_indices]
X_test = X[test_indices]
y_train = y[train_indices]
y_test = y[test_indices]
return X_train, X_test, y_train, y_test
def train_linear_regression(self, X: np.ndarray, y: np.ndarray,
regularization: float = 0.0) -> Tuple[np.ndarray, float]:
"""Train linear regression model."""
# Add intercept
X_with_intercept = np.column_stack([np.ones(len(X)), X])
if regularization > 0:
# Ridge regression
n_features = X_with_intercept.shape[1]
reg_matrix = regularization * np.eye(n_features)
reg_matrix[0, 0] = 0 # Don't regularize intercept
XtX = X_with_intercept.T @ X_with_intercept + reg_matrix
else:
XtX = X_with_intercept.T @ X_with_intercept
try:
XtX_inv = np.linalg.inv(XtX)
beta = XtX_inv @ X_with_intercept.T @ y
except np.linalg.LinAlgError:
# Use pseudoinverse if singular
beta = np.linalg.pinv(X_with_intercept) @ y
return beta[1:], beta[0]
def train_knn_model(self, X_train: np.ndarray, y_train: np.ndarray,
k: int = 5) -> Callable:
"""Create k-NN prediction function."""
def predict(X_new: np.ndarray) -> np.ndarray:
predictions = []
for x in X_new:
distances = np.sqrt(np.sum((X_train - x) ** 2, axis=1))
nearest_indices = np.argsort(distances)[:k]
nearest_values = y_train[nearest_indices]
predictions.append(np.mean(nearest_values))
return np.array(predictions)
return predict
def calculate_metrics(self, y_true: np.ndarray,
y_pred: np.ndarray) -> ModelMetrics:
"""Calculate model performance metrics."""
residuals = y_true - y_pred
mae = np.mean(np.abs(residuals))
mape = np.mean(np.abs(residuals / (y_true + 1e-10))) * 100
rmse = math.sqrt(np.mean(residuals ** 2))
# R-squared
ss_res = np.sum(residuals ** 2)
ss_tot = np.sum((y_true - np.mean(y_true)) ** 2)
r_squared = 1 - (ss_res / (ss_tot + 1e-10))
return ModelMetrics(
mae=round(mae, 2),
mape=round(mape, 2),
rmse=round(rmse, 2),
r_squared=round(r_squared, 4),
samples=len(y_true)
)
def build_model(self, df: pd.DataFrame,
target_column: str,
feature_columns: List[str],
target_type: PredictionTarget,
algorithm: AlgorithmType = AlgorithmType.LINEAR_REGRESSION,
model_id: str = None,
**kwargs) -> TrainedModel:
"""Build and train a prediction model."""
model_id = model_id or f"{target_type.value}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
# Prepare data
X_train, X_test, y_train, y_test = self.prepare_data(
df, target_column, feature_columns,
test_size=kwargs.get('test_size', 0.2)
)
# Train model based on algorithm
if algorithm == AlgorithmType.LINEAR_REGRESSION:
coefficients, intercept = self.train_linear_regression(X_train, y_train)
y_pred = X_test @ coefficients + intercept
elif algorithm == AlgorithmType.RIDGE_REGRESSION:
coefficients, intercept = self.train_linear_regression(
X_train, y_train,
regularization=kwargs.get('alpha', 1.0)
)
y_pred = X_test @ coefficients + intercept
elif algorithm == AlgorithmType.KNN:
predict_fn = self.train_knn_model(
X_train, y_train,
k=kwargs.get('k', 5)
)
y_pred = predict_fn(X_test)
coefficients = np.zeros(len(feature_columns))
intercept = np.mean(y_train)
else:
# Default to linear
coefficients, intercept = self.train_linear_regression(X_train, y_train)
y_pred = X_test @ coefficients + intercept
# Calculate metrics
metrics = self.calculate_metrics(y_test, y_pred)
# Calculate feature importance (based on coefficient magnitude)
coef_abs = np.abs(coefficients)
importance_sum = np.sum(coef_abs) or 1
importances = coef_abs / importance_sum
features = [
Feature(
name=col,
feature_type=FeatureType.CATEGORICAL if col in self.categorical_encodings else FeatureType.NUMERIC,
importance=round(float(importances[i]), 4),
categories=list(self.categorical_encodings.get(col, {}).keys())
)
for i, col in enumerate(feature_columns)
]
# Create model object
model = TrainedModel(
model_id=model_id,
target=target_type,
algorithm=algorithm,
features=features,
metrics=metrics,
coefficients={col: float(coefficients[i]) for i, col in enumerate(feature_columns)},
intercept=float(intercept),
trained_at=datetime.now(),
training_samples=len(X_train)
)
self.models[model_id] = model
return model
def predict(self, model_id: str, features: Dict[str, Any]) -> Dict[str, Any]:
"""Make prediction using trained model."""
if model_id not in self.models:
return {'error': 'Model not found'}
model = self.models[model_id]
# Process features
feature_values = []
for feat in model.features:
value = features.get(feat.name)
if feat.feature_type == FeatureType.CATEGORICAL:
encoded = self.categorical_encodings.get(feat.name, {}).get(value, 0)
feature_values.append(encoded)
else:
# Normalize
stats = self.feature_stats.get(feat.name, {'mean': 0, 'std': 1})
normalized = (value - stats['mean']) / stats['std']
feature_values.append(normalized)
# Calculate prediction
feature_array = np.array(feature_values)
coef_array = np.array([model.coefficients[f.name] for f in model.features])
prediction = float(np.dot(feature_array, coef_array) + model.intercept)
return {
'model_id': model_id,
'prediction': round(prediction, 2),
'model_metrics': {
'mae': model.metrics.mae,
'r_squared': model.metrics.r_squared
},
'feature_contributions': {
f.name: round(feature_values[i] * model.coefficients[f.name], 2)
for i, f in enumerate(model.features)
}
}
def compare_models(self, model_ids: List[str] = None) -> pd.DataFrame:
"""Compare multiple models."""
models = [self.models[m] for m in (model_ids or self.models.keys())]
data = [{
'Model ID': m.model_id,
'Target': m.target.value,
'Algorithm': m.algorithm.value,
'MAE': m.metrics.mae,
'MAPE %': m.metrics.mape,
'RMSE': m.metrics.rmse,
'R²': m.metrics.r_squared,
'Training Samples': m.training_samples,
'Features': len(m.features)
} for m in models]
return pd.DataFrame(data)
def get_feature_importance(self, model_id: str) -> pd.DataFrame:
"""Get feature importance for a model."""
if model_id not in self.models:
return pd.DataFrame()
model = self.models[model_id]
data = [{
'Feature': f.name,
'Importance': f.importance,
'Coefficient': model.coefficients.get(f.name, 0),
'Type': f.feature_type.value
} for f in sorted(model.features, key=lambda x: x.importance, reverse=True)]
return pd.DataFrame(data)
def export_model(self, model_id: str, output_path: str) -> str:
"""Export model to JSON."""
if model_id not in self.models:
return ""
model = self.models[model_id]
export_data = {
'model_id': model.model_id,
'target': model.target.value,
'algorithm': model.algorithm.value,
'trained_at': model.trained_at.isoformat(),
'training_samples': model.training_samples,
'metrics': {
'mae': model.metrics.mae,
'mape': model.metrics.mape,
'rmse': model.metrics.rmse,
'r_squared': model.metrics.r_squared
},
'coefficients': model.coefficients,
'intercept': model.intercept,
'features': [
{
'name': f.name,
'type': f.feature_type.value,
'importance': f.importance
}
for f in model.features
],
'preprocessing': {
'feature_stats': self.feature_stats,
'categorical_encodings': self.categorical_encodings
}
}
with open(output_path, 'w') as f:
json.dump(export_data, f, indent=2)
return output_path
def export_to_excel(self, output_path: str) -> str:
"""Export all models summary to Excel."""
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# Model comparison
comparison = self.compare_models()
comparison.to_excel(writer, sheet_name='Model Comparison', index=False)
# Feature importance for each model
for model_id in self.models:
importance = self.get_feature_importance(model_id)
sheet_name = f"Features_{model_id}"[:31]
importance.to_excel(writer, sheet_name=sheet_name, index=False)
return output_path
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.
- 8d ago First seen · 499 lines · 25 tokens per session scan A bfd0685c313e
ml-model-builder 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 25 tokens to every session and 3,698 once invoked, about $0.0001 per session on Opus 5. A static security scan graded it A with 0 findings. It is 100% identical to ml-model-builder, differing in 0 lines, and is treated as a copy.
Other skills, from other repositories
agent-platform-rag-engine-management
Manage and query Agent Platform RAG Engine Corpora and retrieve grounded contexts using the Google GenAI SDK. Use when listing RAG corpora or files, inspecting a corpus, retrieving contexts, or generating content grounded in a RAG corpus. Do not use for standard database queries (use SQL/Spanner skills), Google…
agent-platform-model-registry
Agent Platform Model Registry Management. Use when you need to upload, list, describe, update, or delete machine learning models (and their versions) in the Agent Platform Model Registry. Don't use for model training, model deployment to endpoints, or managing non-Agent Platform models.
foundry-config-setup
Resolve missing setup caused by a hardcoded Foundry project endpoint or model in a sample. Use when a sample fails because it uses a placeholder/hardcoded projectendpoint (for example "https://your-project.services.ai.azure.com") or a hardcoded model instead of reading them from the environment.
google-cloud-solution-agentic-analytics-spark-knowledge-catalog
Discovers requirements and generates guidance to design and deploy a governed, secure agentic-analytics solution for data that's distributed across Google Cloud, other cloud providers, or on-premises. Data that's outside Google Cloud (such as data from Databricks, Snowflake, Salesforce, SAP, or Oracle systems) is…
training-check
Interactively monitor training metrics from the current Codex session, periodically checking WandB or fallback logs for NaN, divergence, plateaus, and broken runs.
nemo-automodel-launcher-config
Configure NeMo AutoModel job launches for interactive runs, Slurm clusters, and SkyPilot cloud execution.