OpenEik.org
Apps on OpenEik

One building, many apps.

The apps that work with OpenEik today, and how any app reads a version of the building, keeps its results beside it, proposes changes and stays in step with everyone else.

OpenEik is non-profit and vendor-neutral, so this is a directory and an open pattern, not an advertisement. Any app that reads or writes OpenEik models can be listed.

The apps today

Four apps, and where each stands.

Last updated 11 October 2026Listed 4 apps

Stomra

LiveOpenEik support in testing

BIM authoring for people and AI agents, and the reference implementation of OpenEik.

  • Reference implementation
  • Reads
Reads
The whole model: every record, and other apps' files, which it keeps as they are.
Writes
The whole model. Its ek engine reads, checks and edits OpenEik folders, every change a checked command.
stomra.com →

Femra

In development

Structural analysis by the finite element method, to Eurocode, as a connector for AI assistants.

  • Reads
  • Writes its own folder planned
  • Proposes commands planned
Reads
Beams, columns, slabs, walls, roofs, foundations, their types and materials, and the levels, by the format alone.
Writes
Designed to keep its analysis models and results in its own folder beside the building, tied to the version they were computed from. That writer is not built yet.
femra.app →

The openeik command and library

In testingpublic with the specification in Q4 2026

Read, check, hash, diff, push and pull OpenEik models, from the command line or inside an app. Written from the specification alone, with no dependencies.

  • Reads
Reads
Every file of a model folder, or a version from a store.
Writes
A version to a store when it pushes, and a version into a folder when it pulls. It does not edit the building.
No public link yet

A railing manufacturer

Research

A supplier reads a model, checks its railings against what it can make, and proposes changes.

  • Reads planned
  • Proposes commands planned
Reads
Railings, and the stairs, slabs and levels they are fixed to.
Writes
Nothing in the building. Its changes come as proposals that a person reviews.

The study is behind the roadmap's richer railing types, and behind the supplier pattern.

How suppliers propose in the model → No public link yet
Status
  • LiveIn use today.
  • In testingWorks, and is being tested with early users.
  • In developmentBeing built; parts of it work.
  • PilotTried out with one organisation.
  • ResearchA study: what an app would need, before it is built.
Relation to OpenEik
  • Reference implementationThe evidence that each rule of the standard can be met.
  • ReadsReads OpenEik models.
  • Writes its own folderKeeps its own data beside the building, in a folder of its own.
  • Proposes commandsChanges the building only by proposing checked commands, which a person accepts.
  • plannedDesigned, not built yet.
01 The idea

A code base has many tools around it. A building can too.

