Instant Connection for Pixel Streaming

— New Feature Automated Setup

Guide

Claude Code with Archicad: BIM Data Checks on Vagon

Use Claude Code with Archicad on Vagon to build a Python audit for door IDs, classifications, and required properties, then review findings and rerun checks.

On this page

Before issuing a door schedule, a BIM coordinator needs to know which doors have missing IDs, conflicting identifiers, or incomplete required properties. Repeating that review after every model revision takes time, especially when the checks depend on the project’s classifications and data requirements.

Claude Code can help turn those requirements into a repeatable Python audit. Using Graphisoft’s official Python interface, the script reads data from an open Archicad project and produces findings tied to individual elements. You define the rules, inspect the results, and decide which model changes are appropriate.

Archicad openings schedule showing door Element IDs, dimensions, orientation, plan symbols and elevation views.

Source: Graphisoft

This guide follows a door-data audit on a project working copy. You will check identifiers, classification assignments, and required property values, then review a reported issue in Archicad and rerun the same checks after correcting it.

Vagon Cloud Computer provides the desktop environment for bringing the application, assistant, Python tools, and reports together. The workflow finishes with a reusable audit package you can carry into the next model revision.

Define the Door Data Checks Before Asking Claude to Code

Start with a short checking brief for Office_QA.pln, the working copy used in this example. Use its native Door elements as the initial audit scope, and require a unique, nonblank Element ID within that set. If your delivery covers only certain doors, define that subset before checking uniqueness and record what you excluded.

An Element ID such as D-101 is the readable label used in schedules. Archicad also maintains a separate, automatically generated unique identifier. Duplicating elements can preserve their readable IDs, so the report should retain each door’s GUID alongside its Element ID to distinguish conflicting entries.

Give Claude Code these specific rules:

Check

Report a finding when

Element ID completeness

The readable ID is empty or contains only whitespace.

Element ID uniqueness

Multiple doors in the audit scope share the same ID.

Classification

A door has no assignment in the chosen classification system, or its assignment falls outside the project’s approved door classes.

Required rating data

A door identified by the coordinator as requiring a fire-rating value has no defined value, or its value falls outside the project-approved set.

For the rating check, the coordinator identifies the required doors and approves their accepted values. The selection-export step below collects their native GUIDs for rules.json.

Keep property availability separate from completeness: availability depends on classification. An unavailable property needs its own finding when the rule requires it.

Archicad property availability dialog with the Door and Window classification branches checked.

Source: Graphisoft

Save these decisions in rules.json. Keep the first audit read-only, producing findings for review before any model correction.

Prepare Archicad, Python, and Claude Code on Vagon

Open your Vagon Windows desktop and check the operating system before installing Archicad. Graphisoft’s current requirements list Windows 11 as supported for Archicad 30. If your cloud computer uses a Windows Server image, confirm the configuration with Vagon and Graphisoft before proceeding. Claude Code’s support for that OS does not establish Archicad compatibility. This documentation-based setup needs validation on the chosen machine, including activation and a successful model-data read.

Install the Archicad version used by your project, complete its license activation, and open Office_QA.pln. Check that its libraries load and that you can inspect door properties. Commercial Archicad use requires an appropriate license; arrange your Claude Code access separately. Keep a record of the Archicad version and build so the script can target the correct API.

Choose enough memory for the actual model and its libraries. The first practical requirement is opening and reviewing the project comfortably. Increasing GPU capacity is not a demonstrated shortcut for this property-checking task.

Install Python for Windows, then confirm that python --version works in PowerShell. Create a dedicated audit folder and virtual environment. These commands use the Graphisoft package version listed for the Archicad 30 example:

New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\Documents\ArchicadQA"
Set-Location "$env:USERPROFILE\Documents\ArchicadQA"
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install archicad==30.3000
.\.venv\Scripts\python.exe -m pip show archicad
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\Documents\ArchicadQA"
Set-Location "$env:USERPROFILE\Documents\ArchicadQA"
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install archicad==30.3000
.\.venv\Scripts\python.exe -m pip show archicad
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\Documents\ArchicadQA"
Set-Location "$env:USERPROFILE\Documents\ArchicadQA"
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install archicad==30.3000
.\.venv\Scripts\python.exe -m pip show archicad

For a different Archicad release, consult the package’s release documentation before choosing its version. Use the virtual environment’s Python executable for subsequent commands so installation and execution use the same interpreter.

Install Claude Code using Anthropic’s native Windows instructions:

