# OpenEik in 10 minutes

| | |
|---|---|
| Status | Guide, informative. Written 14 October 2026, for OpenEik 0.1.0-draft; brought up to 0.2.0-draft on 30 October 2026 |
| For | A developer who has never seen OpenEik |
| Rule | Where this primer and the specification (`spec/`, `schemas/`) differ, the specification wins |

## 1. What a model is

OpenEik is an open standard for building models. A building is stored as a code base: a folder of small JSON files, one record per file, at paths derived from the records. Types play the part of classes and elements of their instances; records refer to each other by id. Bodies, areas and quantities are derived by a compiler and never stored. Changes are typed commands, checked before anything changes. History is kept as versions with diffs and merges, as git keeps code. An AI agent reads and edits a model through a defined interface, or works on its files directly. IFC is an export, not the base.

A model works on a local disk, in any git host or in any store. Nothing in the standard requires a particular product or service.

## 2. A tour of a small folder

[`examples/one-storey-house`](https://gitlab.com/openeik/spec/-/tree/main/examples/one-storey-house) is a complete model in 34 files: a house of 10 m by 7 m with four outer walls and a partition, a ground slab, a door, two windows and a gable roof. The reference implementation wrote it from typed commands ([`one-storey-house.commands.json`](https://gitlab.com/openeik/spec/-/blob/main/examples/one-storey-house.commands.json)).

```text
eik.json                                       the format and the units
AGENTS.md                                      the conventions, for agents
project/project.json                           the project
project/levels.json                            level-0 (ground floor) and level-1 (roof)
project/order.json                             the order of the record lists
project/materials/mat-render.json              … and nine more materials
types/architecture/wall/type-wall-exterior-300.json
types/architecture/wall/type-wall-partition-100.json
types/architecture/door/type-door-1000.json    … and three more types
architecture/level-0/wall/wall-south.json      … and wall-east, wall-north, wall-west, wall-partition
architecture/level-0/slab/slab-ground.json
architecture/level-0/door/door-entrance.json
architecture/level-0/window/window-south.json  and window-north.json
architecture/level-1/roof/roof-main.json
drawings/setup/views/plan/view-plan-0/view.json
                                               … and two more views
```

**`eik.json` comes first.** It says `{"format": "openeik/0.4", "units": "mm"}`. A reader reads it before any record, and refuses a format it does not implement. A reader of 0.2 also reads a model of 0.1, by 0.1's rules.

**An element** is one placed thing. Its path is `<discipline>/<level>/<category>/<id>.json`, `<discipline>` the discipline that owns it: `architecture`, `structure`, `ventilation`, `plumbing`, `electrical`, `sprinkler`, `site` or, for views, `setup`. Here is the south wall, `architecture/level-0/wall/wall-south.json`:

```json
{
  "category": "wall",
  "height": 2700,
  "id": "wall-south",
  "levelId": "level-0",
  "name": "South wall",
  "offset": 0,
  "profile": [
    [10000, 0],
    [0, 0]
  ],
  "revision": 1,
  "top": {
    "attach": {
      "face": "underside",
      "hostId": "roof-main"
    },
    "constraint": "unconnected"
  },
  "typeId": "type-wall-exterior-300",
  "width": 300
}
```

- Units are millimetres, Z up. A wall's level plus its `offset` is its base; for a slab or a roof the same sum is its top face.
- `profile` is the wall's centreline in plan, from its first point to its second.
- `typeId` names its type, `top.attach` the roof whose underside its top follows.
- `revision` is 1: a command changed it once, when it attached the wall to the roof.

**A type** is what its elements share. `types/architecture/wall/type-wall-exterior-300.json` lists four layers, exterior first: render 20 mm, insulation 100 mm, a masonry core 165 mm and plasterboard 15 mm. The exterior is on the left of the wall's direction. The south wall runs from east to west, so its left is the south, and the render is outside.

**A hosted element** takes its place from its host. The door, `door-entrance.json`, names `"hostId": "wall-south"`; `"along": 2500` is the distance in plan from the wall's first point to the door's near edge, and `"offset": 0` the height of its bottom above the wall's base.

**What is not there.** No file holds a mesh, an area, a volume, a corner join or the cut of the walls under the roof. They are derived, every time, from the records.

**Other files.** A file that is no record, such as a README or an application's results, is a kept file: it travels with the model, untouched. Files and folders whose names start with `.` (`.git/`, `.eik/`) are not part of the model.

## 3. The rules that matter most

1. **One record, one file.** A record's path is derived from it; its identity is its id, not its path. Ids are stable for life and never contain `/` (Part I, 6; Part III, 4).
2. **Millimetres and Z up.** A level plus an offset is read as each category says: a wall's base, a slab's top face (Part I, 3 and 4).
3. **References are ids.** A `typeId` names a type of the same category, a `levelId` a level, a door's `hostId` its wall; they must resolve (Part I, 7; Part II, 7).
4. **Nothing derived is stored** (Part II, 10; Part IV, 1).
5. **One text form.** Every JSON file is written in the stored form: members sorted, two spaces, one member a line. Whoever changes a record by hand adds 1 to its `revision` (Part III, 5; Part I, 8).
6. **Keep what you do not know.** Unknown members, records of unknown categories and kept files are written back unchanged (Part I, 10; Part III, 7).
7. **Change through commands where you can.** A command is typed and checked against the whole model, and a batch is all or nothing, with dry runs (Part V). Hand edits are allowed, and checked when the folder is read (Part III, 14).

## 4. Check a folder

`@openeik/tools`, in [`packages/openeik`](https://openeik.org/tools/0.4/README.md), reads, checks, hashes and diffs models, and has no dependencies. From the root of this repository, with Node.js 20.16 or later:

```sh
node packages/openeik/bin/openeik.mjs check examples/one-storey-house
```

```text
examples/one-storey-house: 34 files (1 agents, 1 eik, 10 element, 1 levels, 1 order, 1 project, 10 record, 6 type, 3 view); 0 errors, 0 warnings; 0 generic elements
```

Now break it. Copy the folder, move the door past the end of its wall (`"along": 9500`, and add 1 to its `revision`), and check the copy. The steps can be run again: the copy takes the example's files afresh each time.

```sh
mkdir -p ~/openeik-house && cp -R examples/one-storey-house/. ~/openeik-house
perl -pi -e 's/"along": 2500/"along": 9500/; s/"revision": 0/"revision": 1/' \
  ~/openeik-house/architecture/level-0/door/door-entrance.json      # or edit the two values by hand
node packages/openeik/bin/openeik.mjs check ~/openeik-house
```

The check prints a summary line, which starts with the folder's full path (shown here as `…`), and then each diagnostic:

```text
…/openeik-house: 34 files (1 agents, 1 eik, 10 element, 1 levels, 1 order, 1 project, 10 record, 6 type, 3 view); 1 error, 0 warnings; 0 generic elements
  error   architecture/level-0/door/door-entrance.json /along: Opening must fit within its host wall: it reaches 10500 mm along a wall 10000 mm long. [opening-fit, II.6.1.5]
```

The command exits with 1. Each diagnostic names the file, the member, a stable code and the rule of the specification it comes from: here Part II, 6.1, rule 5.

From JavaScript:

```js
import { readFolder, checkFolder } from "./packages/openeik/src/index.js";

const { ok, errors, warnings } = checkFolder("examples/one-storey-house");
// each error: {severity, code, path, pointer, message, rule}

const house = readFolder("examples/one-storey-house"); // refused, with the diagnostics, if it does not check
house.model.elements.length;                            // 10
house.pathOf("elements", "door-entrance");              // "architecture/level-0/door/door-entrance.json"
```

Three more commands are worth knowing on the first day:

```sh
node packages/openeik/bin/openeik.mjs tree examples/one-storey-house architecture/level-0   # the layout, a folder at a time
node packages/openeik/bin/openeik.mjs hash examples/one-storey-house                         # the root hash: equal hashes, equal models
node packages/openeik/bin/openeik.mjs diff <folder> <other folder>                           # what changed, by record and field
```

## 5. Where to read next

- [The specification](https://openeik.org/spec/0.4/): its contents and conventions. Part I (Foundations) and Part III (Code base) are enough to work on files.
- [Terminology and references](https://openeik.org/spec/0.4/terminology-and-references): every term, and where it is defined.
- Part V (Commands), Part VI (History) and Part VII (Agent interface), when you change models, keep their versions or serve them to agents.
- [Conformance](https://openeik.org/spec/0.4/conformance): what a reader, a writer or an agent host must do.
- [Security and privacy considerations](https://openeik.org/spec/0.4/security-and-privacy): before you read models from others, or let agents work on them.
- [The other guides](https://openeik.org/guides/README.md), and the [`@openeik/tools` README](https://openeik.org/tools/0.4/README.md) for the whole library.
