DDC_Skills_for_AI_Agents_in_Construction claims-documentation
Document construction claims for disputes and recovery. Compile evidence, calculate damages, track notice requirements, and prepare claim packages.
install
source · Clone the upstream repo
git clone https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction "$T" && mkdir -p ~/.claude/skills && cp -r "$T/4_DDC_Curated/Contract-Legal/claims-documentation" ~/.claude/skills/datadrivenconstruction-ddc-skills-for-ai-agents-in-construction-claims-documenta && rm -rf "$T"
manifest:
4_DDC_Curated/Contract-Legal/claims-documentation/SKILL.mdsource content
Claims Documentation
Overview
Document and manage construction claims for schedule delays, cost impacts, and scope disputes. Track contractual notice requirements, compile supporting evidence, calculate damages, and prepare comprehensive claim packages.
Claims Process
┌─────────────────────────────────────────────────────────────────┐ │ CLAIMS PROCESS │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Notice → Document → Quantify → Submit → Negotiate │ │ ────── ──────── ──────── ────── ───────── │ │ 📋 Identify 📂 Collect 💰 Calculate 📤 Package 🤝 Resolve │ │ 📧 Timely 📸 Evidence ⏱️ Time 📋 Format ⚖️ Settle │ │ 📝 Written 📄 Chain 📊 Cost ✓ Review 💵 Payment │ │ │ └─────────────────────────────────────────────────────────────────┘
Technical Implementation
from dataclasses import dataclass, field from typing import List, Dict, Optional from datetime import datetime, timedelta from enum import Enum class ClaimType(Enum): DELAY = "delay" DISRUPTION = "disruption" ACCELERATION = "acceleration" DIFFERING_CONDITIONS = "differing_conditions" OWNER_CHANGE = "owner_change" SUSPENSION = "suspension" TERMINATION = "termination" DEFECTIVE_SPECS = "defective_specs" class ClaimStatus(Enum): DRAFT = "draft" NOTICE_SENT = "notice_sent" DOCUMENTING = "documenting" SUBMITTED = "submitted" UNDER_REVIEW = "under_review" NEGOTIATING = "negotiating" SETTLED = "settled" DISPUTED = "disputed" LITIGATION = "litigation" WITHDRAWN = "withdrawn" class EvidenceType(Enum): DAILY_REPORT = "daily_report" PHOTO = "photo" VIDEO = "video" EMAIL = "email" LETTER = "letter" MEETING_MINUTES = "meeting_minutes" SCHEDULE = "schedule" COST_RECORD = "cost_record" INVOICE = "invoice" TIMESHEET = "timesheet" WEATHER_DATA = "weather_data" DELIVERY_TICKET = "delivery_ticket" INSPECTION_REPORT = "inspection_report" RFI = "rfi" SUBMITTAL = "submittal" @dataclass class Evidence: id: str evidence_type: EvidenceType description: str date: datetime file_path: str source: str relevance: str authenticated: bool = False @dataclass class NoticeRequirement: notice_type: str deadline_days: int recipient: str method: str # Written, certified mail, etc. contract_reference: str sent: bool = False sent_date: Optional[datetime] = None confirmation: str = "" @dataclass class DamageCalculation: category: str description: str amount: float basis: str # How calculated supporting_docs: List[str] = field(default_factory=list) @dataclass class Claim: id: str claim_type: ClaimType title: str description: str status: ClaimStatus # Event details event_date: datetime discovery_date: datetime responsible_party: str contract_references: List[str] = field(default_factory=list) # Notice notice_requirements: List[NoticeRequirement] = field(default_factory=list) notice_compliant: bool = False # Documentation evidence: List[Evidence] = field(default_factory=list) narrative: str = "" # Damages time_claimed_days: int = 0 cost_claimed: float = 0.0 damage_calculations: List[DamageCalculation] = field(default_factory=list) # Resolution time_awarded_days: int = 0 amount_awarded: float = 0.0 settlement_date: Optional[datetime] = None settlement_notes: str = "" class ClaimsDocumentor: """Document and manage construction claims.""" # Common notice requirements DEFAULT_NOTICE_REQUIREMENTS = { ClaimType.DELAY: [ {"notice_type": "Intent to Claim", "deadline_days": 21, "method": "Written"}, {"notice_type": "Detailed Claim", "deadline_days": 45, "method": "Written"}, ], ClaimType.DIFFERING_CONDITIONS: [ {"notice_type": "Immediate Notice", "deadline_days": 2, "method": "Written/Verbal"}, {"notice_type": "Written Notice", "deadline_days": 7, "method": "Written"}, ], ClaimType.OWNER_CHANGE: [ {"notice_type": "Notice of Impact", "deadline_days": 14, "method": "Written"}, ], } def __init__(self, project_name: str, contract_date: datetime): self.project_name = project_name self.contract_date = contract_date self.claims: Dict[str, Claim] = {} def create_claim(self, claim_type: ClaimType, title: str, description: str, event_date: datetime, responsible_party: str) -> Claim: """Create new claim.""" claim_id = f"CLM-{datetime.now().strftime('%Y%m%d%H%M%S')}" claim = Claim( id=claim_id, claim_type=claim_type, title=title, description=description, status=ClaimStatus.DRAFT, event_date=event_date, discovery_date=datetime.now(), responsible_party=responsible_party ) # Add default notice requirements for req in self.DEFAULT_NOTICE_REQUIREMENTS.get(claim_type, []): notice = NoticeRequirement( notice_type=req["notice_type"], deadline_days=req["deadline_days"], recipient=responsible_party, method=req["method"], contract_reference="" ) claim.notice_requirements.append(notice) self.claims[claim_id] = claim return claim def record_notice_sent(self, claim_id: str, notice_type: str, confirmation: str = "") -> NoticeRequirement: """Record that notice was sent.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") claim = self.claims[claim_id] for notice in claim.notice_requirements: if notice.notice_type == notice_type: notice.sent = True notice.sent_date = datetime.now() notice.confirmation = confirmation # Check overall notice compliance claim.notice_compliant = all(n.sent for n in claim.notice_requirements) if claim.status == ClaimStatus.DRAFT: claim.status = ClaimStatus.NOTICE_SENT return notice raise ValueError(f"Notice type {notice_type} not found") def check_notice_deadlines(self, claim_id: str) -> List[Dict]: """Check status of notice deadlines.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") claim = self.claims[claim_id] status = [] for notice in claim.notice_requirements: deadline = claim.event_date + timedelta(days=notice.deadline_days) days_remaining = (deadline - datetime.now()).days status.append({ "notice_type": notice.notice_type, "deadline": deadline, "days_remaining": days_remaining, "sent": notice.sent, "overdue": days_remaining < 0 and not notice.sent, "status": "Sent" if notice.sent else ("OVERDUE" if days_remaining < 0 else f"{days_remaining} days left") }) return status def add_evidence(self, claim_id: str, evidence_type: EvidenceType, description: str, date: datetime, file_path: str, source: str, relevance: str) -> Evidence: """Add evidence to claim.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") evidence_id = f"EVD-{len(self.claims[claim_id].evidence)+1:04d}" evidence = Evidence( id=evidence_id, evidence_type=evidence_type, description=description, date=date, file_path=file_path, source=source, relevance=relevance ) self.claims[claim_id].evidence.append(evidence) if self.claims[claim_id].status == ClaimStatus.NOTICE_SENT: self.claims[claim_id].status = ClaimStatus.DOCUMENTING return evidence def add_damage_calculation(self, claim_id: str, category: str, description: str, amount: float, basis: str, supporting_docs: List[str] = None) -> DamageCalculation: """Add damage calculation to claim.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") calc = DamageCalculation( category=category, description=description, amount=amount, basis=basis, supporting_docs=supporting_docs or [] ) claim = self.claims[claim_id] claim.damage_calculations.append(calc) # Update total claimed claim.cost_claimed = sum(c.amount for c in claim.damage_calculations) return calc def calculate_delay_damages(self, claim_id: str, delay_days: int, daily_rate: float, include_escalation: bool = True) -> Dict: """Calculate delay damages using Eichleay formula or daily rate.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") claim = self.claims[claim_id] # Direct costs extended_general_conditions = delay_days * daily_rate # Add standard categories self.add_damage_calculation( claim_id, "Extended General Conditions", f"{delay_days} days × ${daily_rate:,.2f}/day", extended_general_conditions, "Daily rate method" ) # Escalation (if applicable) escalation = 0 if include_escalation: escalation = extended_general_conditions * 0.03 # 3% escalation self.add_damage_calculation( claim_id, "Material/Labor Escalation", "Cost increase due to extended duration", escalation, "3% escalation factor" ) claim.time_claimed_days = delay_days return { "delay_days": delay_days, "daily_rate": daily_rate, "extended_gc": extended_general_conditions, "escalation": escalation, "total": claim.cost_claimed } def write_narrative(self, claim_id: str, narrative: str): """Write claim narrative.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") self.claims[claim_id].narrative = narrative def submit_claim(self, claim_id: str) -> Claim: """Submit claim.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") claim = self.claims[claim_id] claim.status = ClaimStatus.SUBMITTED return claim def record_settlement(self, claim_id: str, time_awarded: int, amount_awarded: float, notes: str = "") -> Claim: """Record claim settlement.""" if claim_id not in self.claims: raise ValueError(f"Claim {claim_id} not found") claim = self.claims[claim_id] claim.status = ClaimStatus.SETTLED claim.time_awarded_days = time_awarded claim.amount_awarded = amount_awarded claim.settlement_date = datetime.now() claim.settlement_notes = notes return claim def generate_evidence_index(self, claim_id: str) -> str: """Generate evidence index.""" if claim_id not in self.claims: return "Claim not found" claim = self.claims[claim_id] lines = [ "# Evidence Index", "", f"**Claim:** {claim.title}", f"**Claim ID:** {claim.id}", "", "| # | Type | Date | Description | Source | Relevance |", "|---|------|------|-------------|--------|-----------|" ] for i, ev in enumerate(sorted(claim.evidence, key=lambda e: e.date), 1): lines.append( f"| {i} | {ev.evidence_type.value} | {ev.date.strftime('%Y-%m-%d')} | " f"{ev.description[:30]} | {ev.source} | {ev.relevance[:30]} |" ) return "\n".join(lines) def generate_claim_package(self, claim_id: str) -> str: """Generate complete claim package.""" if claim_id not in self.claims: return "Claim not found" claim = self.claims[claim_id] lines = [ "# CLAIM PACKAGE", "", f"## Claim: {claim.title}", "", f"**Claim ID:** {claim.id}", f"**Type:** {claim.claim_type.value.replace('_', ' ').title()}", f"**Status:** {claim.status.value}", f"**Event Date:** {claim.event_date.strftime('%Y-%m-%d')}", f"**Responsible Party:** {claim.responsible_party}", "", "---", "", "## 1. Executive Summary", "", claim.description, "", f"**Time Claimed:** {claim.time_claimed_days} days", f"**Amount Claimed:** ${claim.cost_claimed:,.2f}", "", "## 2. Factual Narrative", "", claim.narrative if claim.narrative else "*Narrative pending*", "", "## 3. Contract References", "", ] for ref in claim.contract_references: lines.append(f"- {ref}") lines.extend([ "", "## 4. Notice Compliance", "", "| Notice Type | Deadline | Status | Sent Date |", "|-------------|----------|--------|-----------|" ]) for notice in claim.notice_requirements: deadline = claim.event_date + timedelta(days=notice.deadline_days) status = "✓ Sent" if notice.sent else "Pending" sent = notice.sent_date.strftime('%Y-%m-%d') if notice.sent_date else "-" lines.append(f"| {notice.notice_type} | {deadline.strftime('%Y-%m-%d')} | {status} | {sent} |") lines.extend([ "", "## 5. Damage Calculations", "", "| Category | Description | Amount | Basis |", "|----------|-------------|--------|-------|" ]) for calc in claim.damage_calculations: lines.append(f"| {calc.category} | {calc.description} | ${calc.amount:,.2f} | {calc.basis} |") lines.extend([ "", f"**Total Claimed: ${claim.cost_claimed:,.2f}**", "", "## 6. Evidence Summary", "", f"Total Documents: {len(claim.evidence)}", "" ]) # Group evidence by type by_type = {} for ev in claim.evidence: t = ev.evidence_type.value by_type[t] = by_type.get(t, 0) + 1 for t, count in sorted(by_type.items()): lines.append(f"- {t.replace('_', ' ').title()}: {count}") return "\n".join(lines)
Quick Start
from datetime import datetime, timedelta # Initialize documentor documentor = ClaimsDocumentor("Office Tower", datetime(2024, 1, 1)) # Create claim claim = documentor.create_claim( claim_type=ClaimType.DELAY, title="Owner-Caused Delay - Design Changes", description="Multiple design changes to structural system caused 45-day delay", event_date=datetime(2024, 6, 15), responsible_party="Owner" ) # Check notice deadlines deadlines = documentor.check_notice_deadlines(claim.id) for d in deadlines: print(f"{d['notice_type']}: {d['status']}") # Record notice sent documentor.record_notice_sent(claim.id, "Intent to Claim", "Certified Mail #12345") # Add evidence documentor.add_evidence( claim.id, EvidenceType.RFI, "RFI-042 requesting structural clarification", datetime(2024, 6, 10), "/docs/RFI-042.pdf", "Project Files", "Shows owner's delayed response" ) # Calculate damages damages = documentor.calculate_delay_damages( claim.id, delay_days=45, daily_rate=5000.0 ) print(f"Total damages: ${damages['total']:,.2f}") # Write narrative documentor.write_narrative(claim.id, """ On June 15, 2024, the Owner issued a design change directive requiring modifications to the structural steel at Levels 5-8. This change... """) # Generate claim package print(documentor.generate_claim_package(claim.id))
Requirements
pip install (no external dependencies)