irm https://claude.ai/install.ps1 | iex
irm https://claude.ai/install.ps1 | iex
irm https://claude.ai/install.ps1 | iex

Reopen PowerShell, return to the audit folder, and run claude --version, then claude to sign in. Native Windows can use PowerShell for shell commands; Git for Windows adds Git Bash when needed.

Place rules.json in this folder and create an outputs subfolder for reports. Keep the model in a known project location with its required libraries.

Connect Python to the Intended Archicad Session

For the first connection check, leave only the intended Archicad instance running, with Office_QA.pln open. Confirm the project name and revision in the application, switch to a floor plan, and select one known native door. This gives you an application-side reference to compare with the API response.

A selected native door in an Archicad floor plan beside Door Selection Settings and the door library browser.

Source: Graphisoft Support

The Archicad connection object exposes the connected application’s version, build, and language. Those details identify the application environment; confirm the document separately. Record the project label as information you verified in Archicad, rather than presenting it as a filename returned by this connection check.

Save the following as verify_connection.py in the audit folder:

from archicad import ACConnection

conn = ACConnection.connect()
if conn is None:
    raise SystemExit("No Archicad connection. Open the intended project and retry.")

acc = conn.commands
doors = acc.GetElementsByType("Door")
if not doors:
    raise SystemExit("No native doors returned. Check the project and audit scope.")

door_guids = {str(item.elementId.guid).lower() for item in doors}
selected = acc.GetSelectedElements()
if len(selected) != 1:
    raise SystemExit("Select exactly one known native door in the floor plan.")

selected_guid = str(selected[0].elementId.guid).lower()
if selected_guid not in door_guids:
    raise SystemExit("The selected element is not in the returned Door inventory.")

print(f"Archicad {conn.version}, build {conn.build}, language {conn.lang}")
print(f"Connected port: {conn.port}")
print(f"Candidate doors: {len(doors)}")
print(f"Selected door GUID: {selected_guid}")
from archicad import ACConnection

conn = ACConnection.connect()
if conn is None:
    raise SystemExit("No Archicad connection. Open the intended project and retry.")

acc = conn.commands
doors = acc.GetElementsByType("Door")
if not doors:
    raise SystemExit("No native doors returned. Check the project and audit scope.")

door_guids = {str(item.elementId.guid).lower() for item in doors}
selected = acc.GetSelectedElements()
if len(selected) != 1:
    raise SystemExit("Select exactly one known native door in the floor plan.")

selected_guid = str(selected[0].elementId.guid).lower()
if selected_guid not in door_guids:
    raise SystemExit("The selected element is not in the returned Door inventory.")

print(f"Archicad {conn.version}, build {conn.build}, language {conn.lang}")
print(f"Connected port: {conn.port}")
print(f"Candidate doors: {len(doors)}")
print(f"Selected door GUID: {selected_guid}")
from archicad import ACConnection

conn = ACConnection.connect()
if conn is None:
    raise SystemExit("No Archicad connection. Open the intended project and retry.")

acc = conn.commands
doors = acc.GetElementsByType("Door")
if not doors:
    raise SystemExit("No native doors returned. Check the project and audit scope.")

door_guids = {str(item.elementId.guid).lower() for item in doors}
selected = acc.GetSelectedElements()
if len(selected) != 1:
    raise SystemExit("Select exactly one known native door in the floor plan.")

selected_guid = str(selected[0].elementId.guid).lower()
if selected_guid not in door_guids:
    raise SystemExit("The selected element is not in the returned Door inventory.")

print(f"Archicad {conn.version}, build {conn.build}, language {conn.lang}")
print(f"Connected port: {conn.port}")
print(f"Candidate doors: {len(doors)}")
print(f"Selected door GUID: {selected_guid}")

Run it from PowerShell in the same folder:

.\.venv\Scripts\python.exe .\verify_connection.py
.\.venv\Scripts\python.exe .\verify_connection.py
.\.venv\Scripts\python.exe .\verify_connection.py

The check should print application metadata, a candidate-door count, and the selected door’s GUID. It confirms that the selected element belongs to the returned inventory. Compare the count with the doors you expect in the working copy before applying any delivery-specific exclusions.

Resolve a connection failure, empty inventory, or selection mismatch at this stage before attempting property checks.

Run this Python process on the Vagon computer where Archicad is open. The standard JSON interface communicates over localhost; a Python terminal on your laptop would target that laptop’s environment. Once the check succeeds, retain the confirmed project/revision label, port, and application metadata for the audit’s run record. You can then resolve the properties attached to those door GUIDs.

Map the Project’s Classifications and Property States

With the connection verified, inspect the definitions in Office_QA.pln before comparing values. In Archicad, open Options > Property Manager and find the rating property your checking brief requires. Record its exact group, name, data type, and available options. A rating stored as an option set needs different handling from a free-text field.

Archicad Property Manager showing Fire Resistance Rating as an Option Set with an Undefined default.

Source: Graphisoft: Property Manager

To inspect the corresponding API inventory, append these lines to verify_connection.py and run it again:

import json

print("Classification systems:")
print(json.dumps([s.to_dict() for s in acc.GetAllClassificationSystems()], indent=2))
print("Property names:")
print(json.dumps([p.to_dict() for p in acc.GetAllPropertyNames()], indent=2))
import json

print("Classification systems:")
print(json.dumps([s.to_dict() for s in acc.GetAllClassificationSystems()], indent=2))
print("Property names:")
print(json.dumps([p.to_dict() for p in acc.GetAllPropertyNames()], indent=2))
import json

print("Classification systems:")
print(json.dumps([s.to_dict() for s in acc.GetAllClassificationSystems()], indent=2))
print("Property names:")
print(json.dumps([p.to_dict() for p in acc.GetAllPropertyNames()], indent=2))

Use the release-specific Python API to resolve the built-in Element ID through conn.utilities.GetBuiltInPropertyId("General_ElementID"). Resolve the project’s rating property through GetUserDefinedPropertyId(group_name, property_name), using the recorded names. Inspect its definition with GetDetailsOfProperties and preserve the returned identifier objects for subsequent calls.

Choose the classification system required by the project, including its version. Read its tree with GetAllClassificationsInSystem, identify the approved door items, and retrieve door assignments with GetClassificationsOfElements. Use the visible item id values from that tree for allowed_classification_codes, resolving them to item identifiers within the chosen system. A missing classificationItemId represents an unassigned item; distinguish it from an API error.

Archicad Classification Manager showing the classification tree and the selected system name and version.

Source: Graphisoft

Before processing every door, read properties for a few known examples. Keep the statuses defined by Graphisoft’s property-value schema intact:

  • normal: inspect the typed value. A whitespace-only string can still fail your completeness rule.

  • userUndefined: the value is deliberately Undefined. Flag it only where the project requires a defined value.

  • notAvailable: the property is unavailable for that element. Check the expected classification and property availability.

  • notEvaluated: evaluation did not produce a value. Mark the affected check incomplete.

Handle API errors separately and retain their messages. Do not convert every non-normal result into an empty string.

For an option set, map the returned enum identifier to its display label using the property definition’s possibleEnumValues. Compare against the coordinator-approved options; do not assume a label such as “1 hour” arrives as the number 60.

Archicad Options Setup listing fire-rating labels including 20 minutes, 30 minutes, 45 minutes and 1 hour.

Source: Graphisoft

Update rules.json with the selected system and approved classes, exact rating-property names, required-door GUIDs, and accepted values. If a definition cannot be resolved, stop and correct the mapping before interpreting door data.

Collect the Coordinator-Approved Door List

In the floor plan, select the doors that the coordinator has identified as requiring rating data. Confirm the selection against the checking brief, including doors hidden in other views or stories. Save this separate helper as export_required_doors.py; the single-door connection probe remains unchanged:

import json
from pathlib import Path
from archicad import ACConnection

conn = ACConnection.connect()
if conn is None:
    raise SystemExit("Open the intended Archicad project and retry.")
acc = conn.commands
selected = acc.GetSelectedElements()
if not selected:
    raise SystemExit("Select the coordinator-approved doors first.")

door_guids = {str(item.elementId.guid).lower()
              for item in acc.GetElementsByType("Door")}
if any(str(item.elementId.guid).lower() not in door_guids for item in selected):
    raise SystemExit("Selection contains an element outside the Door inventory.")

id_property = conn.utilities.GetBuiltInPropertyId("General_ElementID")
properties = [conn.types.PropertyIdArrayItem(id_property)]
results = acc.GetPropertyValuesOfElements(selected, properties)
if len(results) != len(selected):
    raise SystemExit("Selection/property response length mismatch.")

