Think Lightning payment receipt style, but for project information: a person signs a structured record, broadcasts it to relays, and everyone can verify who signed what, which file hash it references, and which earlier record it depends on.
Contents
Actors
| Person | Project role | Key | Typical actions |
|---|---|---|---|
| Alice | Client / appointing party | alice-pubkey | Creates project, defines requirements, approves publication. |
| Bob | Architect / lead appointed party | bob-pubkey | Publishes IFC packages, answers issues, requests approval. |
| Max | MEP engineer / BIM coordinator | max-pubkey | Checks the model, creates BCF topics, comments, validates issues. |
| Relay | Shared message board | none | Stores and forwards signed events. It is not the source of truth. |
| Storage | File holder | none | Stores binaries such as IFC, PNG, PDF. Hashes prove file integrity. |
Signed-record analogy
The analogy is useful if it stays precise. We do not put BIM data into a payment network. The shared idea is simpler: a signed object references earlier objects and can be verified without asking a platform database for permission.
| Verifiable payment record | BIM-CVP event |
|---|---|
| A payer authorizes a payment. | NIP-07 signer signs the event with Alice, Bob or Max's key. |
| The receipt can be checked later. | Nostr event ID and signature can be verified independently. |
| The payment references a recipient and amount. | e, a and file tags reference project, topic, viewpoint and file events. |
| The network only moves the message. | Relays distribute events; clients verify signatures and file hashes. |
| Settlement history is append-only. | Comments and audit events are append-only. Replacements create new signed records. |
Alice signs project event -> relay stores it -> Bob and Max verify Alice's signature Bob signs model reference -> references Alice's project -> references a file hash -> everyone verifies the same IFC bytes Max signs BCF issue -> references Bob's model -> references IFC element GUIDs -> references viewpoint and snapshot Alice signs approval -> references the resolved topic and model package -> proves who accepted what
End-to-end story
The whole project can be read as a graph. The important part is not that everything is public; private projects can use private relays. The important part is that every actor can take the graph, verify signatures and hashes, and export normal buildingSMART artifacts such as BCFZIP or IFC references.
kind:30902 Alice creates project
|
+-- kind:30880 Alice defines requirements
+-- kind:30810 Alice/Max publish IDS
|
+-- kind:1063 Bob uploads IFC file metadata
+-- kind:30904 Bob publishes IFC file reference
|
+-- kind:1063 Max uploads snapshot metadata
+-- kind:30901 Max publishes immutable BCF viewpoint
+-- kind:30900 Max publishes current BCF topic
|
+-- kind:1170 Bob comments
+-- kind:1171 Bob changes status, audit record
+-- kind:30900 Bob publishes replacement topic state
|
+-- kind:1180 Max publishes IDS validation result
+-- kind:30970 Alice approves package
1. Bob shares an IFC model
Bob does not send a model by email. He uploads the IFC to storage, then signs metadata that says: this exact file, with this hash, belongs to Alice's project and represents the architectural model at this revision.
{
"kind": 1063,
"pubkey": "bob-pubkey",
"tags": [
["url", "https://storage.example/pilot-arc-r03.ifc"],
["m", "application/x-step"],
["x", "sha256-of-ifc-file"],
["size", "42850432"],
["a", "30902:alice-pubkey:pilot-2026"],
["filename", "PILOT_ARC_MOD_S2_P03.ifc"]
],
"content": "IFC file uploaded by Bob"
}
{
"kind": 30904,
"pubkey": "bob-pubkey",
"tags": [
["d", "pilot-arc-model-r03"],
["a", "30902:alice-pubkey:pilot-2026"],
["e", "ifc-file-metadata-event-id", "", "file"],
["discipline", "architecture"],
["schema", "IFC4X3_ADD2"],
["mvd", "ReferenceView"],
["ifc-project", "0aB1cD2eF3gH4iJ5kL6mN7"],
["iso19650-state", "Shared"],
["revision", "P03"]
],
"content": "{\"model_name\":\"Architecture model\",\"authoring_tool\":\"Archicad\"}"
}
2. Max creates a BCF issue
Max opens Bob's IFC in a viewer and sees that an MEP duct crosses a beam. He creates a BCF issue. The signed event does not contain the IFC model; it references Bob's model event, the affected IFC element GUID, a snapshot file and an immutable viewpoint.
{
"kind": 30901,
"pubkey": "max-pubkey",
"tags": [
["d", "viewpoint-guid-001"],
["a", "30902:alice-pubkey:pilot-2026"],
["bcf-guid", "viewpoint-guid-001"],
["bcf-version", "3.0"],
["ifc-file", "bob-ifc-reference-event-id"],
["ifc", "2Y$0aBv19FqQ9rP5J6wQhA"],
["e", "snapshot-file-event-id", "", "snapshot"]
],
"content": "{\"camera\":{\"type\":\"perspective\"},\"components\":{\"selection\":[{\"ifc_guid\":\"2Y$0aBv19FqQ9rP5J6wQhA\"}]}}"
}
{
"kind": 30900,
"pubkey": "max-pubkey",
"tags": [
["d", "topic-guid-duct-beam"],
["a", "30902:alice-pubkey:pilot-2026"],
["bcf-guid", "topic-guid-duct-beam"],
["bcf-version", "3.0"],
["bcf-type", "Clash"],
["bcf-status", "Open"],
["s", "Open"],
["bcf-priority", "High"],
["p", "bob-pubkey", "", "assignee"],
["p", "alice-pubkey", "", "watcher"],
["ifc-file", "bob-ifc-reference-event-id"],
["ifc", "2Y$0aBv19FqQ9rP5J6wQhA"],
["e", "viewpoint-event-id", "", "viewpoint"],
["e", "snapshot-file-event-id", "", "snapshot"]
],
"content": "{\"title\":\"Duct crosses beam at axis 4/B\",\"description\":\"Please reroute duct or confirm structural opening.\",\"labels\":[\"mep\",\"structure\"]}"
}
3. Bob comments and changes status
Bob cannot silently overwrite Max's issue. He signs a comment and then publishes an audit event plus a replacement topic state. The current state is easy to query, while the reason remains visible.
{
"kind": 1170,
"pubkey": "bob-pubkey",
"tags": [
["e", "topic-event-id", "", "root"],
["a", "30902:alice-pubkey:pilot-2026"],
["p", "max-pubkey"]
],
"content": "{\"guid\":\"comment-guid-001\",\"text\":\"I will reroute the duct below the ceiling zone and publish P04.\"}"
}
{
"kind": 1171,
"pubkey": "bob-pubkey",
"tags": [
["e", "topic-event-id", "", "root"],
["a", "30902:alice-pubkey:pilot-2026"],
["audit-field", "bcf-status"],
["audit-from", "Open"],
["audit-to", "InProgress"],
["bcf-action", "update"]
],
"content": "{\"reason\":\"Assignee accepted the issue.\"}"
}
Bob then publishes a new kind:30900 with the same
d and bcf-guid, but with
bcf-status = InProgress. That is the BCF equivalent of
spending the old current state into a new current state, while retaining
the full signed history.
4. Alice asks for IDS validation
Alice wants machine-checkable delivery requirements. Max or a validator publishes an IDS spec and then signs a validation result against Bob's model reference.
{
"kind": 30810,
"pubkey": "alice-pubkey",
"tags": [
["d", "ids-fire-and-classification-lp4"],
["a", "30902:alice-pubkey:pilot-2026"],
["schema", "IDS1.0"],
["lang", "en"]
],
"content": "{\"title\":\"LP4 delivery requirements\",\"ids_url\":\"https://storage.example/ids-lp4.xml\"}"
}
{
"kind": 1180,
"pubkey": "max-validator-pubkey",
"tags": [
["e", "ids-spec-event-id", "", "spec"],
["e", "bob-ifc-reference-event-id", "", "model"],
["a", "30902:alice-pubkey:pilot-2026"],
["result", "pass-with-warnings"],
["passed-count", "147"],
["failed-count", "3"],
["x", "sha256-of-validation-report"],
["report-url", "https://storage.example/report-lp4.json"]
],
"content": "{\"summary\":\"147 requirements passed, 3 classification warnings.\"}"
}
5. Alice approves the package
Approval is a new signed decision. It references Bob's model, Max's validation result and the resolved BCF topic. If Alice later needs to prove what was approved, the event graph is enough.
{
"kind": 30970,
"pubkey": "alice-pubkey",
"tags": [
["d", "approval-lp4-2026-05-16"],
["a", "30902:alice-pubkey:pilot-2026"],
["approval-type", "PhaseGate"],
["target-state", "Published"],
["target-stage", "LP4"],
["e", "bob-ifc-reference-event-id", "", "file"],
["e", "validation-result-event-id", "", "validation"],
["e", "topic-event-id", "", "resolved-topic"],
["signers", "alice-pubkey,max-pubkey"],
["sig-policy", "2-of-2"]
],
"content": "{\"decision\":\"LP4 architecture package accepted with listed warnings.\"}"
}
buildingSMART process map
| buildingSMART / ISO process | Alice/Bob/Max example | Signed records |
|---|---|---|
| Project setup / BCF project | Alice creates the project and invites Bob/Max. | 30902 |
| IFC model exchange | Bob publishes the architectural IFC package. | 1063, 30904 |
| BCF coordination | Max creates a clash topic with viewpoint and snapshot. | 1063, 30901, 30900 |
| BCF discussion | Bob answers, Max reviews, Alice watches. | 1170 |
| BCF status history | Open becomes InProgress, then Resolved. | 1171 + replacement 30900 |
| IDS requirement check | Max validates Bob's IFC against Alice's IDS. | 30810, 1180 |
| ISO 19650 publication | Alice approves the Shared package as Published. | 30970 |
| BCFZIP export | A classic tool receives a normal BCF file. | Event graph to .bcfzip |
Why this makes implementation easier
Once the story is fixed, each component has a narrow job. The BCF form only creates a topic. The thread view only reads topic, comments, audit, viewpoint and snapshot. The approval component only references already signed records. The implementation does not need to invent workflow rules; it follows the graph.
BCF form
Creates 30900, then links 1063 and 30901.
Thread view
Queries 30900, 1170, 1171, linked viewpoint and snapshot.
Importer/exporter
Transforms event graph to and from BCFZIP without owning the workflow.
Approval gate
Checks unresolved topics, validation results and file hashes, then signs 30970.
Read on
- Workflow model — the complete process frame
- BCF to Nostr events — exact event schema
- Kind mapping — all event kinds
- BCF primer — how buildingSMART BCF works