Appearance
The setup file (JSON)
A parsing setup can be downloaded as a JSON file and uploaded back. The file holds every rule of the setup, so it is how you move a setup between companies, keep a copy outside the platform, or write a setup somewhere else and bring it in finished.
This page is the reference for that file: every field, every key, and what a value has to look like for the platform to read it.
You do not have to write it by hand
Claude can write the whole file for you from a sample IFC and a description of your panels. See Let Claude write it at the end of this page.
Download and upload
Both live in Projects Settings → IFC Parsing Setups, in the company menu under Settings.
| Action | Where | What it does |
|---|---|---|
| Download | The ↓ button on a setup row | Saves ifcps_<name>.json. The uuid and the company are stripped, so the file describes rules and nothing else. |
| Upload | UPLOAD in the toolbar | Reads the file and opens the editor filled in with it. |
Uploading saves nothing on its own. The file lands in the normal editor, you check it tab by tab, and it exists only when you press Save.
A uuid in the file overwrites that setup
A downloaded file carries no uuid, so uploading it always creates a new setup. If you add a uuid by hand, saving overwrites the setup with that uuid and re-analyses every project using it. Leave it out.
The two building blocks
Almost every value in the file is one of two things.
A rule
Used by the categories, the assembly filter, the machine flags, the branches and the classes. Three keys:
json
{ "prop_key": "reference", "match": "prefix", "value": "TR" }{ "prop_key": "reference", "match": "prefix", "value": "TR" }| Key | Value |
|---|---|
prop_key | The property to look into. Any property name the file carries, or one of the five element attributes below. Case does not matter. |
match | "all", "prefix" or "contains". |
value | What to look for. Case does not matter. |
match | Matches when the property value |
|---|---|
all | is exactly this value |
prefix | starts with this value |
contains | holds this value anywhere |
A part matches a setting when any one of its rules matches. A rule whose prop_key the element does not carry never matches, and neither does one whose match is missing or misspelled.
Never leave value empty
An empty value with match set to prefix or contains matches every element that carries the property, because every string starts with nothing and holds nothing. A whole category would swallow the panel.
The editor refuses to save a rule with an empty value, so an uploaded file is caught before it does any harm — but it is caught as a red field on some tab you have to go and find. Do not write one.
The five element attributes are always available as prop_key, whatever the file's property sets are called:
name · ifc_tag · ifc_id · object_type · description
Everything else has to be a property the exporter actually wrote: reference, zone, profile and the rest are only useful if your IFC carries a property with that name.
A property name list
Used by everything under props, steel_props and project_props. Here you do not match, you say where to read a value from: a list of property names, tried in order, first one present on the element wins.
json
"weight": ["WEIGHT", "GEWICHT"]"weight": ["WEIGHT", "GEWICHT"]Reading from one property set only
Both blocks take an optional pset, for the case where two property sets carry the same property name with different values.
json
{ "prop_key": "reference", "match": "prefix", "value": "TR", "pset": "Tekla_Common" }
{ "key": "ZONE", "pset": "Pset_WallCommon" }{ "prop_key": "reference", "match": "prefix", "value": "TR", "pset": "Tekla_Common" }
{ "key": "ZONE", "pset": "Pset_WallCommon" }pset | What is read |
|---|---|
| absent | The property wherever it appears. The normal case. |
"Tekla_Common" | That property set only. |
"" | The element's own attributes only. |
A property name list takes the plain string form "ZONE" or the scoped form {"key": "ZONE", "pset": "..."}, and you can mix both in the same list.
The editor offers pset on the category, filter and flag rules and on the property names. It is not offered on the entries of custom_branches and part_classes, so leave it out there.
BTLx files have no property sets
The same setup reads BTLx files, where prop_key is the name of an attribute on the BTLx part (Designation, Material, Group). A scoped entry never matches a BTLx part.
Top-level fields
json
{
"name": "Tekla Wall Panels",
"is_default": false,
"setup": {},
"props": {},
"steel_setup": {},
"steel_props": {},
"project_setup": {},
"project_props": {},
"level_setup": {},
"custom_branches": [],
"part_classes": []
}{
"name": "Tekla Wall Panels",
"is_default": false,
"setup": {},
"props": {},
"steel_setup": {},
"steel_props": {},
"project_setup": {},
"project_props": {},
"level_setup": {},
"custom_branches": [],
"part_classes": []
}| Field | Type | Holds |
|---|---|---|
name | string, max 22 characters | The setup name. Required. |
is_default | boolean | Whether new projects start from this setup. Only one setup per company can be the default. |
setup | object | Panel part categories, operations and machine flags. Rule lists. |
props | object | Part properties. Property name lists. |
steel_setup | object | Steel cage categories. Rule lists. |
steel_props | object | Steel cage properties. Property name lists. |
project_setup | object | The assembly filter. Rule lists. |
project_props | object | What is read off a module or an assembly. Property name lists. |
level_setup | object | How the file is split into levels, plus the BTLx zone rules. |
custom_branches | array | Your own kinds of part. |
part_classes | array | Your own classes and their behaviours. |
Every one of them may be left out, and an empty object or list is valid. A category with no rules simply recognises nothing.
Fields you can ignore
wood_setup, wood_props, concrete_setup, concrete_props, custom_setup, custom_props and level_props exist in the file for compatibility. The editor writes to none of them. Leave them out.
read_only and company_lock are locks, not rules. Leave them out too.
setup — categories, operations and flags
Every key holds a list of rules.
A mistyped key here is not ignored
The rules under it still run, and a part matching one is filed under a category nothing recognises: it drops out of the parts list, the measurements, the reports and the machine files without a word. It can also outrank a correct rule and take a part away from the category it belonged in.
Check every key against the tables below. This is the single most common way a hand-written setup goes wrong.
Frame
| Key | What it is |
|---|---|
top_rail | The horizontal wood at the top of the frame |
bottom_rail | The horizontal wood at the bottom |
extra_top_rail | Woods over the top rail |
extra_bottom_rail | Woods below the bottom rail |
wood | Any other frame wood: studs, noggins, diagonals |
extra_wood | Frame woods outside the standard framing |
batten | Battens fixed on the panel |
Plates
| Key | What it is |
|---|---|
plate | A sheet on a face of the frame |
core_plate | A plate inside the frame |
Other parts
| Key | What it is |
|---|---|
brick | Single bricks or stones |
opening | Door and window placeholders, not produced |
Areas and flags
| Key | What it is |
|---|---|
lockout_area | Areas the machine must not work on |
isolated_area | Areas that carry insulation |
skip_framing_wood | BTLx parts that must not be counted as framing wood |
Operation lines
| Key | What it is |
|---|---|
frame_nail | Frame nail lines |
frame_nail_single | Single frame nails |
plate_nail | Plate nail lines |
plate_screw | Plate screws |
glue | Glue lines |
glue_area | Glue areas |
Cutting and milling
| Key | What it is |
|---|---|
frame_saw | Saw cuts on the frame |
frame_drill | Drills on the frame |
milling | Milling lines |
sawing | Sawing lines on the plates |
drilling | Drilling operations |
Machine flags (BTLx)
Each one mirrors a property of the same job under props, for files that carry attributes instead of properties.
| Key | What it is |
|---|---|
brick_machine_flag | Bricks built by the machine |
isolation_machine_flag | Insulation applied by the machine |
battens_machine_flag | Battens fitted by the machine |
v_mill | Milling lines done as a V-mill |
Two keys that used to live here
ignore_me and hidden_material were categories and are now class behaviours — skip_everything and hide_in_viewer on a part class. A setup written today should use the classes; old files keep working. not_isolated_area was never read by anything.
props — part properties
Every key holds a list of property names. Unlike setup, a key that is not in this table is read by nothing — silently, so the property simply comes out empty and nothing says why.
| Key | What it reads |
|---|---|
name | The part name. Left out, the element's own Name is used. |
fab_ref | The reference, expected to be the same for parts of the same shape |
material | The material name |
shaped_section_name | The profile name, for sections that are not rectangular |
profile_joined | Whether the profile is extended or joined |
zone | The panel layer the part belongs to |
finish | The finish |
comment | A free comment |
weight | The weight in kg |
volume | The volume in m³ |
isolation_order | The order insulation areas are filled in |
nail_ctc | Centre-to-centre distance in nail and screw lines |
mill_depth | Depth of a milling or sawing line |
nail_tool_id | The tool the MOB2 machine nails with |
frame_saw_side | The side of the frame the saw works on |
brick_type | The type of brick |
is_machine_brick | Bricks built by the machine |
is_machine_isolation | Insulation applied by the machine |
is_machine_battens | Battens fitted by the machine |
is_vmill | Milling lines done as a V-mill |
skip_framing_wood | Parts not to be counted as framing wood |
The zone reads a letter as a sign
A zone value holding a B becomes a negative zone; anything else stays positive, and letters are stripped. So F1 is 1 and B2 is -2.
That rule applies to every numeric property, so keep a B out of the values you map to nail_ctc, mill_depth, isolation_order and nail_tool_id.
steel_setup and steel_props
Only for the steel cage flow. Leave both out if you do not produce steel cages.
steel_setup key | What it is |
|---|---|
top_steel_rail | Top steel profile |
bottom_steel_rail | Bottom steel profile |
steel_profile | Any other steel profile |
steel_plate | Steel plate |
steel_welding_seam | Welding seam |
steel_props key | What it reads |
|---|---|
steel_compute_holes | Whether the holes of the profile are computed |
assembly_id | Assembly id, level 1 |
assembly_id2 | Assembly id, level 2 |
project_props — read off a module or an assembly
Property name lists, read off the container, not off its parts.
| Key | What it reads |
|---|---|
module_design_name | The module design name. Instances of the same design share it. |
custom_module_id | The unique id of each module instance |
assembly_design_name | The panel name. Left out, the container's own name is used. |
custom_assembly_id | The unique id of each panel instance, such as the element number the customer uses. Stored on each assembly unit as its unit ID. |
phase_name | The phase a panel belongs to |
batch_name | The batch a panel belongs to |
client_meta | Properties copied onto the design as client data |
project_setup — the module and assembly filters
Four rule lists deciding which modules and assemblies are split out of the project file. The split always takes out every level; these lists leave things out.
json
"project_setup": {
"module_filter": [],
"module_filter_out": [{"prop_key": "name", "match": "prefix", "value": "TEST"}],
"assembly_filter": [{"prop_key": "ASSEMBLY_PREFIX", "match": "prefix", "value": "WA"}],
"assembly_filter_out": [{"prop_key": "name", "match": "contains", "value": "_TEST"}]
}"project_setup": {
"module_filter": [],
"module_filter_out": [{"prop_key": "name", "match": "prefix", "value": "TEST"}],
"assembly_filter": [{"prop_key": "ASSEMBLY_PREFIX", "match": "prefix", "value": "WA"}],
"assembly_filter_out": [{"prop_key": "name", "match": "contains", "value": "_TEST"}]
}| Key | Meaning |
|---|---|
module_filter | Empty or absent, every module is split out as a module IFC. With rules, only matching modules are. |
module_filter_out | Matching modules are never split out, even when the first list keeps them. |
assembly_filter | Empty or absent, every assembly is split. With rules, only matching assemblies are split. |
assembly_filter_out | Matching assemblies are never split, even when the first list keeps them. |
In each pair the drop list always wins. An assembly that is not split produces nothing: no IFC file, no design, no row in the phase and batch counts. A module that is not split gives no module IFC and no module design; its assemblies are still split, as the assembly lists say. A module rule reads the module's name under name, and the properties of its first assembly.
level_setup — how the file is split
Three levels, each an object rather than a list of rules.
json
"level_setup": {
"module": { "detection": "ifc_class", "match": "IfcElementAssembly" },
"assembly": { "detection": "ifc_class", "match": "IfcElementAssembly" },
"subassembly": { "detection": "part_prop", "match": "SUBASSEMBLY" }
}"level_setup": {
"module": { "detection": "ifc_class", "match": "IfcElementAssembly" },
"assembly": { "detection": "ifc_class", "match": "IfcElementAssembly" },
"subassembly": { "detection": "part_prop", "match": "SUBASSEMBLY" }
}detection | match is |
|---|---|
ifc_class | An IFC class name: IfcElementAssembly, IfcWall, IfcSlab, IfcPresentationLayerAssignment |
part_prop | A property name read off the parts |
ass_prop | A property name read off the assembly |
On the subassembly level, ifc_class and ass_prop read the group a part sits in, and only when that group is inside the panel: a part straight in the panel belongs to the panel. For ifc_class, match is optional and narrows the groups to one class. See Subassemblies.
The same object also holds two more keys, each a plain list of rules, because BTLx layer numbers carry no sign and the face of the panel has to be declared.
| Key | What it is |
|---|---|
positive_zone | BTLx layers on the reference face of the panel |
negative_zone | BTLx layers on the opposite face |
json
"positive_zone": [{"prop_key": "Layer", "match": "all", "value": "1"}],
"negative_zone": [{"prop_key": "Layer", "match": "all", "value": "2"}]"positive_zone": [{"prop_key": "Layer", "match": "all", "value": "1"}],
"negative_zone": [{"prop_key": "Layer", "match": "all", "value": "2"}]They do nothing for IFC files, where the zone sign comes from the zone property instead.
custom_branches
Kinds of part beyond the built-in timber and plate: windows, connectors, airtightness, electrical, plumbing.
json
"custom_branches": [
{
"name": "windows",
"alike": "generic",
"logistics": true,
"metrics": true,
"entries": [{"prop_key": "reference", "match": "prefix", "value": "WIN"}]
}
]"custom_branches": [
{
"name": "windows",
"alike": "generic",
"logistics": true,
"metrics": true,
"entries": [{"prop_key": "reference", "match": "prefix", "value": "WIN"}]
}
]| Key | Value |
|---|---|
name | The branch name. Lowercased everywhere it is used. |
alike | "generic", "plate" or "wood" — the geometry it resembles, so drawings and cutting lists know how to treat it. |
logistics | true puts its parts in the parts list and through logistics. Default false. |
metrics | true counts its parts in the panel width, height, thickness and surface. Default false. |
entries | The rules that recognise it. |
metrics is off by default and that has consequences
A branch is recognised before a part falls back to timber or plate from its category, so a part your setup knows perfectly well can end up with no category — and a part with no category is outside every panel measurement.
Turn metrics on for cladding and window frames. Leave it off for brackets and anything that sticks out past the frame.
part_classes
A category says what a part is. A class says how your factory treats it. A part can match several classes. Its name is the first class in the list whose rules match, so put the more specific classes first. Its behaviours add up from every class it matches.
json
"part_classes": [
{
"name": "Placeholder",
"entries": [{"prop_key": "name", "match": "prefix", "value": "PLH"}],
"behaviours": {"skip_area": true, "skip_x": true, "skip_y": true}
}
]"part_classes": [
{
"name": "Placeholder",
"entries": [{"prop_key": "name", "match": "prefix", "value": "PLH"}],
"behaviours": {"skip_area": true, "skip_x": true, "skip_y": true}
}
]| Key | Value |
|---|---|
name | The class name. Settings that behave differently per kind of part, the framing nail matrix first, look it up by this. |
entries | The rules that recognise it. |
behaviours | Optional. Absent means the part behaves normally. |
| Behaviour | What it does |
|---|---|
skip_area | The part is left out of the net, gross and opening areas |
skip_x | Left out of the panel width |
skip_y | Left out of the panel height |
skip_z | Left out of the panel thickness |
skip_everything | The part is ignored completely: no parts list, no reports, no machine files |
hide_in_viewer | Still measured and still produced, only not drawn in the 3D viewer |
All of them are false when absent, and false means the part counts. Only the keys you turn on need to be in the file.
The placeholder case
A layer that is not produced but takes up the space a real one will: it has to count for the thickness, because the panel really is that thick, and not for the surface, because nothing was produced. Turn on skip_area, skip_x and skip_y, and leave skip_z off. That is the example above.
A complete example
A small but working setup. Every field it leaves out is simply not used.
json
{
"name": "Tekla Wall Panels",
"level_setup": {
"module": { "detection": "ifc_class", "match": "IfcElementAssembly" },
"assembly": { "detection": "ifc_class", "match": "IfcElementAssembly" }
},
"project_props": {
"assembly_design_name": ["ASSEMBLY_NAME"],
"phase_name": ["PHASE"],
"batch_name": ["BATCH"]
},
"project_setup": {
"assembly_filter_out": [
{ "prop_key": "name", "match": "contains", "value": "_TEST" }
]
},
"setup": {
"top_rail": [
{ "prop_key": "reference", "match": "all", "value": "TOPRAIL" },
{ "prop_key": "reference", "match": "prefix", "value": "TR" }
],
"bottom_rail": [
{ "prop_key": "reference", "match": "prefix", "value": "BR" }
],
"wood": [
{ "prop_key": "reference", "match": "prefix", "value": "W" }
],
"plate": [
{ "prop_key": "reference", "match": "prefix", "value": "P" }
],
"opening": [
{ "prop_key": "name", "match": "contains", "value": "OPENING" }
],
"frame_nail": [
{ "prop_key": "name", "match": "prefix", "value": "FNL" }
]
},
"props": {
"fab_ref": ["REFERENCE"],
"zone": ["ZONE", "LAYER"],
"material": ["MATERIAL"],
"weight": ["WEIGHT", "GEWICHT"],
"volume": ["VOLUME", "NETVOLUME"],
"nail_ctc": ["NAIL_CTC", "SCREW_CTC"]
},
"custom_branches": [
{
"name": "windows",
"alike": "generic",
"logistics": true,
"metrics": true,
"entries": [
{ "prop_key": "reference", "match": "prefix", "value": "WIN" }
]
}
],
"part_classes": [
{
"name": "Placeholder",
"entries": [
{ "prop_key": "name", "match": "prefix", "value": "PLH" }
],
"behaviours": { "skip_area": true, "skip_x": true, "skip_y": true }
}
]
}{
"name": "Tekla Wall Panels",
"level_setup": {
"module": { "detection": "ifc_class", "match": "IfcElementAssembly" },
"assembly": { "detection": "ifc_class", "match": "IfcElementAssembly" }
},
"project_props": {
"assembly_design_name": ["ASSEMBLY_NAME"],
"phase_name": ["PHASE"],
"batch_name": ["BATCH"]
},
"project_setup": {
"assembly_filter_out": [
{ "prop_key": "name", "match": "contains", "value": "_TEST" }
]
},
"setup": {
"top_rail": [
{ "prop_key": "reference", "match": "all", "value": "TOPRAIL" },
{ "prop_key": "reference", "match": "prefix", "value": "TR" }
],
"bottom_rail": [
{ "prop_key": "reference", "match": "prefix", "value": "BR" }
],
"wood": [
{ "prop_key": "reference", "match": "prefix", "value": "W" }
],
"plate": [
{ "prop_key": "reference", "match": "prefix", "value": "P" }
],
"opening": [
{ "prop_key": "name", "match": "contains", "value": "OPENING" }
],
"frame_nail": [
{ "prop_key": "name", "match": "prefix", "value": "FNL" }
]
},
"props": {
"fab_ref": ["REFERENCE"],
"zone": ["ZONE", "LAYER"],
"material": ["MATERIAL"],
"weight": ["WEIGHT", "GEWICHT"],
"volume": ["VOLUME", "NETVOLUME"],
"nail_ctc": ["NAIL_CTC", "SCREW_CTC"]
},
"custom_branches": [
{
"name": "windows",
"alike": "generic",
"logistics": true,
"metrics": true,
"entries": [
{ "prop_key": "reference", "match": "prefix", "value": "WIN" }
]
}
],
"part_classes": [
{
"name": "Placeholder",
"entries": [
{ "prop_key": "name", "match": "prefix", "value": "PLH" }
],
"behaviours": { "skip_area": true, "skip_x": true, "skip_y": true }
}
]
}Before you upload
nameis present and 22 characters or fewer.- There is no
uuid. - Every key is one from the tables above. A mistyped key under
propsis read by nothing; a mistyped key undersetupis worse, because its rules still run. - Every rule has all three of
prop_key,matchandvalue, andmatchis one ofall,prefix,contains. A misspelledmatchnever matches anything. - No rule has an empty
value. The editor refuses to save one, and withprefixorcontainsit would have matched everything. - Every
prop_keyand every property name is a property your IFC really carries. This is the one thing the file cannot tell you: check it against a sample file.
After uploading, walk the tabs before saving. The editor is the same one you would have filled in by hand, and it validates the same way.
Let Claude write it
produuz.it has a Claude connector, and writing a parsing setup is what it is most useful for. Claude can read this documentation, so it knows every key on this page and what each one is for.
Add the connector — see Claude connector (MCP) — and then:
Give it your properties. Export the property list of a few elements from your BIM application — one stud, one rail, one plate, one panel — and paste it in. That list is what nearly every rule is written from.
Describe your panels in your own words: what marks a top rail, what marks a plate, which elements are not produced, where the phase and the batch come from.
Ask for the file. For example:
Write me an IFC parsing setup JSON for produuz.it. Here are the properties of four elements from our Tekla export. Top rails have REFERENCE starting with TR, studs W, plates P. The phase is in the PHASE property of the assembly. We do not produce steel cages.
Upload it with the UPLOAD button and check every tab before saving.
Claude can also read a setup you already have. Download it, paste it in, and ask why a part is landing in the wrong category or which rules are never used.
Or let it create the setup directly
If you are a company administrator, Claude can skip the file and put the setup straight into Projects Settings → IFC Parsing Setups. It asks for a separate permission the first time, and you can say no and keep working with files.
What it creates is inert: no project uses it, nothing is re-analysed, and it cannot touch a setup that already exists or make one the default. You still open it, walk the tabs and assign it yourself. The checks on this page are not skipped either — they are applied by the tool, so a key that is not in the tables above is refused rather than stored.
Always check what comes back
Claude cannot see your IFC file, only what you tell it about it. It writes the rules; you check them against a real file. Nothing is saved until you press Save in the editor, and the first real test is Step 9 of the setup tutorial: split a sample file and look for parts landing in unknown.