Subcontractor Prequalification
SkillCommerce & financePrequalify subcontractors based on safety, financial, and performance criteria.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Subcontractor Prequalification skill
What this skill tells your AI
The instructions your AI receives, as published by datadrivenconstruction/ddc_skills_for_ai_agents_in_construction in 1_DDC_Toolkit/Procurement/subcontractor-prequalification/SKILL.md and read by ahel’s review.
Technical Implementation
import pandas as pd
from datetime import date
from typing import Dict, Any, List
from dataclasses import dataclass, field
from enum import Enum
class QualificationStatus(Enum):
PENDING = "pending"
QUALIFIED = "qualified"
CONDITIONALLY_QUALIFIED = "conditionally_qualified"
NOT_QUALIFIED = "not_qualified"
@dataclass
class PrequalificationCriteria:
name: str
weight: float
min_score: int
max_score: int = 10
@dataclass
class SubcontractorApplication:
app_id: str
company_name: str
trade: str
contact_email: str
years_in_business: int
annual_revenue: float
bonding_capacity: float
emr_rate: float # Experience Modification Rate
status: QualificationStatus
scores: Dict[str, int] = field(default_factory=dict)
documents_received: List[str] = field(default_factory=list)
notes: str = ""
@property
def total_score(self) -> float:
return sum(self.scores.values())
class SubcontractorPrequalification:
def __init__(self, project_name: str):
self.project_name = project_name
self.applications: Dict[str, SubcontractorApplication] = {}
self.criteria = self._default_criteria()
self._counter = 0
def _default_criteria(self) -> List[PrequalificationCriteria]:
return [
PrequalificationCriteria("Safety Record", 0.25, 6),
PrequalificationCriteria("Financial Stability", 0.20, 5),
PrequalificationCriteria("Experience", 0.20, 6),
PrequalificationCriteria("References", 0.15, 5),
PrequalificationCriteria("Capacity", 0.10, 5),
PrequalificationCriteria("Insurance/Bonding", 0.10, 7)
]
def add_application(self, company_name: str, trade: str, contact_email: str,
years_in_business: int, annual_revenue: float,
bonding_capacity: float, emr_rate: float) -> SubcontractorApplication:
self._counter += 1
app_id = f"PQ-{self._counter:03d}"
app = SubcontractorApplication(
app_id=app_id,
company_name=company_name,
trade=trade,
contact_email=contact_email,
years_in_business=years_in_business,
annual_revenue=annual_revenue,
bonding_capacity=bonding_capacity,
emr_rate=emr_rate,
status=QualificationStatus.PENDING
)
self.applications[app_id] = app
return app
def score_application(self, app_id: str, scores: Dict[str, int]):
if app_id not in self.applications:
return
app = self.applications[app_id]
app.scores = scores
self._evaluate_qualification(app)
def _evaluate_qualification(self, app: SubcontractorApplication):
passed = True
for criteria in self.criteria:
score = app.scores.get(criteria.name, 0)
if score < criteria.min_score:
passed = False
break
if passed and app.total_score >= 60:
app.status = QualificationStatus.QUALIFIED
elif app.total_score >= 50:
app.status = QualificationStatus.CONDITIONALLY_QUALIFIED
else:
app.status = QualificationStatus.NOT_QUALIFIED
def get_qualified(self, trade: str = None) -> List[SubcontractorApplication]:
qualified = [a for a in self.applications.values()
if a.status in [QualificationStatus.QUALIFIED,
QualificationStatus.CONDITIONALLY_QUALIFIED]]
if trade:
qualified = [a for a in qualified if a.trade.lower() == trade.lower()]
return qualified
def export_register(self, output_path: str):
data = [{
'ID': a.app_id,
'Company': a.company_name,
'Trade': a.trade,
'Years': a.years_in_business,
'Revenue': a.annual_revenue,
'EMR': a.emr_rate,
'Status': a.status.value,
'Score': a.total_score
} for a in self.applications.values()]
pd.DataFrame(data).to_excel(output_path, index=False)
Quick Start
prequal = SubcontractorPrequalification("Office Tower")
app = prequal.add_application("ABC Electric", "Electrical", "info@abc.com",
years_in_business=15, annual_revenue=10000000,
bonding_capacity=5000000, emr_rate=0.85)
prequal.score_application(app.app_id, {
"Safety Record": 8, "Financial Stability": 7, "Experience": 8,
"References": 7, "Capacity": 8, "Insurance/Bonding": 9
})
qualified = prequal.get_qualified("Electrical")
Resources
- DDC Book: Chapter 3.4 - Procurement
Signals
- GitHub stars
- 308
- Forks
- 79
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
subcontractor-prequalification- Source
- github.com/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction
github.com/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction