Revit Connector
The seam between Autodesk Revit and the BuildPlan platform — the installable add-in that classifies a model, colours it, writes classifications back, surveys and measures duplicate parameters, and exports a contract artifact for the cloud.
Why it sits at catalog top level, and is not called revit-desktop
It is the machinery several domains reach Revit through — design-management, bim-ontology
and construction-management all meet a customer’s model here — so by this catalog’s own rule it
stays at the top rather than nesting under one of them:
System — Nest under a domain when that domain owns the capability. Keep at catalog top level when the grouping is machinery that spans domains.
backend-platform is the precedent and says the same of itself: “catalog top-level because api-v1
is not owned by a single domain. It is the HTTP machinery other domains call.”
🔴 THE OLD BLOCKER WAS A MIS-FRAMED QUESTION, NOT AN OPEN ONE. These pages were held back for two days on “which platform domain owns the desktop add-in?” — a question with no answer, because a System need not sit inside a domain at all. The rule above was already written in
eventcatalog/CONVENTIONS.md, in the same document the handoff quoted.And the name went with it.
revit-desktopdescribes where it runs;revit-connectordescribes what it does, which is the thing several domains depend on.
What this is
One installable today, two codebases. The add-in ships as a single Revit add-in: a C# host that
owns everything touching the Revit API, and a React panel that runs in an embedded WebView2 and
compiles into assets/ inside the same binary.
It is a System with two Services and not one Service, and the distinction is load-bearing. The System is what says these ship as one binary — nobody should read the two services as a network boundary. But the bridge between them is a real contract between two independently-authored codebases with independently-run test suites, and it has already shipped a defect a contract would have caught: a refusal built as a second object literal, missing keys the panel read.
The cloud half of this seam is built, and is not a third service here
A connector has two ends. The desktop end is here. The end that ingests the export artifact
is Project Delivery Graph on api-v1 — Ingest Revit
Export (requestRevitImportUploadUrl → PUT artifact →
registerRevitImport → processRevitImport or cron → rematerialize → import-run log).
RevitContractExporter produces a contract-v1 JSONL artifact delivered through object storage
(this repository’s ADR-43, backend ADR-0071). api-v1 already reads it. That HTTP surface is
not added as a third services: entry on this System: it is the same seam, but the deployable
is already api-v1, and inventing a box here would render as a missing
service.
This index.mdx is carried from bp_revit_extension by eventcatalog/scripts/sync-revit-plugin.mjs.
A later plugin sync will overwrite a local-only edit. Update the plugin catalog copy when that
checkout is present.
🔴 project-delivery-graph is NOT part of this System, and that is a decision. It is a
cataloged domain — the project delivery graph and the project definition graph — and backend
ADR-0069 makes it a top-level module in its own right.
The connector owns the SEAM: transport, translation, and the anti-corruption edge. The graph domain owns the MODEL the data lands in. Folding the graph into this System would make the connector responsible for what the platform does with what it carries.
The two halves, and the line between them
revit-addin | the C# host. Owns the Revit seam, the classifier, the parameter engine and every command handler |
revit-panel | the React UI. Owns what a person sees and every decision they make |
| between them | 25 wire names — commands, queries and one pushed event. Generated into bridge-messages.json from the C# constants |
The dependency points inward. Revit knows about the classifier and the parameter engine; neither of them learns Revit exists. Two things rest on that: almost everything is testable with Revit closed, and the add-in may hand long work off the Revit API thread, because the snapshots it passes hold no Revit objects.
What it can do
- Classify a model into BuildPlan Object Classes, and colour it by the result.
- Write back an accepted classification into the model — as a shared parameter and an extensible storage stamp — and defend it with an updater that reverts a hand edit.
- Survey every duplicate parameter, work out where each lives and what removing it would cost, validate a reviewer’s decisions, and measure what carrying them out would cost.
🔴 What it deliberately CANNOT do
It cannot perform a parameter migration. The write half of that engine was deliberately not
ported: there is no apply command in any form, and a test asserts the absence over every wire name.
The dry run’s own response carries canApply: false and a sentence saying why, because a person
looking at a dry run beside no apply button cannot otherwise tell a missing feature from an
unfinished one.
The apply is still run from a bench session against the skill, exactly as it was before.
Costs a person will notice
🔴 Two different buildings, because the two halves were measured on two different models — and saying “a real building” for both would size a reader’s expectations against a model the number was never taken on.
| measured on | ||
|---|---|---|
| classify | a 53,800-node building | ~1.5 s of classification on top of extraction |
| survey the parameters | a 734-type, 142-instance, 116-category building | ~28 s, all of it holding Revit’s main loop — and there is no Stop |
| map, dry run, diff | the same small building | 6 ms, 254 ms and 242 ms |
⚠️ The survey’s 28 seconds is the SMALL model’s number, and it will not scale flat. Most of that time goes into opening unplaced families one at a time — 316 of them here — so a building with more families on the shelf is slower, not merely bigger. Nobody has measured it on the 53,800-node model.
The survey freezes Revit for half a minute — on a small model — with no way to abort. The classifier raises an escape window during its long run; the parameter commands take neither the cancellation source nor the escape window, and nothing inside the survey reader checks a token — so there is nothing to trip even if a window were raised. Do not present a Stop button over it.
Entities it consumes
Every one belongs to bim-ontology and is referenced, never redefined:
ObjectClass · ParameterKey · RevitParameterProjection.
They are declared on the revit-addin service, which is what actually consumes them, and a test
asserts this list and that one are the same set — an earlier draft named two more here that the
service did not declare, one of which appears nowhere in this repository at all.
Decisions
The reasoning lives in this repository’s docs/ADR.md and is linked rather than restated. The ones
that shape this System most: ADR-4 (all UI-originated Revit work goes through one external-event
dispatcher), ADR-11 (work needing no Revit API is answered beside it), ADR-31 (the parameter
commands’ thread split, and where decisions live), ADR-34 (the connector boundary) and ADR-42
(the engine’s ontology ships as its own asset).