# Working across disciplines

For teams in which architects, structural engineers and building services engineers (HVAC, plumbing, electrical) work on one building in OpenEik: where each discipline's records are, what they name of each other's, how separate lines of work merge, and what a discipline can take out or add without breaking the others. This guide is informative: the specification wins wherever the two differ. Every result quoted here was run with `@openeik/tools` on a copy of [`examples/l-house`](https://gitlab.com/openeik/spec/-/tree/main/examples/l-house), with an HVAC and drainage set added to it, in the folders of OpenEik 0.1: in the owners' layout of 0.2 the same records are under `ventilation/` and `plumbing/` where 0.1 has `systems/` (section 1).

## 1. One building, one model

A building is one model: one folder, one file for each record (Part III). Each discipline has a top folder of its own, the discipline that owns a record (Part III, 4.4), and every discipline shares the project's folder.

| Folder | Holds | Who places it |
|---|---|---|
| `project/` | the project record (its id, millimetres and Z up, and its zero above a shared datum), the levels, the grids, the materials | everyone shares it |
| `architecture/` | walls, slabs and roofs that bear nothing, ceilings, doors, windows, rooms, stairs that carry nothing, railings, furniture, fire equipment | the architect |
| `structure/` | beams, columns, foundations, slab edges, rebar, mesh, structural plates and connectors, and walls, slabs, roofs and stairs that bear, with their types | the structural engineer |
| `ventilation/` | ducts and air devices | the ventilation engineer |
| `plumbing/` | pipes and every other terminal | the heating and plumbing engineer |
| `electrical/` | electrical devices, cable carriers and cables (Part XIII) | the electrical engineer |
| `sprinkler/` | what a record's `owner` gives it | the sprinkler engineer |
| `site/` | terrain, grading, property lines, planting, roads, parking | the landscape or civil engineer |
| `types/<discipline>/` | the types, in the same discipline folders | as their elements |
| `drawings/<discipline>/` | views and sheets, `setup/` for a view that names no owner | as their records |

A folder of OpenEik 0.1 has four of these, by category: `architecture/`, `structure/`, `systems/` for pipes, ducts and terminals, and `site/` (Part III, 4.1). A reader of 0.2 reads both layouts, and a building moves to the owners' layout once, in the version that migrates it to 0.2 (`openeik migrate`, Part I, 9.8). That version holds the migration alone, the moves and the rewrites of Part I, 9.8 (Part III, 4.4, rule 8): an edit the building needs to pass the checks of 0.2 goes into a version of 0.1 before it, and the change the person was making into a version after it, so that each diff shows one thing.

An element's path is `<discipline>/<level>/<category>/<id>.json`, worked out from the record (Part III, 4.2): the HVAC supply duct of the example is `ventilation/level-0/duct/duct-hall-supply.json`, `systems/level-0/duct/duct-hall-supply.json` in 0.1.

- **The folder follows the owner.** One set of rules gives a record's owner (Part III, 4.4): a wall made `structural` moves to `structure/`, and its type with it; an `owner` set by hand wins over every rule. Some categories land where you might not expect: fire equipment such as detectors and sprinkler valves is in `architecture/` unless its `owner` says `sprinkler`. In 0.1 the folder follows the category: a bearing wall stays in `architecture/`. A component goes in `structure/` when it is structural, a plate, a cast-in item or a connector. A generic element, a lift for example, names its folder in `generic.discipline` (Part III, 4.1).
- **No meaning comes from a folder.** A reader takes a record for what it says (Part III, 4.1, rule 4).
- **A tool that does not handle a discipline keeps it.** A reader that does not implement a profile, the systems profile for example, keeps its records unchanged when it writes the model back (Part II, 8, rule 1). A tool that knows nothing of ducts does not lose them.

The **datums** are what every discipline works to: the project record, whose frame, units and zero every coordinate of the model is in; the levels, each a named horizontal datum; and the grids. Two lines of work that keep the same datums, with the same ids, merge; two that do not, do not (section 3).

## 2. What each discipline's records name

Part II, 7 lists every member that names another element. Read by discipline:

- **Building services name very little.** A pipe, a duct or a terminal names its level (`levelId`) and its type (`typeId`); a run also names the terminal each of its ends joins (`mep.joins.start.terminalId`, `mep.joins.end.terminalId`). It names no wall, slab, beam or room. A run is its points in plan and a height for each above its level (Part IV, 12): it is placed by coordinates, not attached to anything.
- **Architecture and structure name each other a great deal.** A slab edge is hosted by a slab or a foundation, rebar by those or by a beam, a column or a slab edge, and mesh by a slab, a foundation or a wall; a wall's top attaches to a roof, a floor, a ceiling or a foundation; a column's base attaches to its host; framing members and trusses are made from walls and roofs; member ends join other members and plates. Most of these references must resolve, and the check refuses a model where they do not.
- **One exception, in the reference implementation:** a downpipe that Stomra makes from a gutter is hosted on that gutter (`hostId`), so it follows the gutter and is deleted with it (Part V, 5).
- **Electrical:** a wall device lies against its wall's face by its coordinates, and names no wall; circuits, feeds and switches name only electrical records (Part XIII).
- **Components in a pipe or a duct:** a valve, a pump or a meter in a pipe, and a damper, a silencer or a fan in a duct, is a terminal hosted on its run (`hostId`) at a distance along it, and follows it; it names its pipe or its duct and no element of another discipline (Part II, 6.9).

What follows from it:

- **A moved wall moves no duct.** The model holds no statement that a duct passes through a wall. Coordination is a check that a tool runs on the bodies (or on a supplier's declared geometry, Part II, 12.1), not a link kept in the model: `openeik clash` is one (section 3.4).
- **Holes belong to the host.** A slab's `voids`, a wall's `recesses` and a shaft are records of the architect or the structural engineer. Taking a duct away leaves its hole.
- **Systems come apart cleanly; architecture and structure do not.** In the tests, removing `systems/` and `types/systems/` from the merged L-house left a model with 0 errors and 0 warnings, and so did removing `architecture/` and `structure/`, which left the HVAC model alone. Removing `architecture/` alone gave 18 errors, one for each slab edge whose slab was gone.

## 3. Working together

Six rules of thumb follow from sections 1 and 2.

### 3.1 Share the datums

Start the building with its project, levels and grids, and give each discipline the same ones. `openeik datums` writes a building's datums into a new folder, and a discipline starts its own model from it:

```sh
$ openeik datums l-house datums
datums: the datums of l-house: project "roof-study", 2 levels, 0 grids; 5 files written
```

The datums are every discipline's: changing a level's id or elevation, or the project's origin, is a decision for everyone, not one discipline's edit. Levels merge as one list by id, and a conflict in them is settled for the whole list (Part VI, 5, rule 5). `openeik diff` and `openeik merge` name a change to the datums. In the tests, an HVAC model that replaced the building's levels with levels of its own could not merge: every element of the architect's lost its level, and the merge was refused with 130 errors, nothing written (Part VI, 5, rule 7).

### 3.2 One model, a line of work each

Each discipline works on a line of its own: a clone in its own store, a fork on a host, or an alternative (Part VI, 3 and 6). A merge goes by record and by field, never by text (Part VI, 5). Records match by id; a record changed on one side only is taken; a record both sides changed is merged field by field. A conflict comes only where both change the same field, where one changes what the other deleted, or where both add different records with one id. So two disciplines that write in their own folders do not conflict, and merging often keeps it so.

A model that a discipline built on its own merges into the building with the datums as the base. The HVAC engineer started from `datums` above and added four types and five elements; the architect raised a wall meanwhile:

```sh
$ openeik check hvac
hvac: 14 files (1 agents, 1 eik, 5 element, 1 levels, 1 order, 1 project, 4 type); 0 errors, 0 warnings; 0 generic elements
$ openeik merge datums l-house-arch hvac --out merged
ours      architecture 67 added; drawings 13 added; structure 63 added; types/architecture 9 added; types/structure 9 added
theirs    systems 5 added; types/systems 4 added
170 changes merged (161 from ours, 9 from theirs, 0 from both); 0 conflicts; the merged model: 0 errors, 0 warnings
wrote merged
```

`openeik merge` says which top folders each side changed against the base, and `openeik diff` which top folders a change touches:

```sh
$ openeik diff l-house-arch merged
…
10 record changes, 0 kept files
by folder: systems 5 added; types/systems 4 added
```

The order of the lists, `project/order.json`, is an index and not a record (Part III, 9), and the summary does not count it.

### 3.3 Write in your own folders

A line of work writes in its own discipline's folders. When the HVAC engineer needs a hole in a slab or a shaft, that is a change to the architect's or the structural engineer's record: offer it to them, in a proposal they accept (Part VI, 8.7), not as an edit of your own. The summaries above show it when a line of work strays: in the tests, an HVAC line that also cut a void into the architect's slab showed up as `architecture 1 changed` on its side of the merge, beside `systems 5 added; types/systems 4 added`.

In 0.2, ownership by folder is in the model ([Part XVI](https://openeik.org/spec/0.4/ownership), decided on 18 October 2026); in 0.1, which does not stop a writer from writing in another discipline's folder, the rule is kept by review. `project/owners.json` names the project's parties and the paths each owns, and a change to an owned path needs an owner's approval, every owner's for the datums, before a host lets it join the main line. A party may say its discipline and the organisation it is, by a domain of its own (decided on 25 October 2026); a host links an organisation's accounts to a party only once the organisation has proved that domain and the building is shared with it or its administrator accepts. `openeik check` checks the file, `openeik owners <folder> <path>` names the owners of a path, and `openeik diff` and `openeik merge` say which parties a change needs: in the tests, the HVAC line's void in the slab needs the architect's approval, and its ducts its own.

### 3.4 Place building services by coordinates, and check for clashes

Keep pipes, ducts and terminals on the shared levels, at coordinates in the project's frame, and find where they meet the architecture and the structure with a check, not with references. A clash check is a tool's, not a conformance class (Conformance, 1). `openeik clash` checks the pipes and ducts against the bodies that Part IV derives for the architecture and the structure. A run **passes through** an element where its axis enters it, and **grazes** it where only its side does; a run that only touches a face, within a tolerance of 1 mm (`--tolerance`), is no clash. Holes are their host's (section 2), and a run through a slab's void or a window's opening does not clash.

```sh
$ openeik clash merged
clash  pipe-wc-sewage  passes through slab study-slab (architecture, ground-eps) at [9814.4, 2200, -203.1]
1 clash: 1 run against 1 element of the architecture and the structure (tolerance 1 mm); 2 runs checked against 85 elements
```

The sewage pipe, laid at a fall from the WC, runs in the insulation of the architect's ground slab, which no record of either says. The answer is theirs to agree (section 3.3): a void, a sleeve, or the pipe laid under the slab.

Its limits: a member is taken as swept, before its joins cut its ends, and a supplier's declared mesh as its convex hull, so both may clash a little more than they are; reinforcement is left out; a terminal has no body of the compiler's (Part IV, 12) and is not checked; and runs are not checked against each other. The reference implementation also answers what a straight run from one point to another passes through (its `query` with `along`).

### 3.5 Delete with commands

A command does what a hand edit cannot: a `delete` takes with it what is hosted by the element and the view items that name it, and a type is not deleted while anything still names it (Part V, 5). `openeik apply` runs commands on a folder:

```sh
openeik apply ./building ./remove-the-sewage.json --dry-run
openeik apply ./building ./remove-the-sewage.json --out ./building
```

Removing files by hand works for a whole discipline, as section 2 shows. It leaves the ids of the removed types in `project/order.json`, which readers ignore and the next write drops. Neither way closes a hole that was cut for what went: the hole is its host's (section 2), and its owner closes it.

### 3.6 Building services from another tool

A building services model made in another program comes into OpenEik in one of two ways:

- as OpenEik records, written into `ventilation/`, `plumbing/` and their types' folders by a bridge or an agent, on a line of their own or as a proposal (Part VI, 8);
- or as an IFC model linked for reference, which is how the reference implementation reads IFC: shown beside the model, not taken into its records (Part VIII, 2).

## 4. Not in OpenEik 0.2

- **Forks that remember their origin**: planned (Part VI, 7). A host's proposal is made from an envelope ([Part XVII, 6.3](https://openeik.org/spec/0.4/envelope)); where no host offers proposals, an application offers its changes in a proposal file (Part VI, 8.7).
- **Linking a model that another firm owns and keeps elsewhere**, as a reference rather than as records: not defined.

Ownership by discipline folder, folders that follow owners and electrical installations, which this section listed for 0.1, are 0.2's: sections 1 and 3.3 say how. `@openeik/tools` reads and checks `project/owners.json`, says what a change needs and migrates a building to the owners' layout; EikHub, the host the reference implementation pushes to, holds changes for their owners.