rows = []
for element, result in zip(selected, results):
    data = result.to_dict()
    if "error" in data:
        raise SystemExit(f"Element read failed: {data['error']}")
    cells = data.get("propertyValues", [])
    if len(cells) != 1 or "error" in cells[0]:
        raise SystemExit(f"Element ID read failed: {data}")
    value = cells[0].get("propertyValue", {})
    status = value.get("status")
    if status not in {"normal", "userUndefined", "notAvailable", "notEvaluated"}:
        raise SystemExit(f"Unexpected Element ID state: {value}")
    if status == "normal" and not isinstance(value.get("value"), str):
        raise SystemExit(f"Expected a string Element ID: {value}")
    rows.append({"guid": str(element.elementId.guid).lower(),
                 "element_id": value.get("value") if status == "normal" else None,
                 "element_id_status": status})

with Path("required_doors.json").open("x", encoding="utf-8") as output:
    json.dump(rows, output, indent=2)
print(f"Exported {len(rows)} selected doors to required_doors.json")
import json
from pathlib import Path
from archicad import ACConnection

conn = ACConnection.connect()
if conn is None:
    raise SystemExit("Open the intended Archicad project and retry.")
acc = conn.commands
selected = acc.GetSelectedElements()
if not selected:
    raise SystemExit("Select the coordinator-approved doors first.")

door_guids = {str(item.elementId.guid).lower()
              for item in acc.GetElementsByType("Door")}
if any(str(item.elementId.guid).lower() not in door_guids for item in selected):
    raise SystemExit("Selection contains an element outside the Door inventory.")

id_property = conn.utilities.GetBuiltInPropertyId("General_ElementID")
properties = [conn.types.PropertyIdArrayItem(id_property)]
results = acc.GetPropertyValuesOfElements(selected, properties)
if len(results) != len(selected):
    raise SystemExit("Selection/property response length mismatch.")

rows = []
for element, result in zip(selected, results):
    data = result.to_dict()
    if "error" in data:
        raise SystemExit(f"Element read failed: {data['error']}")
    cells = data.get("propertyValues", [])
    if len(cells) != 1 or "error" in cells[0]:
        raise SystemExit(f"Element ID read failed: {data}")
    value = cells[0].get("propertyValue", {})
    status = value.get("status")
    if status not in {"normal", "userUndefined", "notAvailable", "notEvaluated"}:
        raise SystemExit(f"Unexpected Element ID state: {value}")
    if status == "normal" and not isinstance(value.get("value"), str):
        raise SystemExit(f"Expected a string Element ID: {value}")
    rows.append({"guid": str(element.elementId.guid).lower(),
                 "element_id": value.get("value") if status == "normal" else None,
                 "element_id_status": status})

with Path("required_doors.json").open("x", encoding="utf-8") as output:
    json.dump(rows, output, indent=2)
print(f"Exported {len(rows)} selected doors to required_doors.json")
import json
from pathlib import Path
from archicad import ACConnection

conn = ACConnection.connect()
if conn is None:
    raise SystemExit("Open the intended Archicad project and retry.")
acc = conn.commands
selected = acc.GetSelectedElements()
if not selected:
    raise SystemExit("Select the coordinator-approved doors first.")

door_guids = {str(item.elementId.guid).lower()
              for item in acc.GetElementsByType("Door")}
if any(str(item.elementId.guid).lower() not in door_guids for item in selected):
    raise SystemExit("Selection contains an element outside the Door inventory.")

id_property = conn.utilities.GetBuiltInPropertyId("General_ElementID")
properties = [conn.types.PropertyIdArrayItem(id_property)]
results = acc.GetPropertyValuesOfElements(selected, properties)
if len(results) != len(selected):
    raise SystemExit("Selection/property response length mismatch.")

rows = []
for element, result in zip(selected, results):
    data = result.to_dict()
    if "error" in data:
        raise SystemExit(f"Element read failed: {data['error']}")
    cells = data.get("propertyValues", [])
    if len(cells) != 1 or "error" in cells[0]:
        raise SystemExit(f"Element ID read failed: {data}")
    value = cells[0].get("propertyValue", {})
    status = value.get("status")
    if status not in {"normal", "userUndefined", "notAvailable", "notEvaluated"}:
        raise SystemExit(f"Unexpected Element ID state: {value}")
    if status == "normal" and not isinstance(value.get("value"), str):
        raise SystemExit(f"Expected a string Element ID: {value}")
    rows.append({"guid": str(element.elementId.guid).lower(),
                 "element_id": value.get("value") if status == "normal" else None,
                 "element_id_status": status})

