Skip to main content
ClaudeWave
Skill254 repo starsupdated 5mo ago

as-built-documentation

This Claude Code skill manages as-built documentation throughout project closeout by tracking drawing markups, coordinate updates, and verifying document completeness. Use it when systematically documenting field changes, maintaining consistent drawing revisions, ensuring all required documentation is complete before project handover, and verifying that all markups have been incorporated into final as-built packages.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction /tmp/as-built-documentation && cp -r /tmp/as-built-documentation/1_DDC_Toolkit/Document-Control/as-built-documentation ~/.claude/skills/as-built-documentation
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# As-Built Documentation Manager

## Business Case

### Problem Statement
As-built documentation is often incomplete:
- Field changes not documented
- Drawings not updated consistently
- Missing documentation at closeout
- Difficult to verify completeness

### Solution
Systematic as-built documentation tracking with drawing markup management, completeness verification, and handover preparation.

## Technical Implementation

```python
import pandas as pd
from datetime import datetime, date
from typing import Dict, Any, List, Optional
from dataclasses import dataclass, field
from enum import Enum


class DocumentType(Enum):
    DRAWING = "drawing"
    SPECIFICATION = "specification"
    SUBMITTAL = "submittal"
    MANUAL = "manual"
    WARRANTY = "warranty"
    CERTIFICATE = "certificate"


class MarkupStatus(Enum):
    PENDING = "pending"
    IN_REVIEW = "in_review"
    APPROVED = "approved"
    INCORPORATED = "incorporated"


class DocumentStatus(Enum):
    DRAFT = "draft"
    UNDER_REVIEW = "under_review"
    APPROVED = "approved"
    FINAL = "final"


@dataclass
class Markup:
    markup_id: str
    description: str
    location: str
    marked_by: str
    marked_date: date
    status: MarkupStatus
    cloud_reference: str = ""
    notes: str = ""


@dataclass
class AsBuiltDocument:
    document_id: str
    document_number: str
    title: str
    document_type: DocumentType
    discipline: str
    revision: str
    status: DocumentStatus
    original_file: str
    as_built_file: str
    markups: List[Markup] = field(default_factory=list)
    last_updated: Optional[date] = None
    verified_by: str = ""
    verified_date: Optional[date] = None

    @property
    def is_complete(self) -> bool:
        return self.status == DocumentStatus.FINAL and all(
            m.status == MarkupStatus.INCORPORATED for m in self.markups
        )


class AsBuiltDocumentManager:
    """Manage as-built documentation."""

    def __init__(self, project_name: str):
        self.project_name = project_name
        self.documents: Dict[str, AsBuiltDocument] = {}
        self._markup_counter = 0

    def register_document(self, document_number: str, title: str,
                         document_type: DocumentType, discipline: str,
                         original_file: str, revision: str = "0") -> AsBuiltDocument:
        doc_id = f"DOC-{len(self.documents) + 1:04d}"

        doc = AsBuiltDocument(
            document_id=doc_id,
            document_number=document_number,
            title=title,
            document_type=document_type,
            discipline=discipline,
            revision=revision,
            status=DocumentStatus.DRAFT,
            original_file=original_file,
            as_built_file=""
        )
        self.documents[doc_id] = doc
        return doc

    def add_markup(self, doc_id: str, description: str, location: str,
                  marked_by: str, cloud_reference: str = "") -> Markup:
        if doc_id not in self.documents:
            raise ValueError(f"Document {doc_id} not found")

        self._markup_counter += 1
        markup = Markup(
            markup_id=f"MKP-{self._markup_counter:05d}",
            description=description,
            location=location,
            marked_by=marked_by,
            marked_date=date.today(),
            status=MarkupStatus.PENDING,
            cloud_reference=cloud_reference
        )
        self.documents[doc_id].markups.append(markup)
        return markup

    def update_markup_status(self, doc_id: str, markup_id: str, status: MarkupStatus):
        if doc_id in self.documents:
            for markup in self.documents[doc_id].markups:
                if markup.markup_id == markup_id:
                    markup.status = status
                    break

    def upload_as_built(self, doc_id: str, file_path: str, new_revision: str = None):
        if doc_id not in self.documents:
            return
        doc = self.documents[doc_id]
        doc.as_built_file = file_path
        doc.last_updated = date.today()
        if new_revision:
            doc.revision = new_revision
        doc.status = DocumentStatus.UNDER_REVIEW

    def verify_document(self, doc_id: str, verified_by: str):
        if doc_id not in self.documents:
            return
        doc = self.documents[doc_id]
        doc.verified_by = verified_by
        doc.verified_date = date.today()
        doc.status = DocumentStatus.FINAL

    def get_completeness_report(self) -> Dict[str, Any]:
        total = len(self.documents)
        complete = sum(1 for d in self.documents.values() if d.is_complete)
        pending_markups = sum(
            len([m for m in d.markups if m.status != MarkupStatus.INCORPORATED])
            for d in self.documents.values()
        )

        by_discipline = {}
        for doc in self.documents.values():
            if doc.discipline not in by_discipline:
                by_discipline[doc.discipline] = {'total': 0, 'complete': 0}
            by_discipline[doc.discipline]['total'] += 1
            if doc.is_complete:
                by_discipline[doc.discipline]['complete'] += 1

        return {
            'project': self.project_name,
            'total_documents': total,
            'complete': complete,
            'completion_percent': round(complete / total * 100, 1) if total > 0 else 0,
            'pending_markups': pending_markups,
            'by_discipline': by_discipline
        }

    def get_incomplete_documents(self) -> List[AsBuiltDocument]:
        return [d for d in self.documents.values() if not d.is_complete]

    def export_register(self, output_path: str):
        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
            # Document register
            doc_data = [{
                'ID': d.document_id,
                'Number': d.document_number,
                'Title': d.title,
                'Type': d.document_type.value,
                'Discipline': d.discipline,
                'Revision':