N8n workflow automation
221 AI skills for construction: BIM analysis, cost estimation, scheduling, document control, and automation with Claude Code
npx -y skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill n8n-workflow-automationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Build no-code/low-code automation workflows for construction using n8n. Automate data extraction, cost estimation, report generation, and system integrations without writing code.
SKILL.md
11.7 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it
n8n Workflow Automation for Construction
Overview
This skill implements visual workflow automation for construction processes using n8n. Automate repetitive tasks, integrate systems, and build PROJECT TO BUDGET pipelines without extensive programming.
Inspired by DDC Methodology - Automating the bridge between BIM models and cost estimation.
"Автоматизация процесса 'от проекта к смете' позволяет сократить время на подготовку бюджета с недель до часов." — DDC LinkedIn Post
Quick Start
n8n Installation
# Using Docker (recommended)
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
n8nio/n8n
# Using npm
npm install n8n -g
n8n start
# Access at: http://localhost:5678
Construction Workflow Examples
1. Revit to Budget Pipeline
{
"name": "Revit to Budget Automation",
"nodes": [
{
"name": "Watch Revit Export Folder",
"type": "n8n-nodes-base.localFileTrigger",
"parameters": {
"path": "/data/revit_exports",
"events": ["add"],
"fileExtension": ".xlsx"
}
},
{
"name": "Read Excel Data",
"type": "n8n-nodes-base.readWriteFile",
"parameters": {
"operation": "read",
"filePath": "={{ $json.fileName }}"
}
},
{
"name": "Parse BIM Elements",
"type": "n8n-nodes-base.code",
"parameters": {
"language": "python",
"code": "import pandas as pd\nimport json\n\ndf = pd.read_excel(items[0].binary.data)\n\nelements = df.to_dict('records')\n\nreturn [{'json': {'elements': elements, 'count': len(elements)}}]"
}
},
{
"name": "Match to Unit Prices",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "http://api.construction-prices.com/match",
"method": "POST",
"body": "={{ JSON.stringify($json.elements) }}"
}
},
{
"name": "Calculate Costs",
"type": "n8n-nodes-base.code",
"parameters": {
"language": "javascript",
"code": "const elements = items[0].json.elements;\n\nlet totalCost = 0;\nconst costBreakdown = [];\n\nfor (const elem of elements) {\n const cost = elem.quantity * elem.unit_price;\n totalCost += cost;\n costBreakdown.push({\n category: elem.category,\n quantity: elem.quantity,\n unit_price: elem.unit_price,\n total: cost\n });\n}\n\nreturn [{\n json: {\n total_cost: totalCost,\n breakdown: costBreakdown\n }\n}];"
}
},
{
"name": "Generate Report",
"type": "n8n-nodes-base.spreadsheetFile",
"parameters": {
"operation": "create",
"fileName": "cost_estimate_{{ $now.format('yyyy-MM-dd') }}.xlsx"
}
},
{
"name": "Send Email Notification",
"type": "n8n-nodes-base.emailSend",
"parameters": {
"to": "[email protected]",
"subject": "New Cost Estimate Generated",
"text": "Total estimate: ${{ $json.total_cost }}"
}
}
]
}
2. Daily Project Report Automation
{
"name": "Daily Project Report",
"nodes": [
{
"name": "Schedule Trigger",
"type": "n8n-nodes-base.cron",
"parameters": {
"cronExpression": "0 6 * * 1-5"
}
},
{
"name": "Fetch Project Data",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "{{ $env.PROJECT_API }}/status",
"method": "GET"
}
},
{
"name": "Fetch Weather Data",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.openweathermap.org/data/2.5/weather",
"qs": {
"q": "{{ $json.project_location }}",
"appid": "{{ $env.WEATHER_API_KEY }}"
}
}
},
{
"name": "Generate Report",
"type": "n8n-nodes-base.code",
"parameters": {
"language": "javascript",
"code": "const project = items[0].json;\nconst weather = items[1].json;\n\nconst report = {\n date: new Date().toISOString().split('T')[0],\n project_name: project.name,\n progress: project.progress_pct,\n weather: {\n condition: weather.weather[0].main,\n temp: Math.round(weather.main.temp - 273.15)\n },\n tasks_today: project.scheduled_tasks,\n blockers: project.blockers || []\n};\n\nreturn [{ json: report }];"
}
},
{
"name": "Post to Slack",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#project-updates",
"text": "📊 Daily Report - {{ $json.project_name }}\n\nProgress: {{ $json.progress }}%\n🌡️ Weather: {{ $json.weather.condition }} ({{ $json.weather.temp }}°C)\n\nToday's Tasks:\n{{ $json.tasks_today.join('\\n') }}"
}
}
]
}
3. BIM Model Change Detection
{
"name": "BIM Change Detection",
"nodes": [
{
"name": "Watch IFC Folder",
"type": "n8n-nodes-base.localFileTrigger",
"parameters": {
"path": "/models",
"events": ["change"],
"fileExtension": ".ifc"
}
},
{
"name": "Extract Model Data",
"type": "n8n-nodes-base.executeCommand",
"parameters": {
"command": "python /scripts/extract_ifc.py {{ $json.fileName }}"
}
},
{
"name": "Compare with Previous",
"type": "n8n-nodes-base.code",
"parameters": {
"language": "python",
"code": "import json\n\ncurrent = json.loads(items[0].json.output)\nprevious = load_previous_version()\n\nchanges = {\n 'added': [],\n 'modified': [],\n 'deleted': []\n}\n\n# Compare logic\nfor elem in current:\n if elem['id'] not in previous:\n changes['added'].append(elem)\n elif elem != previous[elem['id']]:\n changes['modified'].append(elem)\n\nfor elem_id in previous:\n if elem_id not in [e['id'] for e in current]:\n changes['deleted'].append(previous[elem_id])\n\nreturn [{'json': changes}]"
}
},
{
"name": "Update Database",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO model_changes (timestamp, changes) VALUES (NOW(), '{{ JSON.stringify($json) }}')"
}
},
{
"name": "Notify Team",
"type": "n8n-nodes-base.microsoftTeams",
"parameters": {
"message": "🔔 Model Updated\n\n+{{ $json.added.length }} elements added\n📝 {{ $json.modified.length }} elements modified\n-{{ $json.deleted.length }} elements deleted"
}
}
]
}
Common Workflow Patterns
Data Extraction Pattern
// n8n Code Node - Extract BIM Quantities
const xlsx = require('xlsx');
// Read uploaded file
const workbook = xlsx.read(items[0].binary.data, { type: 'buffer' });
const sheetName = workbook.SheetNames[0];
const data = xlsx.utils.sheet_to_json(workbook.Sheets[sheetName]);
// Process BIM elements
const quantities = {};
for (const row of data) {
const category = row['Category'] || 'Unknown';
const volume = parseFloat(row['Volume']) || 0;
if (!quantities[category]) {
quantities[category] = { count: 0, volume: 0 };
}
quantities[category].count++;
quantities[category].volume += volume;
}
return [{ json: { quantities, total_elements: data.length } }];
Cost Matching Pattern
// n8n Code Node - Match elements to unit prices
const elements = items[0].json.elements;
const priceDatabase = $env.PRICE_DATABASE;
const matched = [];
for (const elem of elements) {
// Fuzzy match description to price items
const match = await $http.post(`${priceDatabase}/search`, {
query: elem.description,
category: elem.category
});
matched.push({
...elem,
matched_item: match.data.best_match,
unit_price: match.data.unit_price,
confidence: match.data.confidence
});
}
return [{ json: { matched_elements: matched } }];
Report Generation Pattern
// n8n Code Node - Generate PDF Report
const PDFDocument = require('pdfkit');
const doc = new PDFDocument();
const buffers = [];
doc.on('data', buffers.push.bind(buffers));
// Header
doc.fontSize(20).text('Cost Estimate Report', { align: 'center' });
doc.moveDown();
// Project Info
doc.fontSize(12).text(`Project: ${items[0].json.project_name}`);
doc.text(`Date: ${new Date().toLocaleDateString()}`);
doc.moveDown();
// Cost Summary
doc.fontSize(14).text('Cost Summary', { underline: true });
for (const [category, cost] of Object.entries(items[0].json.costs)) {
doc.fontSize(10).text(`${category}: $${cost.toLocaleString()}`);
}
doc.end();
return new Promise(resolve => {
doc.on('end', () => {
resolve([{
json: { success: true },
binary: {
data: Buffer.concat(buffers).toString('base64'),
fileName: 'cost_report.pdf',
mimeType: 'application/pdf'
}
}]);
});
});
Integration Nodes
Useful n8n Nodes for Construction
Data Sources:
- Google Sheets: Project tracking, cost databases
- Airtable: Element databases, issue tracking
- PostgreSQL: BIM databases, project data
- HTTP Request: API integrations
File Processing:
- Read/Write File: Excel, CSV, JSON
- Execute Command: Python scripts, CLI tools
- Code: Custom processing logic
Communication:
- Slack: Team notifications
- Microsoft Teams: Project updates
- Email: Reports, alerts
- Telegram: Mobile notifications
Cloud Storage:
- AWS S3: Model storage
- Google Drive: Document sharing
- Dropbox: File sync
Workflow Templates
Template: QTO to Excel
{
"workflow": "QTO Extraction",
"trigger": "Manual/Webhook",
"steps": [
"Receive IFC file",
"Extract quantities (Python/IfcOpenShell)",
"Group by category",
"Add unit prices",
"Calculate totals",
"Generate Excel report",
"Upload to cloud storage",
"Send notification"
]
}
Template: Daily Status Collection
{
"workflow": "Daily Status",
"trigger": "Cron (6:00 AM)",
"steps": [
"Fetch project status from API",
"Get weather forecast",
"Check scheduled tasks",
"Compile daily report",
"Post to Slack/Teams",
"Email to stakeholders"
]
}
Best Practices
1. **Error Handling**
- Always add error branches
- Log failures to database
- Send alerts on critical failures
2. **Data Validation**
- Validate input data format
- Check for required fields
- Handle missing values gracefully
3. **Performance**
- Use batch processing for large datasets
- Implement pagination for API calls
- Cache frequently used data
4. **Security**
- Store credentials in environment variables
- Use encryption for sensitive data
- Implement access controls
Quick Reference
| Workflow Type | Trigger | Common Nodes |
|---|---|---|
| File Processing | File Trigger | Code, HTTP, Spreadsheet |
| Scheduled Reports | Cron | HTTP, Code, Email |
| Data Sync | Webhook | Database, API, Code |
| Notifications | Various | Slack, Teams, Email |
Resources
- n8n Documentation: https://docs.n8n.io
- n8n Community: https://community.n8n.io
- DDC Website: https://datadrivenconstruction.io
Next Steps
- See
etl-pipelinefor code-based data pipelines - See
llm-data-automationfor AI-powered automation - See
vector-searchfor intelligent document search
What ships with it: 2 files
1.8 KB alongside SKILL.md
- claw.json602 B
- instructions.md1.2 KB
Gives 0 of the 12 instructions most docs writing skills give in ~3.0k tokens
Counted across 1,637 of the 3,044 authors here whose files we hold, read 2026-08-07
- Announce the skill at startin 54 of 1637, across 26 files
- Convert legacy doc files before editingin 45 of 1637, across 7 files
- Predict questions readers might askin 42 of 1637, across 4 files
- Generate clarifying questions for initial contextin 42 of 1637, across 3 files
- Create document scaffold with placeholder textin 42 of 1637, across 3 files
- Brainstorm content options for each sectionin 42 of 1637, across 3 files
- Test the document with a fresh context-less instancein 42 of 1637, across 3 files
- Include exact file paths in every taskin 42 of 1637, across 15 files
- Ask interview questions one at a timein 42 of 1637, across 27 files
- Apply surgical edits during refinementin 41 of 1637, across 2 files
- Offer structured workflow or freeformin 40 of 1637, across 1 file
- Ask for document meta-contextin 40 of 1637, across 2 files
Said here and by no other author read
- add error branches to workflows
- log failures to a database
- send alerts on critical failures
- implement pagination for api calls
- use encryption for sensitive data
- implement access controls
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.