with Path("required_doors.json").open("x", encoding="utf-8") as output:
    json.dump(rows, output, indent=2)
print(f"Exported {len(rows)} selected doors to required_doors.json")

Run it in the audit folder with .\.venv\Scripts\python.exe .\export_required_doors.py. It creates required_doors.json only after reading the complete selection. Move an earlier export aside before rerunning; exclusive file creation protects the existing list.

An illustrative row has this shape; it is not a captured project result:

{
  "guid": "12345678-1234-5678-1234-567812345678",
  "element_id": "D-101",
  "element_id_status": "normal"
}
{
  "guid": "12345678-1234-5678-1234-567812345678",
  "element_id": "D-101",
  "element_id_status": "normal"
}
{
  "guid": "12345678-1234-5678-1234-567812345678",
  "element_id": "D-101",
  "element_id_status": "normal"
}

Review every exported row against the coordinator’s selection. A null readable ID remains identifiable by GUID, while its status explains why no text was exported. Copy the approved rows’ guid values into rating_required_guids. The helper records selection, not proof that the selection includes every door the project requires.

Have Claude Code Build a Read-Only Door Audit

Now give Claude Code the checking brief, the verified API version, and the property mappings. Ask it to create one complete audit_doors.py with separate functions for extracting data, evaluating rules, and writing reports. That separation lets you test the rule logic with small fixtures before connecting it to the model.

Use a configuration with explicit fields. Adapt this rules.json template using the definitions you inspected; replace every angle-bracket placeholder and use the actual door GUIDs supplied by the coordinator:

{
  "project_label": "Office_QA.pln",
  "revision_label": "<confirmed model revision>",
  "scope": "all_native_doors",
  "classification_system_name": "<exact system name>",
  "classification_system_version": "<exact system version>",
  "allowed_classification_codes": ["<approved door class code>"],
  "rating_property_group": "<exact property group>",
  "rating_property_name": "<exact property name>",
  "rating_value_type": "singleEnum",
  "rating_required_guids": ["<native door GUID>"],
  "rating_allowed_values": ["<project-approved option label>"]
}
{
  "project_label": "Office_QA.pln",
  "revision_label": "<confirmed model revision>",
  "scope": "all_native_doors",
  "classification_system_name": "<exact system name>",
  "classification_system_version": "<exact system version>",
  "allowed_classification_codes": ["<approved door class code>"],
  "rating_property_group": "<exact property group>",
  "rating_property_name": "<exact property name>",
  "rating_value_type": "singleEnum",
  "rating_required_guids": ["<native door GUID>"],
  "rating_allowed_values": ["<project-approved option label>"]
}
{
  "project_label": "Office_QA.pln",
  "revision_label": "<confirmed model revision>",
  "scope": "all_native_doors",
  "classification_system_name": "<exact system name>",
  "classification_system_version": "<exact system version>",
  "allowed_classification_codes": ["<approved door class code>"],
  "rating_property_group": "<exact property group>",
  "rating_property_name": "<exact property name>",
  "rating_value_type": "singleEnum",
  "rating_required_guids": ["<native door GUID>"],
  "rating_allowed_values": ["<project-approved option label>"]
}

The singleEnum setting describes an option-set example. If your inspected property is a string, use string and specify the accepted text values. Require the script to check that the configured type matches the actual definition. Unknown class codes, ambiguous system matches, and required-door GUIDs absent from the scope should stop the run with an explanation.

Official Claude Code v2.0 terminal interface example showing the welcome panel, recent activity and prompt input.

Source: Anthropic

Start Claude Code in the audit folder and give it this task:

Create audit_doors.py for the installed Graphisoft archicad package.
Read rules.json and verify all mappings before auditing native Door elements.
Support: --config rules.json --output-root outputs.

Use only read operations against Archicad. Do not save or modify the model.
Reuse the connection checks from verify_connection.py without importing its
inventory-printing code. Keep project/revision labels explicitly user-confirmed.
Reject unresolved placeholders, invalid configuration and an empty scope.
Resolve class codes to item identifiers in the exact system name/version.
A missing classificationItemId is a finding; API errors make the check incomplete.
Normalize GUID text with str(...).lower() while retaining API identifier objects.

Check nonblank IDs, scoped duplicate IDs, approved classification assignments,
and required rating data. Preserve API statuses and per-item errors.
Use exact case-sensitive ID comparisons after trimming surrounding whitespace.
Resolve enum labels from property definitions before comparing allowed values.
Preserve request/result ordering and verify response dimensions.

