Automating Revit Workflows with Claude Code Skills
Learn how to create Claude Code skills that automate Revit family creation, sheet setup, schedule generation, and model auditing
Go deeper with Archgyan Academy
Structured BIM and Revit learning paths for architects and students.
Every architect and BIM manager has a mental list of tasks that drain hours each week without producing any design value. Renaming 150 sheets, checking whether every door family has the right shared parameters, auditing model warnings before a deadline, generating quantity takeoffs that match your firm’s template. These tasks follow clear rules, repeat across every project, and feel like they should be automated. With Claude Code skills, they finally can be.
This tutorial walks through building a library of Claude Code skills specifically for Revit workflows. Each skill is a reusable markdown file that teaches Claude Code how to generate pyRevit scripts, Dynamo graphs, journal file analysis, and more. By the end, you will have a working skill library that covers the most common Revit automation needs in professional practice.
Why Revit Users Need Workflow Automation
Revit is powerful, but its interface was designed for manual, one-at-a-time operations. Consider the real cost of common tasks across a mid-size architectural project:
- Sheet creation: Setting up 80 sheets with correct title blocks, parameters, and view placements takes 2 to 3 hours of clicking through dialog boxes.
- Family QA: Checking 40 door families for correct shared parameters, subcategories, and naming conventions takes a full afternoon when done manually.
- Model audits: Reviewing warnings, finding ungrouped elements, checking workset assignments, and validating room boundaries can consume an entire day before a milestone submission.
- Schedule generation: Creating quantity takeoffs that match your firm’s formatting standards involves repetitive column setup, filtering, and formatting across multiple schedule views.
The Revit API exposes nearly everything you can do in the UI (and quite a bit you cannot). The barrier has always been the programming knowledge required to write IronPython scripts, C# add-ins, or Dynamo definitions. Claude Code skills bridge that gap. You describe what you want in plain English inside a skill file, and Claude Code generates the working script for your specific situation.
Understanding the Revit API and Where Claude Code Fits In
The Revit API is a .NET library that provides programmatic access to the Revit document model. There are several ways to execute code against it:
- pyRevit (IronPython or CPython scripts that run inside Revit via the pyRevit extension)
- Dynamo (visual programming nodes, with Python Script nodes for custom logic)
- C# add-ins (compiled plugins loaded at Revit startup)
- Revit macros (C# or VB.NET code edited in SharpDevelop inside Revit)
- Journal files (Revit’s internal command replay format, useful for batch processing)
Claude Code does not run inside Revit directly. Instead, a Claude Code skill instructs Claude to generate scripts in the appropriate format (IronPython for pyRevit, Python for Dynamo, C# for add-ins) that you then execute within Revit. Think of each skill as a recipe card: it tells Claude the exact structure, API patterns, and output format to use for a given category of Revit task.
The skill file lives in your project’s .claude/skills/ directory. When you ask Claude Code to perform a Revit task, it reads the relevant skill and produces a script tailored to your request. Here is the basic directory structure:
your-project/
.claude/
skills/
revit-family-check.md
revit-sheet-setup.md
revit-schedule-gen.md
revit-model-audit.md
revit-dynamo-gen.md
revit-journal-analysis.md
Skill: Automated Revit Family Parameter Checking
Family QA is one of the most tedious tasks in BIM management. You need to verify that every family in a category has the correct shared parameters, naming conventions, subcategory assignments, and type catalog structure. Here is a skill that generates pyRevit scripts for this purpose.
Create .claude/skills/revit-family-check.md:
# Revit Family Parameter Checker
## Purpose
Generate pyRevit IronPython scripts that audit loaded families
for parameter compliance against a firm standard.
## When to use
When the user asks to check families, audit parameters, verify
naming conventions, or validate family standards in a Revit model.
## Script structure
Always generate scripts using this pattern:
```python
# -*- coding: utf-8 -*-
__title__ = "Family Parameter Check"
__author__ = "Generated by Claude Code"
from pyrevit import revit, DB, script
output = script.get_output()
doc = revit.doc
# Configuration - modify per firm standard
REQUIRED_SHARED_PARAMS = [
"Mark", "Comments", "Assembly Code"
]
NAMING_PATTERN = r"^[A-Z]{2,4}_[A-Za-z0-9_]+$"
TARGET_CATEGORY = DB.BuiltInCategory.OST_Doors
# Collect all families in the target category
collector = DB.FilteredElementCollector(doc)
families = collector.OfClass(DB.Family).ToElements()
issues = []
for family in families:
if family.FamilyCategory and \
family.FamilyCategory.Id.IntegerValue == int(TARGET_CATEGORY):
# Check naming convention
import re
if not re.match(NAMING_PATTERN, family.Name):
issues.append({
"family": family.Name,
"issue": "Naming convention violation",
"expected": NAMING_PATTERN
})
# Check required parameters
family_doc = doc.EditFamily(family)
if family_doc:
mgr = family_doc.FamilyManager
param_names = [p.Definition.Name for p in mgr.Parameters]
for req_param in REQUIRED_SHARED_PARAMS:
if req_param not in param_names:
issues.append({
"family": family.Name,
"issue": "Missing parameter: " + req_param,
"expected": "Parameter should exist"
})
family_doc.Close(False)
# Output results
output.print_md("# Family Parameter Audit Report")
output.print_md("**Families checked:** {}".format(len(families)))
output.print_md("**Issues found:** {}".format(len(issues)))
for issue in issues:
output.print_md("- **{}**: {} (expected: {})".format(
issue["family"], issue["issue"], issue["expected"]
))
```
## Customization rules
- Always let the user specify which category to check (doors, windows,
furniture, generic models, etc.)
- Always let the user define their firm's required parameters as a list
- Include a naming convention regex that can be modified
- Output results using pyRevit's output module for in-Revit display
- Never modify families automatically unless the user explicitly asks
for auto-fix mode
When you tell Claude Code “check all door families for our standard parameters,” it reads this skill and generates a script customized to your specific parameter list and naming rules.
Skill: Sheet Setup Automation
Creating sheets from a master list is one of the clearest automation wins in Revit. Most firms maintain a spreadsheet or template that defines sheet numbers, names, title block types, and discipline assignments. This skill generates a pyRevit script that reads a CSV or directly embedded list and creates all sheets in one execution.
Create .claude/skills/revit-sheet-setup.md:
# Revit Sheet Setup Automation
## Purpose
Generate pyRevit scripts that batch-create sheets from a
structured list, applying correct title blocks and parameters.
## When to use
When the user asks to create sheets, set up a sheet list,
batch-generate sheets, or populate a drawing set from a template.
## Input format
Accept sheet definitions as either:
1. A CSV file path with columns: Number, Name, TitleBlock, Discipline
2. An inline Python list of dictionaries
## Script template
```python
# -*- coding: utf-8 -*-
__title__ = "Batch Sheet Creator"
__author__ = "Generated by Claude Code"
from pyrevit import revit, DB, script
from pyrevit import forms
output = script.get_output()
doc = revit.doc
SHEETS = [
{"number": "A101", "name": "Floor Plan - Level 1",
"titleblock": "E1 30x42 Horizontal", "discipline": "Architectural"},
{"number": "A102", "name": "Floor Plan - Level 2",
"titleblock": "E1 30x42 Horizontal", "discipline": "Architectural"},
{"number": "A201", "name": "Building Sections",
"titleblock": "E1 30x42 Horizontal", "discipline": "Architectural"},
{"number": "A301", "name": "Wall Sections",
"titleblock": "E1 30x42 Horizontal", "discipline": "Architectural"},
]
# Find title block family symbols
tb_collector = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_TitleBlocks) \
.WhereElementIsElementType()
titleblocks = {tb.FamilyName: tb for tb in tb_collector}
created = []
skipped = []
with revit.Transaction("Batch Create Sheets"):
for sheet_def in SHEETS:
# Check if sheet number already exists
existing = DB.FilteredElementCollector(doc) \
.OfClass(DB.ViewSheet).ToElements()
existing_numbers = [s.SheetNumber for s in existing]
if sheet_def["number"] in existing_numbers:
skipped.append(sheet_def["number"])
continue
# Find matching title block
tb_symbol = titleblocks.get(sheet_def["titleblock"])
if not tb_symbol:
output.print_md("WARNING: Title block '{}' not found".format(
sheet_def["titleblock"]))
continue
# Create sheet
new_sheet = DB.ViewSheet.Create(doc, tb_symbol.Id)
new_sheet.SheetNumber = sheet_def["number"]
new_sheet.Name = sheet_def["name"]
created.append(sheet_def["number"])
output.print_md("# Sheet Creation Report")
output.print_md("**Created:** {} sheets".format(len(created)))
output.print_md("**Skipped (existing):** {} sheets".format(len(skipped)))
for num in created:
output.print_md("- Created: {}".format(num))
```
## Rules
- Always check for existing sheet numbers before creating
- Always wrap creation in a single transaction for undo support
- Title block lookup must be by family name, not hard-coded ElementId
- Include a dry-run mode option that reports what would be created
without actually creating anything
The key advantage here is that the skill enforces patterns that prevent common mistakes: duplicate sheet detection, transaction wrapping for clean undo, and title block lookup by name rather than brittle element IDs.
Skill: Schedule and Quantity Takeoff Generation
Quantity takeoffs and material schedules follow predictable patterns, but setting them up in Revit’s schedule editor is slow. This skill generates pyRevit scripts that create and configure schedule views programmatically.
Create .claude/skills/revit-schedule-gen.md:
# Revit Schedule and Quantity Takeoff Generator
## Purpose
Generate pyRevit scripts that create schedule views with
specified fields, filters, sorting, and formatting.
## Script pattern
```python
# -*- coding: utf-8 -*-
__title__ = "Generate Schedule"
__author__ = "Generated by Claude Code"
from pyrevit import revit, DB, script
output = script.get_output()
doc = revit.doc
SCHEDULE_CONFIG = {
"name": "Door Schedule - QTO",
"category": DB.BuiltInCategory.OST_Doors,
"fields": [
"Mark", "Level", "Width", "Height",
"Frame Type", "Fire Rating", "Count"
],
"sort_by": ["Level", "Mark"],
"group_by": "Level",
"itemize_every_instance": True
}
with revit.Transaction("Create Schedule"):
# Create the schedule view
schedule = DB.ViewSchedule.CreateSchedule(
doc,
DB.ElementId(SCHEDULE_CONFIG["category"])
)
schedule.Name = SCHEDULE_CONFIG["name"]
# Get schedulable fields
definition = schedule.Definition
schedulable = definition.GetSchedulableFields()
field_map = {}
for sf in schedulable:
field_map[sf.GetName(doc)] = sf
# Add fields in order
for field_name in SCHEDULE_CONFIG["fields"]:
if field_name in field_map:
definition.AddField(field_map[field_name])
else:
output.print_md("WARNING: Field '{}' not found".format(
field_name))
# Configure sorting and grouping
for sort_field_name in SCHEDULE_CONFIG["sort_by"]:
if sort_field_name in field_map:
added_field = None
for i in range(definition.GetFieldCount()):
f = definition.GetField(i)
if f.GetName() == sort_field_name:
added_field = f
break
if added_field:
sort_group = DB.ScheduleSortGroupField(
added_field.FieldId
)
if sort_field_name == SCHEDULE_CONFIG.get("group_by"):
sort_group.ShowHeader = True
sort_group.ShowFooter = True
definition.AddSortGroupField(sort_group)
# Set itemization
definition.IsItemized = SCHEDULE_CONFIG["itemize_every_instance"]
output.print_md("# Schedule Created")
output.print_md("**Name:** {}".format(SCHEDULE_CONFIG["name"]))
output.print_md("**Fields:** {}".format(len(SCHEDULE_CONFIG["fields"])))
```
## Customization rules
- Accept any Revit category (doors, walls, rooms, windows, etc.)
- Let the user specify fields by display name, not internal parameter name
- Support sorting, grouping, and conditional formatting
- For quantity takeoffs, always include a Count field and set itemization
appropriately
- Handle shared parameters and project parameters in the field lookup
This skill becomes especially powerful when combined with your firm’s standard schedule templates. You can tell Claude Code “create our standard door schedule for this project” and it generates the exact script with your fields, sorting, and formatting rules.
Skill: Model Health Audit
Before every milestone submission, someone on the team spends hours reviewing model health. Warnings, workset assignments, ungrouped elements, room boundary issues, and duplicate types all need checking. This skill generates a comprehensive audit script.
Create .claude/skills/revit-model-audit.md:
# Revit Model Health Audit
## Purpose
Generate pyRevit scripts that perform comprehensive model health
checks and produce a formatted report.
## Audit categories
1. **Warnings:** Count and categorize all active model warnings
2. **Worksets:** Find elements on incorrect worksets
3. **Groups:** Find ungrouped detail items in group instances
4. **Rooms:** Check for unplaced, unenclosed, or redundant rooms
5. **Views:** Find unused views (not placed on any sheet)
6. **Line styles:** Find direct model line usage (should use detail lines)
7. **Duplicate types:** Find family types with near-identical parameters
## Script template
```python
# -*- coding: utf-8 -*-
__title__ = "Model Health Audit"
__author__ = "Generated by Claude Code"
from pyrevit import revit, DB, script
from collections import Counter
output = script.get_output()
doc = revit.doc
report = {"warnings": [], "worksets": [], "rooms": [],
"unused_views": [], "duplicates": []}
# 1. Warning Analysis
warnings = doc.GetWarnings()
warning_types = Counter()
for w in warnings:
desc = w.GetDescriptionText()
warning_types[desc] += 1
output.print_md("# Model Health Audit Report")
output.print_md("## Warnings ({} total)".format(len(warnings)))
for desc, count in warning_types.most_common(20):
output.print_md("- **{}x** {}".format(count, desc))
# 2. Room Check
room_collector = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Rooms)
rooms = room_collector.ToElements()
unplaced = [r for r in rooms if r.Area == 0 and r.Location is None]
unenclosed = [r for r in rooms
if r.Area == 0 and r.Location is not None]
output.print_md("## Rooms")
output.print_md("- **Total rooms:** {}".format(len(rooms)))
output.print_md("- **Unplaced:** {}".format(len(unplaced)))
output.print_md("- **Not enclosed:** {}".format(len(unenclosed)))
# 3. Unused Views
all_views = DB.FilteredElementCollector(doc) \
.OfClass(DB.View).ToElements()
all_sheets = DB.FilteredElementCollector(doc) \
.OfClass(DB.ViewSheet).ToElements()
placed_view_ids = set()
for sheet in all_sheets:
for vp_id in sheet.GetAllPlacedViews():
placed_view_ids.add(vp_id.IntegerValue)
unused = [v for v in all_views
if not v.IsTemplate
and v.Id.IntegerValue not in placed_view_ids
and not isinstance(v, DB.ViewSheet)
and not isinstance(v, DB.ViewSchedule)]
output.print_md("## Unused Views ({})".format(len(unused)))
for v in unused[:20]:
output.print_md("- {}".format(v.Name))
if len(unused) > 20:
output.print_md("- ... and {} more".format(len(unused) - 20))
# 4. Summary Score
total_issues = len(warnings) + len(unplaced) + \
len(unenclosed) + len(unused)
if total_issues == 0:
grade = "A"
elif total_issues < 20:
grade = "B"
elif total_issues < 50:
grade = "C"
else:
grade = "D"
output.print_md("## Overall Health Grade: {}".format(grade))
output.print_md("**Total issues:** {}".format(total_issues))
```
## Rules
- Always include a summary grade or score for quick assessment
- Limit output lists to 20 items with a "and N more" overflow message
- Group warnings by type and show counts, not individual instances
- Never delete or fix anything automatically unless explicitly requested
- Support exporting the report as CSV or HTML for project records
The model audit skill is one you will use on every project. It generates a consistent, repeatable check that catches issues before they become problems in coordination meetings.
Skill: Dynamo Script Generation from Natural Language
Dynamo is Revit’s built-in visual programming environment. While the node-based interface is accessible, writing Python Script nodes for complex logic still requires coding knowledge. This skill instructs Claude Code to generate Dynamo-compatible Python scripts.
Create .claude/skills/revit-dynamo-gen.md:
# Dynamo Script Generator
## Purpose
Generate Python code for Dynamo's Python Script nodes based on
natural language descriptions of the desired geometry or data
manipulation.
## Context
- Dynamo Python nodes use CPython 3 (Dynamo 2.13+) or IronPython 2.7
- The Revit API is accessed via `clr` and `RevitServices`
- Geometry operations use the Autodesk.DesignScript.Geometry library
- Input ports are accessed via IN[0], IN[1], etc.
- Output is assigned to the OUT variable
## Template for Revit API operations
```python
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
# Input from Dynamo nodes
elements = UnwrapElement(IN[0])
TransactionManager.Instance.EnsureInTransaction(doc)
results = []
for elem in elements:
# Perform operations on each element
param = elem.LookupParameter("Comments")
if param and not param.IsReadOnly:
param.Set("Updated by Dynamo")
results.append(elem.Id.IntegerValue)
TransactionManager.Instance.TransactionTaskDone()
OUT = results
```
## Template for geometry operations
```python
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Input from Dynamo nodes
curves = IN[0]
offset_distance = IN[1]
results = []
for curve in curves:
# Create offset curves
normal = Vector.ZAxis()
offset = curve.Offset(offset_distance, normal)
results.append(offset)
OUT = results
```
## Rules
- Always specify whether the script is for CPython 3 or IronPython 2.7
- Always include clr references for any .NET API usage
- Always use TransactionManager for any document modifications
- Use UnwrapElement() for elements coming from Dynamo selection nodes
- Provide clear comments explaining each IN[] port's expected input
- Include error handling for None or empty inputs
With this skill in place, you can say “generate a Dynamo Python script that reads all room boundaries and creates floor elements matching their perimeters,” and Claude Code produces a working script with the correct imports, transaction handling, and geometry operations.
Skill: Revit Journal File Analysis and Troubleshooting
Revit journal files are plain-text logs that record every operation performed in a session. When Revit crashes or behaves unexpectedly, the journal file is the primary diagnostic tool. However, these files are dense, verbose, and difficult to parse manually. This skill teaches Claude Code to analyze journal files.
Create .claude/skills/revit-journal-analysis.md:
# Revit Journal File Analyzer
## Purpose
Analyze Revit journal (.txt) files to diagnose crashes, slow
operations, and error patterns.
## When to use
When the user shares a Revit journal file or asks about Revit
crashes, hangs, slow performance, or error messages.
## Analysis approach
1. **Find the crash point:** Search backward from the end of the file
for lines containing "Jrn.Command", "error", "exception",
"fatal", or "assert"
2. **Identify the last successful operation:** The Jrn.Command line
before the crash indicates what the user was doing
3. **Check memory usage:** Look for "MemMark" lines and track memory
growth over the session
4. **Identify slow operations:** Look for large time gaps between
consecutive timestamp lines
5. **Check for known patterns:**
- "Element has been deleted" during sync: workset conflict
- "Regeneration failure": corrupt family or constraint issue
- "Out of memory": model too large or memory leak in add-in
- "Cannot create extrusion": geometry failure in family editor
## Output format
Always structure the analysis as:
### Crash Summary
- **Last operation:** [what the user was doing]
- **Error type:** [crash/hang/slow/corruption]
- **Root cause:** [best assessment]
### Timeline
Show the last 10 significant operations before the failure.
### Recommendations
Provide specific, actionable steps to prevent recurrence.
## Rules
- Never include the raw journal file content in the output (it is too
long); always summarize
- Focus on the last 500 lines of the journal for crash analysis
- For performance analysis, sample timestamps throughout the file
- Correlate memory marks with operations to find memory-heavy tasks
This skill does not generate a pyRevit script. Instead, it instructs Claude Code on how to read and interpret a journal file that you paste or reference. This is valuable because journal file analysis is a specialized skill that most architects and BIM managers never learn.
Building a Revit Project Template Skill Library
Individual skills are useful, but the real productivity gain comes from building a cohesive library that covers your firm’s standard workflows. Here is a practical approach to organizing your skills:
Tier 1: Project setup skills (run once per project)
- Sheet setup from master list
- View template creation and assignment
- Workset structure creation
- Shared parameter loading
Tier 2: Ongoing production skills (run weekly or as needed)
- Family parameter compliance checks
- Schedule creation and updates
- Model health audits
- Clash detection preparation (export NWC with correct settings)
Tier 3: Submission and handoff skills (run at milestones)
- Drawing set validation (all views placed, all sheets numbered)
- Export automation (PDF, DWG, IFC with correct settings)
- Model cleanup (purge unused, remove orphaned elements)
Store these in a shared repository so every team member uses the same skills. The .claude/skills/ directory can live in your firm’s project template repository, meaning every new project starts with the full skill library already configured.
A practical directory structure for a firm-wide library:
firm-standards/
.claude/
skills/
setup/
revit-sheet-setup.md
revit-workset-setup.md
revit-view-templates.md
production/
revit-family-check.md
revit-schedule-gen.md
revit-model-audit.md
submission/
revit-export-pdf.md
revit-export-ifc.md
revit-purge-cleanup.md
troubleshooting/
revit-journal-analysis.md
revit-dynamo-gen.md
Integration with pyRevit and Revit API Scripts
Claude Code skills work best when integrated into your existing pyRevit toolbar and script library. Here is how to connect the two:
Step 1: Set up a pyRevit extension for generated scripts.
Create a custom pyRevit extension directory:
YourFirm.extension/
YourFirm.tab/
Audit.panel/
FamilyCheck.pushbutton/
script.py
icon.png
ModelHealth.pushbutton/
script.py
icon.png
Setup.panel/
BatchSheets.pushbutton/
script.py
icon.png
Step 2: Use Claude Code to generate scripts directly into the extension.
When you run a skill, tell Claude Code to write the output to the correct pushbutton directory. For example: “Generate a family parameter check script and save it to YourFirm.extension/YourFirm.tab/Audit.panel/FamilyCheck.pushbutton/script.py.”
Step 3: Add pyRevit-specific features to generated scripts.
Skills should instruct Claude Code to include pyRevit UI elements:
# pyRevit UI integration examples
from pyrevit import forms
# Let user select category from a dropdown
categories = ["Doors", "Windows", "Furniture", "Generic Models"]
selected = forms.SelectFromList.show(
categories,
title="Select Category to Audit",
multiselect=False
)
# Show a progress bar for long operations
with forms.ProgressBar(title="Checking families...") as pb:
for i, family in enumerate(families):
pb.update_progress(i, len(families))
# ... check family
Step 4: Handle the IronPython versus CPython distinction.
pyRevit supports both IronPython 2.7 and CPython 3 (via pyRevit’s CPython engine). Your skills should specify which runtime to target:
- IronPython 2.7: Full Revit API access, but Python 2 syntax (no f-strings,
printis a statement) - CPython 3: Modern Python syntax, but requires
clrsetup and has some API limitations
Add a line to each skill specifying the target runtime, so Claude Code generates compatible syntax.
Best Practices for Revit-Specific Skills
After building and using dozens of Revit skills, several patterns emerge as critical for reliability:
1. Always use transactions for document modifications.
Every script that changes the Revit model must wrap modifications in a transaction. Skills should enforce this pattern and never generate scripts that modify documents outside a transaction context.
2. Use FilteredElementCollector efficiently.
The collector is the primary way to query Revit elements. Skills should instruct Claude Code to apply category filters and class filters before calling ToElements() to avoid loading the entire model into memory.
# Efficient: filter first, collect second
doors = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Doors) \
.WhereElementIsNotElementType() \
.ToElements()
# Inefficient: collect everything, filter in Python
all_elements = DB.FilteredElementCollector(doc) \
.WhereElementIsNotElementType() \
.ToElements()
doors = [e for e in all_elements
if e.Category and e.Category.Name == "Doors"]
3. Handle the element deletion lifecycle.
Elements in Revit can be deleted between the time you collect them and the time you access their properties. Skills should include null checks and try/except blocks around element access.
4. Respect workset ownership.
In a workshared model, you cannot modify elements owned by another user. Scripts should check workset ownership before attempting modifications and report which elements were skipped due to ownership conflicts.
5. Include undo support.
By naming transactions descriptively, users can undo generated operations with a single Ctrl+Z. Every skill should enforce meaningful transaction names like “Batch Create 80 Sheets” rather than generic names.
6. Output actionable results.
Scripts should not just report “47 issues found.” They should list the specific elements (with element IDs that users can paste into Revit’s Select by ID dialog) and provide recommended fixes.
Quick-Start Guide: Your First Revit Skill in 10 Minutes
If you want to start using skills immediately, follow these steps to create and test your first one.
Minute 0 to 2: Create the skill file.
In your project directory (or any directory where you run Claude Code), create the skills folder and your first skill:
mkdir -p .claude/skills
Minute 2 to 5: Write the skill content.
Create .claude/skills/revit-rename-views.md with this content:
# Revit View Renamer
## Purpose
Generate a pyRevit script that renames views based on a pattern.
## Script template
```python
# -*- coding: utf-8 -*-
__title__ = "Rename Views"
__author__ = "Generated by Claude Code"
from pyrevit import revit, DB, script, forms
output = script.get_output()
doc = revit.doc
# Get all floor plan views
views = DB.FilteredElementCollector(doc) \
.OfClass(DB.View) \
.ToElements()
floor_plans = [v for v in views
if v.ViewType == DB.ViewType.FloorPlan
and not v.IsTemplate]
# Define rename mapping
PREFIX = "A-FP-"
REPLACEMENTS = {
"Level 1": "L01",
"Level 2": "L02",
"Level 3": "L03",
"Ground Floor": "GF",
"Basement": "B1",
}
renamed = []
with revit.Transaction("Rename Floor Plan Views"):
for view in floor_plans:
old_name = view.Name
new_name = old_name
for old, new in REPLACEMENTS.items():
new_name = new_name.replace(old, new)
if not new_name.startswith(PREFIX):
new_name = PREFIX + new_name
if new_name != old_name:
view.Name = new_name
renamed.append((old_name, new_name))
output.print_md("# View Rename Report")
for old, new in renamed:
output.print_md("- {} -> {}".format(old, new))
```
## Rules
- Accept custom prefixes and replacement mappings from the user
- Always check for naming conflicts before renaming
- Show before/after names in the output
Minute 5 to 8: Test with Claude Code.
Open Claude Code in the project directory and type:
Rename all floor plan views in my Revit model. Use the prefix
"ARCH-FP-" and replace "Level" with "L" followed by the number
with zero padding.
Claude Code reads your skill file and generates a customized pyRevit script with your specific prefix and replacement rules.
Minute 8 to 10: Run in Revit.
Copy the generated script into pyRevit’s Script Console (or save it as a pushbutton script). Execute it, review the rename report, and undo if the results are not what you expected.
That is the complete cycle: write a skill once, use it across every project, and let Claude Code handle the customization each time.
Where to Go from Here
The skills covered in this tutorial handle the most common Revit automation scenarios, but they are starting points. As you use them, you will discover patterns specific to your firm’s workflow that deserve their own skills. A structural engineering firm might build skills for rebar schedule generation and load path verification. An MEP firm might focus on duct sizing calculations and electrical panel schedule creation.
The key insight is that each skill encodes institutional knowledge. When a senior BIM manager writes a skill that captures the firm’s family naming convention, parameter requirements, and QA checklist, that knowledge becomes available to every team member through Claude Code. Junior staff can run the same sophisticated audits that previously required years of experience to perform manually.
Start with one skill that addresses your biggest time sink. Test it on a live project. Refine it based on real results. Then add a second skill, and a third. Within a few weeks, you will have a library that saves measurable hours on every project.
Level up your skills
Ready to learn hands-on?
- Project-based Revit & BIM courses for architects
- Go from beginner to confident professional
- Video lessons you can follow at your own pace