Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Design data models for construction projects. Create entity-relationship diagrams, define schemas, and generate database structures.
.claude/skills/datadrivenconstruction-data-model-designer/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 454% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 34% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 62% | 0% |
Construction data management challenges:
Systematic data model design for construction projects, defining entities, relationships, and schemas for effective data management.
pythonfrom typing import Dict, Any, List, Optional from dataclasses import dataclass, field from enum import Enum import json class DataType(Enum): STRING = "string" INTEGER = "integer" FLOAT = "float" BOOLEAN = "boolean" DATE = "date" DATETIME = "datetime" TEXT = "text" JSON = "json" class RelationType(Enum): ONE_TO_ONE = "1:1" ONE_TO_MANY = "1:N" MANY_TO_MANY = "N:M" class ConstraintType(Enum): PRIMARY_KEY = "primary_key" FOREIGN_KEY = "foreign_key" UNIQUE = "unique" NOT_NULL = "not_null" @dataclass class Field: name: str data_type: DataType nullable: bool = True default: Any = None description: str = "" constraints: List[ConstraintType] = field(default_factory=list) @dataclass class Entity: name: str description: str fields: List[Field] = field(default_factory=list) primary_key: str = "id" @dataclass class Relationship: name: str from_entity: str to_entity: str relation_type: RelationType from_field: str to_field: str class ConstructionDataModel: """Design data models for construction projects.""" def __init__(self, project_name: str): self.project_name = project_name self.entities: Dict[str, Entity] = {} self.relationships: List[Relationship] = [] def add_entity(self, entity: Entity): """Add entity to model.""" self.entities[entity.name] = entity def add_relationship(self, relationship: Relationship): """Add relationship between entities.""" self.relationships.append(relationship) def create_entity(self, name: str, description: str, fields: List[Dict[str, Any]]) -> Entity: """Create entity from field definitions.""" entity_fields = [ Field( name=f['name'], data_type=DataType(f.get('type', 'string')), nullable=f.get('nullable', True), default=f.get('default'), description=f.get('description', ''), constraints=[ConstraintType(c) for c in f.get('constraints', [])] ) for f in fields ] entity = Entity(name=name, description=description, fields=entity_fields) self.add_entity(entity) return entity def create_relationship(self, from_entity: str, to_entity: str, relation_type: str = "1:N", from_field: str = None) -> Relationship: """Create relationship between entities.""" rel = Relationship( name=f"{from_entity}_{to_entity}", from_entity=from_entity, to_entity=to_entity, relation_type=RelationType(relation_type), from_field=from_field or f"{to_entity.lower()}_id", to_field="id" ) self.add_relationship(rel) return rel def generate_sql_schema(self, dialect: str = "postgresql") -> str: """Generate SQL DDL statements.""" sql = [] type_map = { DataType.STRING: "VARCHAR(255)", DataType.INTEGER: "INTEGER", DataType.FLOAT: "DECIMAL(15,2)", DataType.BOOLEAN: "BOOLEAN", DataType.DATE: "DATE", DataType.DATETIME: "TIMESTAMP", DataType.TEXT: "TEXT", DataType.JSON: "JSONB" if dialect == "postgresql" else "JSON" } for name, entity in self.entities.items(): columns = [] for fld in entity.fields: col = f" {fld.name} {type_map.get(fld.data_type, 'VARCHAR(255)')}" if not fld.nullable: col += " NOT NULL" if ConstraintType.PRIMARY_KEY in fld.constraints: col += " PRIMARY KEY" columns.append(col) sql.append(f"CREATE TABLE {name} (\n" + ",\n".join(columns) + "\n);") for rel in self.relationships: sql.append(f"""ALTER TABLE {rel.from_entity} ADD CONSTRAINT fk_{rel.name} FOREIGN KEY ({rel.from_field}) REFERENCES {rel.to_entity}({rel.to_field});""") return "\n\n".join(sql) def generate_json_schema(self) -> Dict[str, Any]: """Generate JSON Schema representation.""" schemas = {} for name, entity in self.entities.items(): properties = {} required = [] for fld in entity.fields: prop = {"description": fld.description} if fld.data_type == DataType.STRING: prop["type"] = "string" elif fld.data_type == DataType.INTEGER: prop["type"] = "integer" elif fld.data_type == DataType.FLOAT: prop["type"] = "number" elif fld.data_type == DataType.BOOLEAN: prop["type"] = "boolean" else: prop["type"] = "string" properties[fld.name] = prop if not fld.nullable: required.append(fld.name) schemas[name] = { "type": "object", "title": entity.description, "properties": properties, "required": required } return schemas def generate_er_diagram(self) -> str: """Generate Mermaid ER diagram.""" lines = ["erDiagram"] for name, entity in self.entities.items(): for fld in entity.fields[:5]: lines.append(f" {name} {{") lines.append(f" {fld.data_type.value} {fld.name}") lines.append(" }") for rel in self.relationships: rel_symbol = { RelationType.ONE_TO_ONE: "||--||", RelationType.ONE_TO_MANY: "||--o{", RelationType.MANY_TO_MANY: "}o--o{" }.get(rel.relation_type, "||--o{") lines.append(f" {rel.from_entity} {rel_symbol} {rel.to_entity} : \"{rel.name}\"") return "\n".join(lines) def validate_model(self) -> List[str]: """Validate data model for issues.""" issues = [] for rel in self.relationships: if rel.from_entity not in self.entities: issues.append(f"Missing entity: {rel.from_entity}") if rel.to_entity not in self.entities: issues.append(f"Missing entity: {rel.to_entity}") for name, entity in self.entities.items(): has_pk = any(ConstraintType.PRIMARY_KEY in f.constraints for f in entity.fields) if not has_pk: issues.append(f"Entity '{name}' has no primary key") return issues class ConstructionEntities: """Standard construction data entities.""" @staticmethod def project_entity() -> Entity: return Entity( name="projects", description="Construction projects", fields=[ Field("id", DataType.INTEGER, False, constraints=[ConstraintType.PRIMARY_KEY]), Field("code", DataType.STRING, False, constraints=[ConstraintType.UNIQUE]), Field("name", DataType.STRING, False), Field("status", DataType.STRING), Field("start_date", DataType.DATE), Field("end_date", DataType.DATE), Field("budget", DataType.FLOAT) ] ) @staticmethod def activity_entity() -> Entity: return Entity( name="activities", description="Schedule activities", fields=[ Field("id", DataType.INTEGER, False, constraints=[ConstraintType.PRIMARY_KEY]), Field("project_id", DataType.INTEGER, False), Field("wbs_code", DataType.STRING), Field("name", DataType.STRING, False), Field("start_date", DataType.DATE), Field("end_date", DataType.DATE), Field("percent_complete", DataType.FLOAT) ] ) @staticmethod def cost_item_entity() -> Entity: return Entity( name="cost_items", description="Project cost items", fields=[ Field("id", DataType.INTEGER, False, constraints=[ConstraintType.PRIMARY_KEY]), Field("project_id", DataType.INTEGER, False), Field("wbs_code", DataType.STRING), Field("description", DataType.STRING), Field("budgeted_cost", DataType.FLOAT), Field("actual_cost", DataType.FLOAT) ] )
python# Create model model = ConstructionDataModel("Office Building A") # Add standard entities model.add_entity(ConstructionEntities.project_entity()) model.add_entity(ConstructionEntities.activity_entity()) model.add_entity(ConstructionEntities.cost_item_entity()) # Add relationships model.create_relationship("activities", "projects") model.create_relationship("cost_items", "projects") # Generate SQL sql = model.generate_sql_schema("postgresql") print(sql)
pythonmodel.create_entity( name="change_orders", description="Project change orders", fields=[ {"name": "id", "type": "integer", "nullable": False, "constraints": ["primary_key"]}, {"name": "project_id", "type": "integer", "nullable": False}, {"name": "amount", "type": "float"}, {"name": "status", "type": "string"} ] )
pythoner_diagram = model.generate_er_diagram() print(er_diagram)
pythonissues = model.validate_model() for issue in issues: print(f"Issue: {issue}")
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 24,599 | 39,859 | +62% | 1 | 1 | 0% | 5,716 | 7,160 | +25% | 0 | 0 | — |
case-02 | fail→fail | 18,601 | 19,811 | +7% | 1 | 1 | 0% | 4,120 | 7,233 | +76% | 0 | 0 | — |
case-03 | fail→fail | 21,906 | 14,218 | -35% | 1 | 1 | 0% | 4,627 | 5,873 | +27% | 0 | 0 | — |
case-04 | pass→pass | 18,263 | 15,965 | -13% | 1 | 1 | 0% | 3,576 | 5,983 | +67% | 0 | 0 | — |
case-05 | pass→pass | 17,725 | 13,240 | -25% | 1 | 1 | 0% | 3,577 | 5,612 | +57% | 0 | 0 | — |
case-06 | pass→pass | 20,814 | 15,603 | -25% | 1 | 1 | 0% | 4,058 | 5,853 | +44% | 0 | 0 | — |
case-07 | pass→pass | 10,425 | 6,768 | -35% | 1 | 1 | 0% | 1,905 | 4,014 | +111% | 0 | 0 | — |
case-08 | fail→pass | 10,837 | 3,955 | -64% | 1 | 1 | 0% | 1,852 | 3,364 | +82% | 0 | 0 | — |
case-09 | fail→pass | 3,490 | 4,057 | +16% | 1 | 1 | 0% | 623 | 3,451 | +454% | 0 | 0 | — |
case-10 | fail→pass | 15,263 | 3,256 | -79% | 1 | 1 | 0% | 2,494 | 3,330 | +34% | 0 | 0 | — |
case-11 | fail→pass | 13,622 | 4,568 | -66% | 1 | 1 | 0% | 2,238 | 3,616 | +62% | 0 | 0 | — |
case-12 | pass→pass | 8,377 | 3,169 | -62% | 1 | 1 | 0% | 1,716 | 3,271 | +91% | 0 | 0 | — |
case-13 | pass→pass | 6,471 | 3,618 | -44% | 1 | 1 | 0% | 1,031 | 3,317 | +222% | 0 | 0 | — |
case-14 | fail→pass | 10,283 | 2,733 | -73% | 1 | 1 | 0% | 1,614 | 3,205 | +99% | 0 | 0 | — |
case-15 | pass→pass | 9,124 | 1,571 | -83% | 1 | 1 | 0% | 1,508 | 2,952 | +96% | 0 | 0 | — |
case-16 | fail→pass | 8,957 | 2,195 | -75% | 1 | 1 | 0% | 1,632 | 2,987 | +83% | 0 | 0 | — |
case-17 | fail→pass | 10,783 | 3,719 | -66% | 1 | 1 | 0% | 1,880 | 3,383 | +80% | 0 | 0 | — |
case-18 | pass→pass | 11,334 | 6,756 | -40% | 1 | 1 | 0% | 2,034 | 3,899 | +92% | 0 | 0 | — |
case-19 | pass→pass | 4,206 | 3,177 | -24% | 1 | 1 | 0% | 695 | 3,234 | +365% | 0 | 0 | — |
case-20 | pass→pass | 15,918 | 3,428 | -78% | 1 | 1 | 0% | 2,424 | 3,222 | +33% | 0 | 0 | — |
case-21 | fail→pass | 9,890 | 2,670 | -73% | 1 | 1 | 0% | 1,743 | 3,076 | +76% | 0 | 0 | — |
case-22 | pass→pass | 12,865 | 13,966 | +9% | 1 | 1 | 0% | 2,869 | 5,969 | +108% | 0 | 0 | — |
case-23 | pass→pass | 6,044 | 3,541 | -41% | 1 | 1 | 0% | 1,124 | 3,352 | +198% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +39 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.