Create a unique run directory before preflight. Always write issues.csv,
report.md and run.json for handled preflight/extraction failures as well as success.
If the output directory cannot be created, exit 2 with a clear terminal diagnostic
stating that no report was written; never point readers to an older run.

CSV fields: guid, element_id, rule_id, observed_state, observed_value, reason.
Emit a row for each door in a duplicate-ID group.
Manifest: user-confirmed project/revision labels; UTC timestamp; Archicad version,
build and language; Python/package versions; SHA-256 of script and configuration;
configured scope; candidate count; unique affected-door count; and coverage counts.
For each rule, report evaluated, not-applicable and failed-read counts. Define
these as disjoint counts accounting for every candidate. Record zero coverage
when preflight prevents evaluation, with a separate preflight failure reason.

Distinguish complete_pass, complete_with_findings and incomplete outcomes.
Exit 0, 1 and 2 respectively. Incomplete takes precedence over findings.
Write failure diagnostics in report.md/run.json, including errors without a GUID.
Test the evaluator with synthetic fixtures before proposing a live read

Create audit_doors.py for the installed Graphisoft archicad package.
Read rules.json and verify all mappings before auditing native Door elements.
Support: --config rules.json --output-root outputs.

Use only read operations against Archicad. Do not save or modify the model.
Reuse the connection checks from verify_connection.py without importing its
inventory-printing code. Keep project/revision labels explicitly user-confirmed.
Reject unresolved placeholders, invalid configuration and an empty scope.
Resolve class codes to item identifiers in the exact system name/version.
A missing classificationItemId is a finding; API errors make the check incomplete.
Normalize GUID text with str(...).lower() while retaining API identifier objects.

Check nonblank IDs, scoped duplicate IDs, approved classification assignments,
and required rating data. Preserve API statuses and per-item errors.
Use exact case-sensitive ID comparisons after trimming surrounding whitespace.
Resolve enum labels from property definitions before comparing allowed values.
Preserve request/result ordering and verify response dimensions.

Create a unique run directory before preflight. Always write issues.csv,
report.md and run.json for handled preflight/extraction failures as well as success.
If the output directory cannot be created, exit 2 with a clear terminal diagnostic
stating that no report was written; never point readers to an older run.

CSV fields: guid, element_id, rule_id, observed_state, observed_value, reason.
Emit a row for each door in a duplicate-ID group.
Manifest: user-confirmed project/revision labels; UTC timestamp; Archicad version,
build and language; Python/package versions; SHA-256 of script and configuration;
configured scope; candidate count; unique affected-door count; and coverage counts.
For each rule, report evaluated, not-applicable and failed-read counts. Define
these as disjoint counts accounting for every candidate. Record zero coverage
when preflight prevents evaluation, with a separate preflight failure reason.

Distinguish complete_pass, complete_with_findings and incomplete outcomes.
Exit 0, 1 and 2 respectively. Incomplete takes precedence over findings.
Write failure diagnostics in report.md/run.json, including errors without a GUID.
Test the evaluator with synthetic fixtures before proposing a live read

Create audit_doors.py for the installed Graphisoft archicad package.
Read rules.json and verify all mappings before auditing native Door elements.
Support: --config rules.json --output-root outputs.

Use only read operations against Archicad. Do not save or modify the model.
Reuse the connection checks from verify_connection.py without importing its
inventory-printing code. Keep project/revision labels explicitly user-confirmed.
Reject unresolved placeholders, invalid configuration and an empty scope.
Resolve class codes to item identifiers in the exact system name/version.
A missing classificationItemId is a finding; API errors make the check incomplete.
Normalize GUID text with str(...).lower() while retaining API identifier objects.

Check nonblank IDs, scoped duplicate IDs, approved classification assignments,
and required rating data. Preserve API statuses and per-item errors.
Use exact case-sensitive ID comparisons after trimming surrounding whitespace.
Resolve enum labels from property definitions before comparing allowed values.
Preserve request/result ordering and verify response dimensions.

Create a unique run directory before preflight. Always write issues.csv,
report.md and run.json for handled preflight/extraction failures as well as success.
If the output directory cannot be created, exit 2 with a clear terminal diagnostic
stating that no report was written; never point readers to an older run.