In a code baseIn an OpenEik projectFor example
Small source files in one repositoryOne record per file, in discipline foldersstructure/level-1/beam/beam-r8n2wc4d.json
Tools check out a commit and do their own jobApps read a version, named by its hash, and do their disciplineFemra reads hall-b@c3d41f9a
CI results belong to one commitResults name the version they were computed from"computedFrom": {"version": "c3d41f9a…"}
A pull request carries code changesA proposal carries typed, validated commandsbeam B3: type-beam-360 → type-beam-450
Required checks before mergeChecks before mergeutilisation ≤ 1.0 for every member
Code owners review their pathsDisciplines own their foldersanalysis/frame-a/**: the structural engineer
A fork for an experimentA fork or an alternative for a simplified modela stick model for seismic analysis
“This branch is behind main”“These results are stale”computed from v2; the beam changed in v3

One difference, on purpose. A code host keeps CI results beside the repository. OpenEik keeps the results people rely on inside the tree, so they travel with the model: on disk, in any git host, or with a hosting service.

02 The pattern, for any app

Six steps coordinate every app, and the building changes only through review.

  1. Read a versionNamed by its hash, never “latest”. Read only the records you need, and note their hashes.Code: check out a commit
  2. Work in your disciplineYour own model, assumptions and software: an analysis, a schedule, orders, a light study.Code: build and test
  3. Write your outputUnder your own folder in the tree, with a manifest naming the version it was computed from.Code: a CI result on a commit
  4. Propose changesTo the building, as typed, validated commands on a branch or an alternative. Never edit another discipline's records.Code: a pull request
  5. A person reviews and mergesWith the diff, the checks and the owners' approval.Code: review, checks, merge
  6. Everyone is currentEvery app reads the new head. Results whose source is no longer current show as stale until run again.Code: “behind main”, re-run

Steps 1–3 touch only the app's own folder. Steps 4–5, in oak, are the only way the building itself changes.

03 One round · Femra and one beam · synthetic example

One round of the pattern, on the version graph.

MAIN the building, protected v1 · a7e3c0d1 frame drawn v2 · c3d41f9a level 1 beams results · 4f8e2a6b computedFrom c3d41f9a stale from v3 v3 · e5f6a0b2 B3 600 mm longer v4 · 9d01b7e4 merged: deeper B3 command B3 → type-beam-450 results max 0.86 PROPOSAL · an alternative today Femrareads c3d41f9a, analyses frame-a 1 read v2 by its hash 2 3 write results 4 Femra proposes on its own line 5 a person reviews and merges 6 every app reads v4; old results show as stale
  1. Femra reads v2 by its hash.
  2. It analyses frame-a, from the records it read.
  3. It writes its results; they touch only analysis/frame-a/.
  4. The architect makes beam B3 600 mm longer in v3, so the results go stale. Femra proposes a deeper B3 on its own line, with the results computed on it.
  5. A person reviews the change and its check together, and merges it as v4.
  6. Every app reads v4; the old results show as stale.

Hashes shortened and illustrative. ◆ a results commit: it touches only analysis/frame-a/. ○ a building version. The proposal carries the command and the results computed on it, so the reviewer sees the change and its check together. Today an app writes an alternative rather than the main line, and a person merges it.

04 One tree · a folder per app

One repository holds the building and every app's output, each in its own folder.

hall-b/
├── eik.json                            format, units
├── project/project.json  levels.json  materials/
├── types/architecture/window/type-window-b.json
├── architecture/level-1/window/window-m4c8tq2h.json
├── structure/level-1/beam/beam-r8n2wc4d.json
├── analysis/frame-a/                   Femra · structure
│   ├── model.json  source.json  members/  loads/ …
│   ├── results/r-5d1c0e9a7b32/manifest.json …
│   └── proposals/p-b3-deeper.json
├── analysis/daylight/study-2f7k9xq4/   daylight
├── schedule/                           project management
├── procurement/                        procurement
├── requirements/daylight.json          the project's requirements
└── .eik/                               generated, never committed

Building records

project/, types/, architecture/, structure/, systems/, site/. Changed only by commands, through review.

An app's folder

Written by that app, owned by its discipline. One item per file, in the stored form; text files of at most 1 MiB.

Results, kept small

Per-member extremes, utilisations and summaries. Meshes, node displacements and full fields stay out: cheap to compute again.

Build output

Indexes, bodies, drawings and quantities are derived and rebuilt locally. Never committed.

Live in the reference implementation since 11 October 2026: files it does not know, such as analysis/…, are kept byte for byte through export, save, restore and merge. The layout of an app's folder is proposed for the specification.

05 The design call · results

Results live in the tree, tied to the version they were computed from.

Decided on 11 October 2026: results live in the tree, as long as it is clear which version they belong to. Two ways make it clear, and they work together.

A · A manifest names the version

analysis/frame-a/results/r-5d1c0e9a7b32/manifest.json{
  "app": {"name": "femra", "version": "…"},
  "computedFrom": {
    "inputs": {"count": 41, "digest": "3b0f6c2e…"},
    "model": "a41e0c7d…",
    "upstream": null,
    "version": "c3d41f9a…",
    "versionKind": "openeik"
  },
  "engine": {"codePack": "…", "kernel": "femra …"},
  "format": "openeik-result/0.1-proposal",
  "kind": "structural-analysis",
  "made": {"at": "…", "by": "…"},
  "summary": {"maxUtilisation": 0.71}
}

The file says it itself, so it survives an export, a copy and any git host. inputs.digest is one hash over the path and hash of every record read; source.json lists them. The result manifest is proposed for the specification.

B · The results commit's parent is the analysed version

c3d41f9a v2, analysed 4f8e2a6b parent: c3d41f9a tree = c3d41f9a's tree + analysis/frame-a/results/ nothing else changed Easy to find in history. A later merge blurs it, and an exported single version loses it.
Use both. The manifest is the rule every check reads. The parent link keeps history readable: computedFrom.version is the version before the results were saved, and the commit that adds them is its child.
06 When the building moves on

Old results are kept, marked stale, and run again.

c3d41f9av2 R1results from v2 b61d05c8schedule/ only e5f6a0b2v3: B3 600 mm longer R2re-run from v3 71aa4e03procurement/ only R1 fresh inputs digest at head = 3b0f6c2e… R1 stale 1 input record changed R2 fresh R1 to history A schedule change moves the head but not Femra's inputs: still fresh. A record Femra read changed: stale, and it says which. Two runs compare member by member: beam-r8n2wc4d 0.71 → 1.08

Kept

The latest set per model, and every set an engineer signed, stay in the tree. The history keeps the rest; deleting an old run's folder is a normal change.

Marked stale

Computed, never written into a file. Hash the records source.json selects at the head and compare with inputs.digest. “Not the head” alone is not enough: saving results is itself a commit.

Run again

A run's id comes from its inputs, model and engine, so the same inputs give the same files. A new run gets a new folder, and the two compare member by member.

07 Forks and alternatives · a simplified model · synthetic example

A simplified model lives on its own line, and its results belong to that line.

MAIN · demo/hall-b c3d41f9av2 e5f6a0b2v3 9d01b7e4v4: B3 deeper 3e8b7c10v5: bracing, reviewed ITS OWN LINE · seismic-stick behind main: a record changed in 9d01b7e4 f1c8a2e7 · simplify stick model, a node per storey results · computedFrom f1c8a2e7 upstream e5f6a0b2 · response spectrum a proposal to main: commands only, the line's results cited as evidence

The line remembers its origin

Today it is an alternative, whose start is recorded as its base; forks in another repository that remember their origin are planned. Ids stay the same, so each stick member can name the elements it stands for.

Results tie to the line

Analysed under a model id of its own, analysis/seismic-stick/. computedFrom.version is the line's version, and computedFrom.upstream names main's e5f6a0b2.

What flows back

Never the simplification. A proposal to main with commands, such as bracing, reviewed like any other. Merged back by mistake, its folder still says it was not computed from main.

08 Weighing it

Results in the tree are worth it, if four risks are guarded.

For

  • One tree tells the whole story: the building, and what each discipline concluded from it, at every version.
  • A change and its check travel in one proposal; the reviewer sees both.
  • History comes free, and two runs compare file by file: “0.71 → 1.08”.
  • No second system to keep in step: on disk, in any git host or with a hosting service.
  • Agents read results with the same tools they use on the building.
RiskMitigation
Stale results read as currentThe manifest is required: no result set without computedFrom and its inputs digest. Staleness is shown on every read, in viewers and in checks. A release can require fresh results.
Repository sizePer-element extremes and summaries only, as text files of at most 1 MiB. Meshes, node displacements and full fields stay out: cheap to compute again. The latest set per model and the signed ones stay; the history keeps the rest.
Results conflict in a mergeNever merged field by field: take one side, then run again on the merged version. After any merge, the inputs digest says whether a set still holds.
It blurs “build output is never committed”Keep the line: bodies, drawings, quantities and indexes stay out. Results someone signs or relies on are a discipline's work, kept with their version.
Adopted on 11 October 2026. Every result set carries a manifest whose computedFrom names its version and digests its inputs; the manifest is proposed for the specification. Staleness is computed, never stored. Large fields stay out, and build output is still never committed.
09 Femra · structural analysis · 1 of 2 · synthetic example

Femra reads the structure at one version, and writes its analysis beside it.

Reads
From the building: beams, columns and foundations in structure/; walls, slabs and roofs in architecture/; their types and materials; the levels. From its own folder: the analysis model, with members, panels, supports, loads, combinations and assumptions. No building record holds a load.
Writes
analysis/frame-a/: the analysis model, one item per file; source.json with the records read and their hashes; results/<runId>/ with the manifest, one result per member and the report.
Ids
A member made from a beam takes the beam's id, so a result points straight at it: beam-r8n2wc4d. Other items get ids from element and role, never a counter.
Units
Femra's own, m and kN, declared in model.json.
analysis/frame-a/model.json        units, basis, site
source.json       records read, with their hashes
members/  panels/  supports/  loads/ …
assumptions/  generators/
results/r-5d1c0e9a7b32/manifest.json
results/r-5d1c0e9a7b32/members/beam-r8n2wc4d.json
results/r-5d1c0e9a7b32/report.html
proposals/p-b3-deeper.json
results/r-5d1c0e9a7b32/members/beam-r8n2wc4d.json{
  "extremes": {"ULS-2": {"My": 41.3, "Vz": 18.9}},
  "governing": {"check": "bending", "combination": "ULS-2"},
  "id": "beam-r8n2wc4d",
  "utilisation": 0.71
}

Femra lives in its own repository and reads OpenEik folders by the format alone. Writing its analysis and results beside the building, as shown here, is designed and not built yet. Values and hashes are illustrative.

10 Femra · 2 of 2 · synthetic example

Femra proposes a deeper beam, and its check gates the merge.

analysis/frame-a/proposals/p-b3-deeper.json{
  "base": {"records": {"beam-r8n2wc4d": {"hash": "…", "revision": 4}},
           "version": "e5f6a0b2…"},
  "by": {"app": "femra …", "person": "…"},
  "commands": [{
    "expectedRevision": 4,
    "id": "beam-r8n2wc4d",
    "kind": "update",
    "patch": {"height": 450, "typeId": "type-beam-450"}
  }],
  "dryRun": {"ok": true},
  "evidence": {"after": 0.86, "before": 1.08, "check": "bending",
               "run": "analysis/frame-a/results/r-…/manifest.json"},
  "format": "openeik-proposal/0.1-proposal",
  "intent": "Deeper B3: bending utilisation 1.08"
}
Check on the proposal: every member ≤ 1.0; beam-r8n2wc4d 1.08 → 0.86; every case balances.
Proposes
Typed commands, dry-run first. A beam's height is its own, so a deeper beam sets both its type and its height.
Check
Before merge: the structure stands and every case balances; utilisation ≤ 1.0 for every member; the change per member against the base; every assumption accepted.
Today
A person accepts by merging an alternative, or by running the batch on a folder with the reference engine. Checks before merge are planned with a hosting service.
Diffs
Linked records changed since the analysis: “beam-r8n2wc4d 600 mm longer; 2 loads affected”. source.json says which.
Seismic
On a simplified line (07, above). Femra already has modal analysis and the EN 1998 spectrum.

The proposal file is proposed for the specification. Commands are the reference implementation's command kinds today; a common command envelope is planned for OpenEik 0.2.

11 A project management app · synthetic example · not a product

A project management app schedules elements, and turns diffs into change orders.

Reads
Elements and levels; quantities, derived by the engine at that version; the version history.
Writes
schedule/: tasks linked to element ids (4D), the status of each element, change orders. Each task names the version it was planned from.
Proposes
Rarely a building change. It adds time and cost to someone else's proposal.
Check
A proposal that changes elements of a started task lists the tasks it hits. A task that points at a deleted element blocks the merge.
Today
The reference implementation has work orders, written where a person stands in the model; a proposal of commands is previewed on a copy, and the person answers yes or no. They are kept beside the model today, not in the tree.
schedule/tasks/task-4k2m9q7d.json{
  "elements": ["beam-r8n2wc4d", "beam-t5x1hb2k"],
  "finish": "2027-03-12",
  "id": "task-4k2m9q7d",
  "name": "Erect level 1 beams, grid A–C",
  "plannedFrom": "c3d41f9a…",
  "start": "2027-03-08",
  "status": "planned"
}
The diff c3d41f9a → 9d01b7e4 (v2 → v4), building records only~ structure/level-1/beam/beam-r8n2wc4d.json
    profile   600 mm longer                  v3
    height    360 → 450                      v4
    typeId    type-beam-360 → type-beam-450  v4
  analysis/, schedule/: not building records, left out
schedule/change-orders/co-0007.json{"changed": ["beam-r8n2wc4d"], "from": "c3d41f9a…", "id": "co-0007",
 "impact": {"cost": "from the estimate", "days": 2},
 "tasks": ["task-4k2m9q7d"], "to": "9d01b7e4…"}
12 A procurement app · synthetic example · not a product

A procurement app orders by type, and knows when a type changed after the order.

Reads
Types and materials; the quantity takeoff by type, derived at one version.
Writes
procurement/: packages, orders, supplier quotes and delivery status. Each order line names the type id and the type's hash, and the order names the version it was ordered from.
Flags
A diff on types/** between the ordered version and the head: a type whose hash changed after it was ordered. Counts by type are compared too.
Proposes
A substitute when a supplier cannot deliver: a batch of commands gives the windows another type, for the architect to review.
Check
A proposal that changes an ordered type needs procurement's review, and lists the order lines it affects.
procurement/orders/po-0012.json{
  "delivery": {"due": "2027-02-15"},
  "id": "po-0012",
  "lines": [{"quantity": 24, "typeHash": "5a1c07e2…",
             "typeId": "type-window-b", "unit": "pcs"}],
  "orderedFrom": "e5f6a0b2…",
  "package": "pkg-windows",
  "status": "confirmed",
  "supplier": "supplier-a"
}
types/architecture/window/type-window-b.json   e5f6a0b2 → 2c9e71fa-   "width": 1210,
+   "width": 1410,
po-0012 · type-window-b changed after it was ordered. 24 ordered from e5f6a0b2; the width is now 1410, was 1210. Confirm with the supplier, or propose the ordered type back.

Suppliers can take part directly: a supplier reads a version, checks what it can make, and proposes its own parts as checked commands, with a quote tied to that version. Supplier proposals →

13 A light study app · daylight · synthetic example · not a product

A daylight app studies every room at one version, and proposes larger windows.

Reads
Rooms and their use; windows and their types; walls, slabs and roofs; materials; the site, its true north and the terrain.
Writes
analysis/daylight/study-2f7k9xq4/: study.json with the requirement used; results/<runId>/ with a manifest and one result per room. Grids are computed again, not stored. It may run on a simplified line.
Proposes
A larger window. A typed window's size comes from its type, so the command gives it a larger type; a width that disagrees with the type is refused.
Check
The project's daylight requirement is met in every habitable room. Which requirement, and its threshold, is the project's choice, kept in requirements/.
Diffs
Run again when windows, walls, rooms or the site change; two runs list the rooms that crossed the line.
…/study-2f7k9xq4/results/r-…/rooms/room-h3v8kd1p.json{
  "meets": false,
  "ofRequired": 0.82,
  "requirement": "requirements/daylight.json",
  "room": "room-h3v8kd1p",
  "use": "bedroom"
}
analysis/daylight/study-2f7k9xq4/proposals/p-bedroom-2.json{
  "base": {"version": "9d01b7e4…"},
  "commands": [{"expectedRevision": 2, "id": "window-m4c8tq2h",
                "kind": "update", "patch": {"typeId": "type-window-c"}}],
  "evidence": {"after": 1.04, "before": 0.82, "room": "room-h3v8kd1p"},
  "format": "openeik-proposal/0.1-proposal",
  "intent": "Bedroom 2 below the daylight requirement"
}
Check: 1 habitable room below the requirement. room-h3v8kd1p at 0.82 of the required level, computed from 9d01b7e4.

Values are illustrative and cite no regulation. A typed window's width and height are its type's: the reference implementation refuses a record that says otherwise, and the specification states the same rule.

14 Four apps · one pattern

Four apps, four folders, one way of working.

AppReadsWritesProposesCheck before mergeDiffs and history for
Femrabeams, columns, slabs, walls, roofs, foundations, types, materials, levels; its analysis modelanalysis/frame-a/a deeper sectionutilisation ≤ 1.0 for every memberlinked records changed; a run against a run
Project managementelements, levels, quantities, the historyschedule/rarely: time and cost on others' proposalstasks hit; no task on a deleted elementchange orders from version to version
Procurementtypes, materials, takeoff by typeprocurement/a substitute typeordered types need procurement's reviewtypes/** since the ordered version
Daylightrooms, windows, walls, materials, site and true northanalysis/daylight/<studyId>/a larger window typethe requirement in every habitable roomrooms that crossed the line

Every row reads a named version, writes only its own folder with a manifest naming that version, and changes the building only through a reviewed proposal.

15 The contract · for app makers

Nine rules any app can follow, on disk, in any git host or with a hosting service.

01
Read a named version.Record its hash and the hashes of the records you read; never work from “latest”.
02
Write only your own folder.At a path no record could have, such as analysis/<modelId>/; one item per file, in the stored form; text files of at most 1 MiB.
03
Give every result set a manifest.computedFrom with the version and an inputs digest; the app, the engine, the settings.
04
Change the building only by command.Typed, dry-run first, with expectedRevision; reviewed and merged by a person.
05
Point at elements by id.A member made from a beam takes the beam's id. Never treat a copy of geometry as the truth.
06
Keep what you do not know.Other apps' folders and unknown files stay untouched, byte for byte.
07
Keep large fields out.Meshes, node displacements and full grids are cheap to compute again; store extremes and summaries.
08
Compute staleness, never store it.Hash what you read at the head and compare it with your manifest.
09
Never edit building records directly.No fields added; nothing written into a discipline folder, eik.json or AGENTS.md.

The result manifest and the proposal file are proposed for the specification.

16 Today and next · 11 October 2026

What is live today, what is built, and what is planned.

Live today

  • OpenEik folders through Stomra's engine: export, import, validate, commands and IFC, and a headless engine for agents on a folder.
  • Other apps' files, such as analysis/…, kept byte for byte through save, restore and merge (Stomra, 11 October 2026).
  • Unknown fields kept, and eik.json in every version (Stomra, 11 October 2026).
  • One rule for member axes: the reference line, the taper rule and a sectioned beam's height (Stomra, 11 October 2026).
  • Stomra projects can keep their versions with a hosting service.
  • In Stomra: alternatives, merge by record and field, and work orders that carry proposed commands.
  • The openeik command and library: in testing, public with the specification in Q4 2026.

Built, not public

  • Femra's OpenEik reader, in Femra's own repository: it reads OpenEik folders by the format alone and builds its analysis models from them.

Not built yet

  • Femra's results writer, with result manifests and proposal files, both proposed for the specification.
  • The project management, procurement and daylight apps: examples of the pattern, not products.

Planned with a hosting service

  • Proposals, and checks before merge, Femra's among them.
  • Forks that remember their origin.
  • Scoped access for suppliers: only the parts they need.
  • Signed merges.
  • Attachments, such as a supplier's quote.

Host features, not part of the standard: any host can offer them. EikHub, a commercial host, is one being built.

Build an app

Read a version. Work in your own folder. Propose. A person merges.

The implementation guide and the openeik tools open with the specification in Q4 2026.

The directory at the top is rendered from apps.json, its single source, and changes whenever an app's status does.