as-built-documentation
Automate as-built documentation and digital handover for construction. Compile project records, generate O&M manuals, create asset databases, and ensure complete project closeout.
Best use case
as-built-documentation is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Automate as-built documentation and digital handover for construction. Compile project records, generate O&M manuals, create asset databases, and ensure complete project closeout.
Teams using as-built-documentation should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/as-built-documentation/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How as-built-documentation Compares
| Feature / Agent | as-built-documentation | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Automate as-built documentation and digital handover for construction. Compile project records, generate O&M manuals, create asset databases, and ensure complete project closeout.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# As-Built Documentation
## Overview
This skill implements automated as-built documentation and digital handover for construction projects. Compile accurate records, generate operation manuals, and ensure complete documentation for facility management.
**Capabilities:**
- As-built drawing management
- O&M manual generation
- Asset data compilation
- Warranty tracking
- Document organization
- BIM-to-FM handover
## Quick Start
```python
from dataclasses import dataclass, field
from datetime import date, datetime
from typing import List, Dict, Optional
from enum import Enum
class DocumentType(Enum):
DRAWING = "drawing"
SPECIFICATION = "specification"
SUBMITTAL = "submittal"
WARRANTY = "warranty"
CERTIFICATE = "certificate"
MANUAL = "manual"
TEST_REPORT = "test_report"
COMMISSIONING = "commissioning"
PHOTO = "photo"
class DocumentStatus(Enum):
DRAFT = "draft"
REVIEWED = "reviewed"
APPROVED = "approved"
AS_BUILT = "as_built"
FINAL = "final"
@dataclass
class HandoverDocument:
doc_id: str
doc_type: DocumentType
title: str
file_path: str
version: str
status: DocumentStatus
system: str # Building system (HVAC, Electrical, etc.)
uploaded_date: date
approved_by: str = ""
@dataclass
class AssetRecord:
asset_id: str
asset_name: str
asset_type: str
manufacturer: str
model: str
serial_number: str
location: str
install_date: date
warranty_end: date
documents: List[str] = field(default_factory=list)
def check_handover_completeness(documents: List[HandoverDocument],
required_types: List[DocumentType]) -> Dict:
"""Check if all required documents are present"""
present_types = {doc.doc_type for doc in documents if doc.status == DocumentStatus.FINAL}
missing = set(required_types) - present_types
return {
'complete': len(missing) == 0,
'total_required': len(required_types),
'total_present': len(present_types),
'missing_types': [t.value for t in missing]
}
# Example
documents = [
HandoverDocument("DOC-001", DocumentType.DRAWING, "Floor Plans As-Built",
"/docs/floorplans.pdf", "3.0", DocumentStatus.FINAL, "Architecture", date.today()),
HandoverDocument("DOC-002", DocumentType.MANUAL, "HVAC O&M Manual",
"/docs/hvac_om.pdf", "1.0", DocumentStatus.FINAL, "HVAC", date.today()),
]
required = [DocumentType.DRAWING, DocumentType.MANUAL, DocumentType.WARRANTY]
status = check_handover_completeness(documents, required)
print(f"Complete: {status['complete']}, Missing: {status['missing_types']}")
```
## Comprehensive Handover System
### Document Management
```python
from dataclasses import dataclass, field
from datetime import date, datetime, timedelta
from typing import List, Dict, Optional, Tuple
from enum import Enum
import uuid
import os
class BuildingSystem(Enum):
ARCHITECTURAL = "architectural"
STRUCTURAL = "structural"
MECHANICAL = "mechanical"
ELECTRICAL = "electrical"
PLUMBING = "plumbing"
FIRE_PROTECTION = "fire_protection"
CONTROLS = "controls"
ELEVATOR = "elevator"
CIVIL = "civil"
LANDSCAPE = "landscape"
@dataclass
class DocumentRequirement:
requirement_id: str
doc_type: DocumentType
system: BuildingSystem
description: str
is_mandatory: bool = True
quantity: int = 1 # How many documents of this type needed
format_requirements: str = "PDF"
@dataclass
class ProjectDocument:
doc_id: str
requirement_id: Optional[str]
doc_type: DocumentType
system: BuildingSystem
title: str
description: str
file_path: str
file_size_mb: float
format: str
version: str
revision_date: date
author: str
reviewer: str
status: DocumentStatus
metadata: Dict = field(default_factory=dict)
related_assets: List[str] = field(default_factory=list)
supersedes: Optional[str] = None # Previous version doc_id
class DocumentManager:
"""Manage project handover documents"""
STANDARD_REQUIREMENTS = {
BuildingSystem.MECHANICAL: [
DocumentRequirement("REQ-M01", DocumentType.DRAWING, BuildingSystem.MECHANICAL,
"HVAC As-Built Drawings"),
DocumentRequirement("REQ-M02", DocumentType.MANUAL, BuildingSystem.MECHANICAL,
"HVAC Operation & Maintenance Manual"),
DocumentRequirement("REQ-M03", DocumentType.WARRANTY, BuildingSystem.MECHANICAL,
"HVAC Equipment Warranties"),
DocumentRequirement("REQ-M04", DocumentType.TEST_REPORT, BuildingSystem.MECHANICAL,
"TAB Report - Testing, Adjusting, Balancing"),
DocumentRequirement("REQ-M05", DocumentType.COMMISSIONING, BuildingSystem.MECHANICAL,
"Commissioning Report"),
],
BuildingSystem.ELECTRICAL: [
DocumentRequirement("REQ-E01", DocumentType.DRAWING, BuildingSystem.ELECTRICAL,
"Electrical As-Built Drawings"),
DocumentRequirement("REQ-E02", DocumentType.MANUAL, BuildingSystem.ELECTRICAL,
"Electrical O&M Manual"),
DocumentRequirement("REQ-E03", DocumentType.WARRANTY, BuildingSystem.ELECTRICAL,
"Electrical Equipment Warranties"),
DocumentRequirement("REQ-E04", DocumentType.TEST_REPORT, BuildingSystem.ELECTRICAL,
"Electrical Test Reports"),
DocumentRequirement("REQ-E05", DocumentType.CERTIFICATE, BuildingSystem.ELECTRICAL,
"Electrical Inspection Certificate"),
],
BuildingSystem.PLUMBING: [
DocumentRequirement("REQ-P01", DocumentType.DRAWING, BuildingSystem.PLUMBING,
"Plumbing As-Built Drawings"),
DocumentRequirement("REQ-P02", DocumentType.MANUAL, BuildingSystem.PLUMBING,
"Plumbing O&M Manual"),
DocumentRequirement("REQ-P03", DocumentType.TEST_REPORT, BuildingSystem.PLUMBING,
"Pressure Test Reports"),
],
BuildingSystem.FIRE_PROTECTION: [
DocumentRequirement("REQ-F01", DocumentType.DRAWING, BuildingSystem.FIRE_PROTECTION,
"Fire Protection As-Built Drawings"),
DocumentRequirement("REQ-F02", DocumentType.MANUAL, BuildingSystem.FIRE_PROTECTION,
"Fire Systems O&M Manual"),
DocumentRequirement("REQ-F03", DocumentType.CERTIFICATE, BuildingSystem.FIRE_PROTECTION,
"Fire Marshal Approval"),
DocumentRequirement("REQ-F04", DocumentType.TEST_REPORT, BuildingSystem.FIRE_PROTECTION,
"Fire Alarm Acceptance Test"),
],
BuildingSystem.ARCHITECTURAL: [
DocumentRequirement("REQ-A01", DocumentType.DRAWING, BuildingSystem.ARCHITECTURAL,
"Architectural As-Built Drawings"),
DocumentRequirement("REQ-A02", DocumentType.SPECIFICATION, BuildingSystem.ARCHITECTURAL,
"Finish Schedule"),
DocumentRequirement("REQ-A03", DocumentType.WARRANTY, BuildingSystem.ARCHITECTURAL,
"Roofing Warranty"),
]
}
def __init__(self, project_id: str, project_name: str):
self.project_id = project_id
self.project_name = project_name
self.requirements: Dict[str, DocumentRequirement] = {}
self.documents: Dict[str, ProjectDocument] = {}
self._load_standard_requirements()
def _load_standard_requirements(self):
"""Load standard document requirements"""
for system, reqs in self.STANDARD_REQUIREMENTS.items():
for req in reqs:
self.requirements[req.requirement_id] = req
def add_requirement(self, requirement: DocumentRequirement):
"""Add custom requirement"""
self.requirements[requirement.requirement_id] = requirement
def upload_document(self, doc_type: DocumentType, system: BuildingSystem,
title: str, file_path: str, author: str,
requirement_id: str = None,
related_assets: List[str] = None) -> ProjectDocument:
"""Upload new document"""
doc_id = f"DOC-{uuid.uuid4().hex[:8].upper()}"
# Get file info
file_size = os.path.getsize(file_path) / (1024 * 1024) if os.path.exists(file_path) else 0
file_format = os.path.splitext(file_path)[1].upper().replace('.', '')
doc = ProjectDocument(
doc_id=doc_id,
requirement_id=requirement_id,
doc_type=doc_type,
system=system,
title=title,
description="",
file_path=file_path,
file_size_mb=file_size,
format=file_format,
version="1.0",
revision_date=date.today(),
author=author,
reviewer="",
status=DocumentStatus.DRAFT,
related_assets=related_assets or []
)
self.documents[doc_id] = doc
return doc
def approve_document(self, doc_id: str, reviewer: str) -> bool:
"""Approve document"""
doc = self.documents.get(doc_id)
if doc:
doc.status = DocumentStatus.APPROVED
doc.reviewer = reviewer
return True
return False
def finalize_document(self, doc_id: str) -> bool:
"""Finalize document for handover"""
doc = self.documents.get(doc_id)
if doc and doc.status == DocumentStatus.APPROVED:
doc.status = DocumentStatus.FINAL
return True
return False
def get_status_summary(self) -> Dict:
"""Get document status summary"""
summary = {
'total_requirements': len(self.requirements),
'total_documents': len(self.documents),
'by_status': {},
'by_system': {},
'completion': {}
}
# Count by status
for doc in self.documents.values():
status = doc.status.value
summary['by_status'][status] = summary['by_status'].get(status, 0) + 1
system = doc.system.value
if system not in summary['by_system']:
summary['by_system'][system] = {'uploaded': 0, 'final': 0}
summary['by_system'][system]['uploaded'] += 1
if doc.status == DocumentStatus.FINAL:
summary['by_system'][system]['final'] += 1
# Check completion against requirements
for req_id, req in self.requirements.items():
matching_docs = [
d for d in self.documents.values()
if d.requirement_id == req_id and d.status == DocumentStatus.FINAL
]
summary['completion'][req_id] = {
'description': req.description,
'system': req.system.value,
'required': req.quantity,
'submitted': len(matching_docs),
'complete': len(matching_docs) >= req.quantity
}
return summary
def get_missing_documents(self) -> List[DocumentRequirement]:
"""Get list of missing required documents"""
missing = []
for req_id, req in self.requirements.items():
if not req.is_mandatory:
continue
matching_docs = [
d for d in self.documents.values()
if d.requirement_id == req_id and d.status == DocumentStatus.FINAL
]
if len(matching_docs) < req.quantity:
missing.append(req)
return missing
```
### Asset Registry
```python
from datetime import date, timedelta
from typing import List, Dict, Optional
@dataclass
class MaintenanceSchedule:
schedule_id: str
task_description: str
frequency: str # daily, weekly, monthly, quarterly, annual
next_due: date
responsible_party: str
estimated_duration_hours: float
@dataclass
class AssetDetails:
asset_id: str
asset_tag: str
asset_name: str
asset_type: str
category: str # equipment, fixture, system
# Identification
manufacturer: str
model_number: str
serial_number: str
part_number: str = ""
# Location
building: str = ""
floor: str = ""
room: str = ""
coordinates: Tuple[float, float, float] = (0, 0, 0)
# Installation
install_date: date = None
installed_by: str = ""
cost: float = 0
# Warranty
warranty_start: date = None
warranty_end: date = None
warranty_provider: str = ""
warranty_terms: str = ""
# Specifications
specifications: Dict = field(default_factory=dict)
# Documents
manuals: List[str] = field(default_factory=list)
drawings: List[str] = field(default_factory=list)
photos: List[str] = field(default_factory=list)
# Maintenance
maintenance_schedules: List[MaintenanceSchedule] = field(default_factory=list)
service_contacts: List[Dict] = field(default_factory=list)
# BIM reference
ifc_guid: str = ""
revit_element_id: str = ""
class AssetRegistry:
"""Manage building assets for handover"""
def __init__(self, project_id: str):
self.project_id = project_id
self.assets: Dict[str, AssetDetails] = {}
def register_asset(self, asset: AssetDetails):
"""Register new asset"""
self.assets[asset.asset_id] = asset
def import_from_bim(self, bim_data: List[Dict]):
"""Import assets from BIM model"""
for item in bim_data:
asset = AssetDetails(
asset_id=f"AST-{uuid.uuid4().hex[:8].upper()}",
asset_tag=item.get('tag', ''),
asset_name=item.get('name', ''),
asset_type=item.get('type', ''),
category=item.get('category', 'equipment'),
manufacturer=item.get('manufacturer', ''),
model_number=item.get('model', ''),
serial_number=item.get('serial', ''),
building=item.get('building', ''),
floor=item.get('floor', ''),
room=item.get('room', ''),
ifc_guid=item.get('ifc_guid', ''),
revit_element_id=item.get('revit_id', '')
)
# Add specifications
for key, value in item.get('parameters', {}).items():
asset.specifications[key] = value
self.assets[asset.asset_id] = asset
def add_warranty(self, asset_id: str, start_date: date,
duration_years: int, provider: str, terms: str = ""):
"""Add warranty information"""
asset = self.assets.get(asset_id)
if asset:
asset.warranty_start = start_date
asset.warranty_end = start_date + timedelta(days=365 * duration_years)
asset.warranty_provider = provider
asset.warranty_terms = terms
def add_maintenance_schedule(self, asset_id: str,
schedule: MaintenanceSchedule):
"""Add maintenance schedule"""
asset = self.assets.get(asset_id)
if asset:
asset.maintenance_schedules.append(schedule)
def get_warranty_report(self) -> Dict:
"""Get warranty status report"""
today = date.today()
report = {
'total_assets': len(self.assets),
'with_warranty': 0,
'active_warranties': 0,
'expiring_soon': [], # Within 90 days
'expired': []
}
for asset in self.assets.values():
if asset.warranty_end:
report['with_warranty'] += 1
if asset.warranty_end >= today:
report['active_warranties'] += 1
days_remaining = (asset.warranty_end - today).days
if days_remaining <= 90:
report['expiring_soon'].append({
'asset_id': asset.asset_id,
'asset_name': asset.asset_name,
'warranty_end': asset.warranty_end.isoformat(),
'days_remaining': days_remaining
})
else:
report['expired'].append({
'asset_id': asset.asset_id,
'asset_name': asset.asset_name,
'warranty_end': asset.warranty_end.isoformat()
})
return report
def export_to_cmms(self) -> List[Dict]:
"""Export assets for CMMS import"""
export_data = []
for asset in self.assets.values():
export_data.append({
'asset_id': asset.asset_id,
'asset_tag': asset.asset_tag,
'name': asset.asset_name,
'type': asset.asset_type,
'category': asset.category,
'manufacturer': asset.manufacturer,
'model': asset.model_number,
'serial': asset.serial_number,
'location': f"{asset.building}/{asset.floor}/{asset.room}",
'install_date': asset.install_date.isoformat() if asset.install_date else '',
'warranty_end': asset.warranty_end.isoformat() if asset.warranty_end else '',
'specifications': asset.specifications
})
return export_data
```
### O&M Manual Generator
```python
class OMManualGenerator:
"""Generate O&M manuals from project data"""
def __init__(self, doc_manager: DocumentManager, asset_registry: AssetRegistry):
self.docs = doc_manager
self.assets = asset_registry
def generate_system_manual(self, system: BuildingSystem,
output_path: str) -> Dict:
"""Generate O&M manual for building system"""
# Collect system documents
system_docs = [
d for d in self.docs.documents.values()
if d.system == system and d.status == DocumentStatus.FINAL
]
# Collect system assets
system_assets = [
a for a in self.assets.assets.values()
if a.asset_type.lower() in system.value.lower() or
system.value.lower() in a.category.lower()
]
manual_content = {
'system': system.value,
'generated_date': date.today().isoformat(),
'sections': []
}
# Section 1: System Overview
manual_content['sections'].append({
'title': 'System Overview',
'content': f"Overview of {system.value} system",
'subsections': []
})
# Section 2: Equipment List
equipment_list = []
for asset in system_assets:
equipment_list.append({
'tag': asset.asset_tag,
'name': asset.asset_name,
'manufacturer': asset.manufacturer,
'model': asset.model_number,
'location': f"{asset.building}/{asset.floor}/{asset.room}"
})
manual_content['sections'].append({
'title': 'Equipment Schedule',
'equipment': equipment_list
})
# Section 3: Operation Procedures
manual_content['sections'].append({
'title': 'Operation Procedures',
'content': 'Standard operating procedures',
'reference_docs': [d.doc_id for d in system_docs if d.doc_type == DocumentType.MANUAL]
})
# Section 4: Maintenance Requirements
maintenance_tasks = []
for asset in system_assets:
for schedule in asset.maintenance_schedules:
maintenance_tasks.append({
'asset': asset.asset_name,
'task': schedule.task_description,
'frequency': schedule.frequency,
'duration': schedule.estimated_duration_hours
})
manual_content['sections'].append({
'title': 'Preventive Maintenance',
'tasks': maintenance_tasks
})
# Section 5: Warranty Information
warranties = []
for asset in system_assets:
if asset.warranty_end:
warranties.append({
'asset': asset.asset_name,
'provider': asset.warranty_provider,
'expires': asset.warranty_end.isoformat(),
'terms': asset.warranty_terms
})
manual_content['sections'].append({
'title': 'Warranty Information',
'warranties': warranties
})
# Section 6: Service Contacts
contacts = []
for asset in system_assets:
contacts.extend(asset.service_contacts)
manual_content['sections'].append({
'title': 'Service Contacts',
'contacts': list({c['name']: c for c in contacts}.values())
})
# Section 7: Reference Documents
manual_content['sections'].append({
'title': 'Reference Documents',
'documents': [
{'id': d.doc_id, 'title': d.title, 'type': d.doc_type.value}
for d in system_docs
]
})
return manual_content
def generate_building_manual(self, output_path: str) -> Dict:
"""Generate complete building O&M manual"""
building_manual = {
'project': self.docs.project_name,
'generated': date.today().isoformat(),
'systems': {}
}
for system in BuildingSystem:
building_manual['systems'][system.value] = self.generate_system_manual(
system, output_path
)
return building_manual
```
### Handover Checklist
```python
def generate_handover_checklist(doc_manager: DocumentManager,
asset_registry: AssetRegistry) -> Dict:
"""Generate comprehensive handover checklist"""
checklist = {
'generated': date.today().isoformat(),
'project': doc_manager.project_name,
'overall_status': 'incomplete',
'categories': []
}
# Documents category
doc_status = doc_manager.get_status_summary()
missing_docs = doc_manager.get_missing_documents()
checklist['categories'].append({
'name': 'Documents',
'complete': len(missing_docs) == 0,
'items': [
{
'item': req.description,
'system': req.system.value,
'status': 'complete' if req.requirement_id not in [m.requirement_id for m in missing_docs] else 'missing'
}
for req in doc_manager.requirements.values()
]
})
# Assets category
warranty_report = asset_registry.get_warranty_report()
checklist['categories'].append({
'name': 'Asset Registration',
'complete': warranty_report['total_assets'] > 0,
'items': [
{'item': 'All major equipment registered', 'status': 'complete' if warranty_report['total_assets'] > 0 else 'incomplete'},
{'item': 'Warranty information entered', 'status': 'complete' if warranty_report['with_warranty'] > 0 else 'incomplete'},
{'item': 'Maintenance schedules defined', 'status': 'complete' if any(a.maintenance_schedules for a in asset_registry.assets.values()) else 'incomplete'}
]
})
# Training category
checklist['categories'].append({
'name': 'Training',
'complete': False,
'items': [
{'item': 'Operations staff training completed', 'status': 'pending'},
{'item': 'Maintenance staff training completed', 'status': 'pending'},
{'item': 'Safety systems training completed', 'status': 'pending'}
]
})
# Determine overall status
all_complete = all(cat['complete'] for cat in checklist['categories'])
checklist['overall_status'] = 'complete' if all_complete else 'incomplete'
return checklist
```
## Quick Reference
| Document Type | Typical Source | When Required |
|---------------|---------------|---------------|
| As-Built Drawings | Contractor | Substantial completion |
| O&M Manuals | Manufacturer/Contractor | Before training |
| Warranties | Manufacturers | At installation |
| Test Reports | Testing agency | After testing |
| Certificates | Authorities | Final inspection |
| Training Records | Contractor | Before handover |
## Resources
- **COBie Standard**: Construction Operations Building Information Exchange
- **ASHRAE Guideline 0**: Commissioning process
- **IFMA**: Facility Management resources
- **DDC Website**: https://datadrivenconstruction.io
## Next Steps
- See `bim-validation-pipeline` for BIM handover
- See `document-classification-nlp` for document processing
- See `digital-twin-sync` for FM integrationRelated Skills
documentation-templates
Documentation templates and structure guidelines. README, API docs, code comments, and AI-friendly documentation.
documentation-structure-validator
Validate documentation structure, check for missing sections, verify markdown syntax, ensure consistency with templates. Use when user mentions docs validation, structure check, README review, documentation quality, or wants to verify documentation completeness.
documentation-standards
Clear technical documentation with JSDoc, READMEs, Mermaid diagrams, ISMS policy references, and comprehensive code examples
documentation-specialist
文档专家。专注于技术文档编写、API 文档生成、README 优化和文档维护。提供清晰的文档结构、规范的格式和用户友好的内容。
documentation-research
Enforces documentation research before implementation. Auto-loads when implementing features to ensure current best practices are followed. Researches official docs first.
documentation
Technical writing, API docs, and documentation best practices
Documentation Hygiene
This skill should be used when the user asks to perform "documentation hygiene", "update docs for change", "mark historical docs", "add deprecation headers", "documentation migration", or when making significant changes that affect multiple documentation files (like license migrations, tier changes, or API changes).
documentation-guidelines
Write or update backend feature documentation that follows a repo's DOCUMENTATION_GUIDELINES.md (or equivalent) across any project. Use when asked to create/update module docs, API contracts, or backend documentation that must include architecture, endpoints, payloads, Mermaid diagrams, and seeding instructions.
documentation-generation-doc-generate
You are a documentation expert specializing in creating comprehensive, maintainable documentation from code. Generate API docs, architecture diagrams, user guides, and technical references using AI...
create-oo-component-documentation
Create comprehensive, standardized documentation for object-oriented components following industry best practices and architectural documentation standards.
code-documentation
Writing effective code documentation - API docs, README files, inline comments, and technical guides. Use for documenting codebases, APIs, or writing developer guides.
code-documentation-doc-generate
You are a documentation expert specializing in creating comprehensive, maintainable documentation from code. Generate API docs, architecture diagrams, user guides, and technical references using AI...