CSV fields: guid, element_id, rule_id, observed_state, observed_value, reason.
Emit a row for each door in a duplicate-ID group.
Manifest: user-confirmed project/revision labels; UTC timestamp; Archicad version,
build and language; Python/package versions; SHA-256 of script and configuration;
configured scope; candidate count; unique affected-door count; and coverage counts.
For each rule, report evaluated, not-applicable and failed-read counts. Define
these as disjoint counts accounting for every candidate. Record zero coverage
when preflight prevents evaluation, with a separate preflight failure reason.

Distinguish complete_pass, complete_with_findings and incomplete outcomes.
Exit 0, 1 and 2 respectively. Incomplete takes precedence over findings.
Write failure diagnostics in report.md/run.json, including errors without a GUID.
Test the evaluator with synthetic fixtures before proposing a live read

Have Python evaluate the bulk model data locally. Give Claude the schema and the examples needed to develop the tool; you do not need to paste the full property export into the conversation.

Review the extraction function against the documented property-reading commands. Keep each requested GUID paired with its returned values. Sorting or filtering one list independently can attach a finding to the wrong door.

Check the generated output writer against the prompt’s field list. The manifest must distinguish unique affected doors from finding rows and explain any coverage gap. Keep failures that have no element GUID in the run diagnostics.

Before the first live run, inspect fixture results for a valid door, duplicate IDs, required Undefined data, an unavailable property, and an API error. Check that a failed read produces an incomplete outcome. Passing these fixtures verifies the evaluator’s behavior; application-side review still follows.

After inspecting the generated script and its proposed commands, run:

.\.venv\Scripts\python.exe .\audit_doors.py --config .\rules.json --output-root .\outputs
.\.venv\Scripts\python.exe .\audit_doors.py --config .\rules.json --output-root .\outputs
.\.venv\Scripts\python.exe .\audit_doors.py --config .\rules.json --output-root .\outputs

Open the run folder named by the command and check its outcome and diagnostics. If directory creation failed, resolve the terminal error before retrying.

Check the Report Against Doors in Archicad

Begin with run.json and report.md. Confirm that the project/revision labels, timestamp, application build, and configuration hash belong to the run you intend to review. Keep Office_QA.pln unchanged during this comparison so edits do not make the report stale.

Reconcile coverage before investigating individual findings. With scope set to all_native_doors, every returned candidate needs an accounted-for result. Check each rule’s evaluated, not-applicable, and failed-read counts. The rating rule applies only to its configured GUID list; ID and classification checks cover the full scope. One door can generate several findings, so CSV row count is not a door count.

Choose a reported door with a readable ID. Use Edit > Find & Select with an Element ID criterion to locate matching candidates. Select one door at a time on the floor plan and rerun verify_connection.py. Compare its selected GUID with the CSV row before inspecting the door’s classification and properties.

Archicad Find and Select criterion chooser with Element ID highlighted under ID and Categories.

Source: Graphisoft Support

For duplicate or blank IDs, use candidate doors in the plan or door schedule to narrow the search, then confirm identity through the selected GUID. Preserve that GUID when recording your review. An IFC GlobalId should not be substituted for the native identifier used by this audit.

Inspect a small set that exercises different paths:

  • A duplicate-ID finding: confirm that distinct GUIDs share the reported readable ID.

  • A required-rating finding: confirm both the door’s inclusion in the required list and its observed property value.

  • An unavailable-property finding: inspect classification and the property’s availability definition.

  • A door without findings: independently check its ID, classification, and any applicable rating requirement.

Record disagreements with their causes. A wrong property mapping needs a script or configuration correction; a genuine missing value needs a model correction. Resolve extraction and mapping defects, regenerate the report, and establish a reviewed baseline before testing a deliberate model change.

Archicad Find and Select property comparison menu showing available, not available, is undefined and is not undefined filters.

Source: Graphisoft

Correct One Finding and Rerun the Same Rules

Choose one confirmed issue with an unambiguous correction. For example, use a door on the required-rating list whose property is Undefined, provided the coordinator has supplied its approved value. Record the door’s GUID, the failing rule, and the value you expect to see after correction.

Preserve the baseline run folder. For this controlled test, keep audit_doors.py and rules.json unchanged, and record the correction and saved model copies in a separate review note. That makes the model edit the intended difference between runs.

Select the identified door in Archicad and change only the relevant property to the approved value. Save Office_QA.pln, reopen it, and inspect that door again to confirm the correction persisted. Select the known door on the floor plan and rerun the connection check before starting the audit.

Archicad Wall List schedule with the Fire Resistance Rating dropdown open, showing rating options and Undefined.

Source: Graphisoft

Use the same command as before:

.\.venv\Scripts\python.exe .\audit_doors.py --config .\rules.json --output-root .\outputs
$LASTEXITCODE
.\.venv\Scripts\python.exe .\audit_doors.py --config .\rules.json --output-root .\outputs
$LASTEXITCODE
.\.venv\Scripts\python.exe .\audit_doors.py --config .\rules.json --output-root .\outputs
$LASTEXITCODE

Compare the new run with the baseline using (guid, rule_id) as the finding key. Confirm that:

  • The corrected door retains its GUID and its required-rating finding disappears.

  • The candidate inventory, rating-required list, and rule coverage remain consistent.

  • Unrelated findings remain explainable, and no new extraction failures appear.

  • The configuration hash matches and the script has not changed.

The overall outcome can remain complete_with_findings if other doors still fail. For an incomplete run, resolve the recorded failure before comparing improvements.

If several findings disappear unexpectedly, inspect scope and coverage before accepting the improvement. Deleting a door, dropping unreadable rows, or changing a filter can reduce the issue count without fixing the underlying data.

Keep both reports with the correction note. This gives the coordinator a traceable example of a model change that survives saving and produces the expected response from the audit.

Save a Reusable Audit Package for the Next Model Revision

Keep the audit in a project folder that another coordinator can understand without reopening the Claude conversation. Preserve these files together:

  • audit_doors.py, verify_connection.py, and export_required_doors.py, with the evaluator fixtures and their expected results.

  • rules.json and the reviewed required_doors.json, including the approved classification and rating requirements.

  • requirements.txt recording the installed Python dependencies, plus the Python version in a short README.md.

  • The reviewed run folders and correction note, each linked to the corresponding saved model snapshot.

In the README, record the run command, the meaning of each exit status, the Archicad version/build used, and any unresolved findings. Reference the project’s required libraries and model location so the recipient can restore the application context.

For the next model revision, preserve the previous configuration before updating revision_label and the coordinator-approved required-door list. Recheck property definitions and classification mappings when the template changes. A replacement door may need a new entry in the required list, even if its readable ID matches an earlier door.

Create a fresh run folder and review changes against the previous accepted baseline. Treat rule changes separately from model improvements: document what changed in the configuration and why. This keeps the reusable tool connected to the project’s current requirements while preserving the evidence behind earlier reports.

FAQs

Do I need an MCP server to use Claude Code with Archicad?

No. This workflow uses Python scripts and Graphisoft’s official JSON interface. An MCP server is an additional integration choice; it is unnecessary for running the bounded data audit described here.

Can Claude Code check a PLN file without opening Archicad?

The method in this guide reads the model through a running Archicad instance. Giving Claude Code a PLN path does not establish structured model access. Open the intended project before running the connection check.

Does this audit validate IFC exports or detect clashes?

It checks the configured data on native Door elements. IFC export validation requires examining the exported file and its mappings; clash detection requires geometric checks. A passing report establishes only that the implemented data rules completed without findings.

Can the script automatically repair the reported properties?

Graphisoft’s API includes property-writing commands, but the audit specified here uses read operations. Adding repairs requires a separate change plan, appropriate project access, and verification of the saved result. The coordinator must supply the intended values.

Are Archicad and Claude Code access included with Vagon?

Arrange Archicad licensing and Claude Code access separately from the cloud computer. Vagon’s Claude Code setup uses your own Claude access. Confirm Archicad activation and the chosen machine’s operating-system compatibility before starting the audit.

Will the example work with an older Archicad version?

Target the installed release and check the Python package’s release documentation. Commands, arguments, and available properties can differ. Recheck the connection and property mappings, then validate the generated script against a small working copy before relying on its reports.

Vagon Computer

Run it on a cloud computer

Open it from any browser, Mac, iPad or Chromebook. No local hardware needed.

Vagon Computer

Run it on a cloud computer

Open it from any browser, Mac, iPad or Chromebook. No local hardware needed.

Written by

Mert Boz

Mert is a philosophy student with a strong interest in economics, motorsports, and basketball. He enjoys thinking about how the world works, both in theory and in real life. In his free time, you can often find him watching a race, following a basketball game, or reading about economic ideas.

More posts by this writer →

Vagon Computer

Run this guide on a cloud computer.

Open it from any browser, Mac, iPad or Chromebook. No local hardware needed.

Vagon Computer

Run this guide on a cloud computer.

Open it from any browser, Mac, iPad or Chromebook. No local hardware needed.