diff --git a/grcs/0020-knowledge-graph.md b/grcs/0020-knowledge-graph.md
index a21f875..29c6ff0 100644
--- a/grcs/0020-knowledge-graph.md
+++ b/grcs/0020-knowledge-graph.md
@@ -10,176 +10,354 @@ Discussions-To: https://forum.thegraph.com/t/grc-20-knowledge-graph/6161
# GRC-20: Knowledge Graph
-## Abstract
+## 1. Introduction
-This GRC introduces a standard for storing and representing knowledge on The Graph. It can be used by any application that wants to create and consume interoperable information across applications.
+### 1.1 Abstract
-Data is defined as raw bits that are stored and transmitted. Information is data that is decoded and interpreted into a useful structure. Knowledge is created when information is linked and labeled to attain a higher level of understanding. This document outlines the valid serialization format for the knowledge data that is anchored onchain, shared peer-to-peer or stored locally. Using this standard, any application can access the entire knowledge graph and produce knowledge that can become part of The Graph.
+This GRC-20 specification defines a standard for storing and representing knowledge on The Graph. It enables any application to create, share, and consume interoperable knowledge across applications and domains.
-## Motivation
+Data is defined as raw bits that are stored and transmitted. Information is data that is decoded and interpreted into a useful structure. Knowledge is created when information is linked and labeled to attain a higher level of understanding.
+
+This document specifies the serialization format for knowledge. Using this standard, any application can access the entire knowledge graph and produce knowledge that can become part of The Graph.
+
+### 1.2 Motivation & Scope
+
+#### Motivation
Knowledge graphs are the most flexible way of representing information. Knowledge is highly interconnected across applications and domains, so flexibility is important to ensure that different groups and individuals can independently extend and consume knowledge in an interoperable format. Most apps define their own schemas. Those schemas work for a specific application but getting apps to coordinate on shared schemas is difficult. Once data is produced by an app, custom code has to be written to integrate with each app. Migrations, versioning and interpreting data from different apps becomes even more difficult as schemas evolve. These are some of the reasons that instant composability and interoperability across apps is still a mostly unsolved problem. The original architects of the web understood this and tried to build the semantic web which was called Web 3.0 twenty years ago. Blockchains and decentralized networks give us the tools we need to build open and verifiable information systems. Solving the remaining composability challenges will enable an interoperable web3.
-Computer scientists widely understand triples to be the best unit for sharing knowledge across organizational boundaries. RDF is the W3C standard for triples data. A new standard is necessary for web3 for several reasons: IDs in RDF are URIs which typically point to servers that are controlled by corporations or individuals using https. This breaks the web3 requirement of not having to depend on specific server operators. Additionally, RDF doesn't support the property graph model, which is needed to describe facts about relationships between entities. Some of RDF's concepts are cumbersome and complex which has hindered its adoption beyond academic and niche enterprise settings. For these reasons, a new standard is being proposed that is web3 native, benefits from the latest advancements in graph databases and can be easily picked up by anyone who wants to build the decentralized web.
+Early efforts like the Semantic Web leveraged RDF tiples for sharing knowledge across organizational boundaries. RDF is the W3C standard for triples data. A new standard is necessary for web3 for several reasons: IDs in RDF are URIs which typically point to servers that are controlled by corporations or individuals using https. This breaks the web3 requirement of not having to depend on specific server operators. Additionally, RDF doesn't support the property graph model, which is needed to describe facts about relationships between entities. Some of RDF's concepts are unnecessarily complex which has hindered its adoption beyond academic and niche enterprise settings. For these reasons, a new standard is being proposed that is web3 native, benefits from the latest advancements in graph databases and can be easily picked up by anyone who wants to build the decentralized web.
-## Specification
+#### Scope
-Knowledge graphs are comprised of entities that represent people, places, things, concepts, or anything else. These entities have relations that link them into a graph. Knowledge is published onto The Graph using onchain transactions. Data can be stored offchain on a content addressed storage network and then anchored onchain. Each space for a community or individual has its own knowledge graph and its own governance or access controls. Any entity can reference any other entity across the entire graph, creating a global unified graph. Knowledge graph data doesn't have to be onchain, it can also be transmitted peer-to-peer between users and stored locally.
+This specification covers:
-### 1. Encoding
+* **Core data model:** Entities, Relations, Types, Properties
+* **Native value types:** Text, Number, Checkbox, Time, Point, Relation
+* **Identifier conventions:** UUID guidelines
+* **Serialization & encoding:** Protobuf schemas and JSON examples
+* **Operations & versioning:** Ops, Edits, Imports
+* **Spaces:** Personal vs. Public spaces, access controls
-Data is encoded using Protobufs. Protocol Buffers are a language-neutral, platform-neutral extensible mechanism by Google for serializing structured data. It's chosen for speed, compactness and broad language support.
+This specification does *not* prescribe:
-### 2. IDs
+* Detailed smart contract and governance implementations beyond anchoring patterns
+* Content-type extensions outside the minimum needed for implicit properties (e.g., Image, Block)
+* Indexer specifications beyond some basic context
-All IDs must be globally unique and 22 characters using Base58 encoding. They should be created using the UUID4 standard and stripping out the dashes (bringing the length from 36 bytes to 32 bytes) and then Base58 encoding. If an entity is coming from a system that already has globally unique IDs of arbitrary length, they can be deterministically converted into valid globally unique 22 character IDs by taking an md5 hash of the string, seeding that into a UUID4 generator, stripping the dashes and Base58 encoding. IDs must be randomly generated and not be altered to contain any identifiable strings in order to prevent collisions.
-Example ID: `Gw9uTVTnJdhtczyuzBkL3X`
+## 2. Terminology & Concepts
-### 3. Spaces
+## 3. Architecture Overview
-A space is a logical grouping that represents a group or individual, a knowledge graph and a governance process or access control system for updating information or making changes to the space. A space can be a personal space or a public space. Personal spaces can be private and run local first on a user's device, be shared with a group of people or be published onto a public blockchain for global consistency. Public spaces must be onchain with a public governance system.
+This section describes the high-level components and interactions that make up a GRC-20 knowledge graph deployment, from authoring and storage through anchoring, indexing, and consumption.
-### 4. Triples
+---
-The structure of knowledge on The Graph is built on simple primitives that compose to create more complex structures. Triples are the atomic unit. Triples are combined into entities. Entities are linked together to form a graph.
+### 3.1 Logical Components
-Triples represent a single atomic fact about an entity. They consist of an (Entity, Attribute, Value) tuple. There is also an implied space ID for every triple since different spaces can have different points of view on the same (Entity, Attribute) pair. For example, a space for Americans can assert that the Name of an entity is "Fries" and a British space might call the same entity "Chips" - but they would both reference the same entity ID.
+* **Spaces**
+ Logical domains—either **public**, **personal** or **private** that encapsulate a knowledge graph along with its governance and access controls. Public spaces are backed by onchain smart contracts with public governance, personal spaces are publicly visible and anchored onchain but are controlled by an individual or entity, and private spaces are stored locally on-device or can be encrypted and shared within a group.
+* **Content-Addressed Storage**
+ Offchain networks (IPFS, Arweave, etc.) that hold the full protobuf-encoded graph payloads. Each payload is retrievable by its cryptographic hash.
+* **Onchain Anchoring**
+ Smart contracts record minimal anchors (content hashes, version IDs) on a blockchain. Anchors guarantee immutability and global ordering without storing large amounts of data onchain.
+* **Indexers**
+ Services that listen for onchain anchor events, fetch the corresponding offchain payloads, deserialize them, and maintain an up-to-date, queryable graph index.
+* **Clients**
+ End-user or application libraries that create “edits,” submit them for publishing, and query the index (or peers) for entities, relations, and types.
-If there are multiple triples for a single (Space, Entity, Attribute) combination, subsequent values get treated as an upsert, replacing the previous value for that triple. This applies to the native types and doesn't include relations which support many to many relationships.
+---
-#### 4.1 Entity
+### 3.2 Storage & Anchoring Layers
-The entity field of a triple is a valid ID that represents the entity. It is used to associate any additional triples to the same entity. The first time an entity is created, the client is responsible for generating a globally unique ID. Enforcement of global ID uniqueness is expected of each space's governance.
+1. **Edit Serialization**
+ Clients package changes into a protobuf-encoded `Edit` message (see §10).
+2. **Offchain Storage**
+ The serialized `Edit` is stored in a content-addressed network; its CID (hash) becomes the canonical reference.
+3. **Onchain Anchor**
+ A lightweight transaction in the Space contract records the CID (and any minimal metadata), ensuring a tamper-proof history and global ordering.
-#### 4.2 Attribute
+By separating payload storage from onchain anchoring, we minimize gas costs while preserving verifiability.
-The attribute field must be a valid ID that references the attribute entity that this triple is for. For example, the attribute might be for Name, Description, Birthday or any other property of the entity. The attribute may or may not be added as an attribute on one of the entity's types.
+---
-#### 4.3 Value
+### 3.3 P2P & Local-First Modes
-The value is an object that represents the value for the triple. This set of fields contains additional type and formatting information for the value.
+* **Peer-to-Peer Distribution**
+ Spaces can propagate edits directly between clients using gossip, pub/sub, or CRDTs using the same logical model before or instead of onchain anchoring.
+* **Local-First Workflows**
+ Private spaces may operate entirely offline, storing edits for later anchoring or sharing. Conflict resolution (e.g., merging branches) follows the same edit-ordering rules once synchronized.
-| Name | Value | Description |
-| --------------- |-------| --------------------------------------------------------- |
-| Type | 1 | An enum representing 1 of 6 native value types |
-| Value | 2 | The encoding for the value depends on the value type |
-| Options | 3 | Value type specific options |
+---
+
+### 3.4 End-to-End Data Flow
+
+1. **Create/Edit:** User or app constructs an `Edit` with one or more Ops.
+2. **Serialize:** The `Edit` is marshaled into a compact protobuf message.
+3. **Publish:** The binary is uploaded to a content-addressed network; its content hash (CID) is returned.
+4. **Anchor:** The Space contract records the CID in a transaction, establishing a global sequencing for that space.
+5. **Index:** Indexers detect new anchors, retrieve and deserialize the payload, then update their local graph store.
+6. **Consume:** Clients and downstream apps query the index (or fetch directly from peers) to read entities, relations, types, and properties.
+
+---
-The corresponding protobuf message is:
+### 3.5 Cross-Space Interoperability
+
+* Any entity in one space can reference entities in another by including their IDs along with optional space IDs in relations.
+* This design forms a **global unified graph**, where independent communities can interlink information without centralized coordination.
+
+## 4. Core Data Model
+
+This section defines the building blocks of the graph—**Entities**, **Relations**, **Types**, and **Properties**—along with their minimal on-wire representation.
+
+---
+
+### 4.1 Entities
+
+* **Definition:**
+ An *Entity* is a node in the graph representing any thing (person, place, thing, concept, etc.).
+* **Structure:**
+
+ * **ID**: a globally unique UUID4 (byte-encoded on-wire).
+ * **Values**: zero or more key/value pairs (`Value` messages) attaching data to the entity.
+ * **Relations**: handled separately (see §4.2).
```proto
-message Value {
- ValueType type = 1;
- string value = 2;
- Options options = 3;
+message Entity {
+ bytes id = 1; // UUID4
+ repeated Value values = 2;
}
```
-Options can be included with a value and is specific to the value type. Additional options can be added in future spec versions.
+#### 4.1.1 Value
+
+A `Value` bundles a property reference with its literal content and optional per-value metadata.
```proto
message Options {
- string format = 1;
- string unit = 2;
- string language = 3;
+ oneof value {
+ TextOptions text = 1;
+ NumberOptions number = 2;
+ }
}
-```
-```proto
-message Triple {
- string entity = 1;
- string attribute = 2;
- Value value = 3;
+
+message Value {
+ bytes property = 1;
+ string value = 2;
+ optional Options options = 3;
+}
+
+message TextOptions {
+ optional bytes language = 1;
+}
+
+message NumberOptions {
+ optional bytes unit = 1;
}
```
-#### Example Triple in JSON
+* **TextOptions** (e.g. language entity ID)
+* **NumberOptions** (unit ID)
-```jsonc
-{
- "entity": "Gw9uTVTnJdhtczyuzBkL3X",
- "attribute": "7UiGr3qnjZfRuKs3F3CX61",
- "value": {
- "type": 1, // Text
- "value": "San Francisco"
- }
+---
+
+### 4.2 Relations
+
+Relations form the **edges** of the graph. They are compose of two components:
+
+1. **Lightweight Relation:** minimal, index-friendly fields
+2. **Relation Entity:** optional node carrying additional properties or types about the relationship itself
+
+#### 4.2.1 Lightweight Representation
+
+| Field | Type | Description |
+| -------------- | ----------- | --------------------------------------------------------------- |
+| `id` | bytes | Relation’s own UUID4 |
+| `type` | bytes | Relation-type UUID |
+| `from_entity` | bytes | Source entity UUID |
+| `from_space` | bytes ⋅opt | (optional) source Space UUID |
+| `from_version` | bytes ⋅opt | (optional) source Edit/Version UUID |
+| `to_entity` | bytes | Target entity UUID |
+| `to_space` | bytes ⋅opt | (optional) target Space UUID |
+| `to_version` | bytes ⋅opt | (optional) target Edit/Version UUID |
+| `entity` | bytes | UUID of the “relation entity” for attaching extra properties |
+| `position` | string ⋅opt | (optional) fractional position key for ordering |
+| `verified` | bool ⋅opt | (optional) whether the source space trusts the target reference |
+
+> **Immutability:** `id`, `type`, `from_entity`, and `to_entity` are fixed once created.
+> **Mutable:** `to_space`, `verified`, `index`, and the *relation entity*’s own values.
+
+#### 4.2.2 Relation Entity
+
+To annotate a relation (e.g. “joined on” date), the client creates the relation entity (UUID in `entity` field) and then issues `Value` edits against that entity.
+
+#### 4.2.3 Protobuf Snippet
+
+```proto
+message Relation {
+ bytes id = 1;
+ bytes type = 2;
+ bytes from_entity = 3;
+ optional bytes from_space = 4;
+ optional bytes from_version = 5;
+ bytes to_entity = 6;
+ optional bytes to_space = 7;
+ optional bytes to_version = 8;
+ bytes entity = 9;
+ optional string position = 10;
+ optional bool verified = 11;
}
+
```
-### 5. Native value types
+---
-There are 6 built in native value types defined as an enum. A princple used for naming the native types is to prioritize accessibility and familiarity for non-developers. There will be many different types of applications producing and consuming knowledge and the more consistent, familiar and accessible producing and consuming raw knowledge is, the more people will be able to participate in the knowledge economy.
+### 4.3 Types & Subtyping
-| Name | Value | Description |
-| --------------- |-------| --------------------------------------------------------- |
-| Text | 1 | A string of characters |
-| Number | 2 | A decimal value |
-| Checkbox | 3 | Can either be `true` or `false` |
-| URL | 4 | A URI to a resource with a protocol identifier |
-| Time | 5 | A date and time or interval |
-| Point | 6 | For geo locations or other coordinates |
+**Types** describe the structure of information. In an interconnected graph that can be used by any application, types should be helpful but not get in the way. Applications should be able to evolve independently without breaking others. The primary goal is composition and reuse. There should be a draw towards reuse and sharing, while empowering people to customize whatever they want. Every node implicitly has the `Entity` type.
+
+* **Types Relation:** each entity has zero or more outgoing `Types` relations.
+* **Subtyping:**
+
+ * **Broader types** → parent type(s)
+ * **Subtypes** inherit properties and relation-type hints from their broader types.
+
+| Type Property | Relation‹Type› ID |
+| ----------------- | -------------------------------------- |
+| **Properties** | `01412f83-8189-4ab1-8365-65c7fd358cc1` |
+| **Broader types** | `14df474e-4f48-4117-9619-d99e4b3afd3e` |
+
+---
+
+### 4.4 Properties
+
+A **Property** is itself an entity that defines an attribute name, its value type, and optional metadata.
+
+* **Default Type:** if omitted, `Text`
+* **Attributes of a Property entity:**
+
+| Name | Type | Description |
+| ---------------- | -------------- | ------------------------------------------------ |
+| **Value type** | Relation‹Type› | Entity ID indicating the native value type |
+| **Unit** | Relation‹Unit› | Optional unit (e.g., currency) |
+| **Format** | Text | Optional formatting string (ICU-style) |
+| **Has language** | Checkbox | Whether this property value is linguistic |
+
+| Property Type Name | Type | UUID |
+| ------------------ | ---- | -------------------------------------- |
+| Property | Type | `808a04ce-b21c-4d88-8ad1-2e240613e5ca` |
-The equivalent protobuf enum is:
```proto
-enum ValueType {
- TEXT = 1;
- NUMBER = 2;
- CHECKBOX = 3;
- URL = 4;
- TIME = 5;
- POINT = 6;
+message Property {
+ bytes id = 1; // property UUID
+ bytes type = 2; // should always be the Property-type ID
+ // values for Name, Value type, Unit, Format, Has language are stored as Values on this entity
}
```
-For each native value type, if a value is provided that is invalid, the triple should be dropped and treated as unset. Null cannot be provided as a value. Each native value type is UTF-8 encoded as a string.
+Once a property is published with a specific type, that type is immutable. If the user wants to change the type of a property, a new property should be created instead. By modeling Properties as first-class entities, the graph can evolve new attributes and users can share or extend schemas without coordination.
-#### 5.1 Text
+---
-An arbitrary length string of characters. Text may include newline characters or markdown. Clients may choose which attributes to support markdown for. Example: "Radiohead"
+This core model—Entities carrying Values, Relations linking nodes, Types governing schema, and reusable Property entities—forms the foundation for the GRC-20 knowledge graph.
-Options: `language`
+## 5. Native Value Types
-A language option can be provided to specify a language for the text. The language must be an entity ID for a Language entity. If no language is specified and the text is linguistic, it is assumed to be in US English.
+The GRC-20 standard defines six built-in “native” value types. Each is encoded as a UTF-8 string literal. If a value fails to conform to its type’s syntax, it is dropped (treated as unset); `null` is not permitted.
-#### 5.2 Number
+| Name | UUID | Description |
+| -------- | -------------------------------------- | ----------------------------------------------------- |
+| Text | `9edb6fcc-e454-4aa5-8611-39d7f024c010` | A sequence of Unicode characters |
+| Number | `9b597aae-c31c-46c8-8565-a370da0c2a65` | A decimal numeric value |
+| Checkbox | `7aa4792e-eacd-4186-8272-fa7fc18298ac` | A boolean flag (`true` or `false`) |
+| Time | `167664f6-68f8-40e1-976b-20bd16ed8d47` | An ISO-8601 timestamp or interval |
+| Point | `df250d17-e364-413d-9779-2ddaae841e34` | One or more comma-separated coordinates |
+| Relation | `4b6d9fc1-fbfe-474c-861c-83398e1b50d9` | One or more comma-separated coordinates |
+---
-Numbers are encoded as strings. One decimal point may be used. An optional negative sign (-) can be included at the beginning for negative values. No other symbols such as commas may be used. Additional metadata for units and formatting can be included as options.
+### 5.1 Text
-Examples:
-* "1234.56"
-* "-789.01"
+A `Text` value is an arbitrary-length UTF-8 string. It may include newlines or Markdown.
-Options: `format`, `unit`
+* **Validation:** any valid UTF-8 sequence
+* **Options:**
-The format option uses the ICU decimal format. For example:
-`¤#,##0.00` would render a value like `$1,234.56`.
+ * `language` (entity ID referencing a Language); defaults to US English if omitted and the text is linguistic
+* **Example:**
-The unit option can be included to define a specific currency or other unit to use. The value must be the entity ID of a Currency or Unit entity.
+ ```json
+ "Radiohead"
+ ```
-Additional attributes can be added to Number attributes to specify hints for database optimizations. This can allow application developers to add additional constraints that can be useful for choosing more efficient storage types.
+---
-#### 5.3 Checkbox
+### 5.2 Number
-A checkbox can either be `true` or `false`. It's a boolean field named for normal people. The string encoding of the checkbox field must be "1" for `true` and "0" for `false`. Checkbox values can be rendered with alternate UI components such as switches and toggles.
+A `Number` value is a UTF-8 string representing a decimal number.
-#### 5.4 URL
+* **Syntax:**
-A URL value type is technically a URI that starts with the protocol identifier followed by a :// and the resource. The initial supported protocols are: graph, ipfs, ar, https.
+ * Optional leading `-` for negatives
+ * Digits plus at most one `.`
+ * No commas or currency symbols
+* **Options:**
-Examples:
-* "ipfs://QmVGF2e9WqF8g39W81eCQxecz7Bdi5o2DFSJ5BQxwfveYB"
-* "https://geobrowser.io"
+ * `format` (ICU decimal format string, e.g. `¤#,##0.00`)
+ * `unit` (entity ID for a currency or measurement unit)
+* **Examples:**
-#### 5.5 Time
+ ```json
+ "1234.56"
+ "-789.01"
+ ```
-Time is represented as an ISO-8601 format string. A time value can be used to describe both date and time as well as durations. Clients should include timezones when creating times. In rare exceptions, if the timezone is omitted, the time is interpreted as being in the consumer's local time. Example: `2024-11-03T11:15:45.000Z`
+---
+
+### 5.3 Checkbox
+
+A `Checkbox` is a boolean encoded as:
+
+* `"1"` = `true`
+* `"0"` = `false`
+
+Clients may render it as a switch or toggle.
+
+---
+
+### 5.4 URL
+
+A `URL` is any valid URI beginning with a supported protocol and `://`.
+
+* **Supported protocols:** `graph`, `ipfs`, `ar`, `https`
+* **Examples:**
-Options: `format`
+ ```json
+ "ipfs://QmVGF2e9WqF8g39W81eCQxecz7Bdi5o2DFSJ5BQxwfveYB"
+ "https://geobrowser.io"
+ ```
-A format string using the [Unicode Technical Standard #35](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table).
+---
+
+### 5.5 Time
+
+A `Time` value is an ISO-8601 string representing a timestamp or duration.
+
+* **Recommendation:** include a timezone; if omitted, interpret in the consumer’s local time
+* **Options:**
+
+ * `format` A format string using the [Unicode Technical Standard #35](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table).
+
+* **Example value:**
+
+ ```json
+ "2024-11-03T11:15:45.000Z"
+ ```
+* **Example formats:**
Examples:
+
* `h:mmaaa, EEEE, MMMM d, yyyy` - 4:45pm, Thursday, July 4, 2024
* `h:mmaaa, MMMM d, yyyy` - 4:45pm, July 4, 2024
* `h:mmaaa, MMM d, yyyy` - 4:45pm, Jul 4, 2024
@@ -192,343 +370,851 @@ Examples:
* `MM/dd/yy` - 07/04/24
* `h:mmaaa` - 4:45pm
-#### 5.6 Point
-
-A point is a location specified with x and y coordinates string encoded. Points can be used for geo locations or other cartesian coordinate systems. Clients may choose how many dimensions to support. Example: `"12.554564, 11.323474"`
+---
-The value must have valid decimal numbers separated by a comma. A space after the comma is optional. For geo locations, the latitude and longitude must be provided with latitude first. Positive/negative signs indicate north/south for latitude and east/west for longitude respectively.
+### 5.6 Point
-### 6. Types
+A `Point` is a coordinate or vector encoded as comma-separated decimal numbers.
-Types describe the structure of information. In an interconnected graph that can be used by any application, types should be helpful but not get in the way. Applications should be able to evolve independently without breaking others. The primary goal is composition and reuse. There should be a draw towards reuse and sharing, while empowering people to customize whatever they want.
+* **Syntax:** one or more numeric values (e.g. `x,y` or `x,y,z`); optional space after commas
+* **Geolocation convention:** latitude, longitude (positive north/east; negative south/west)
+* **Example:**
-Every entity has an implicit Types relation and can have zero, one or many types.
+ ```json
+ "12.554564, 11.323474"
+ ```
-| Name | Type | ID |
-| --------- |------|----------------------- |
-| Type | Type | Jfmby78N4BCseZinBmdVov |
+### 5.7 Renderable types
-Types may have zero, one or many attributes and relation types defined on them.
+In addition to the native types, renderable types are defined at the knowledge layer to describe to clients how to render certain properties. For example URLs are stored as Text datatypes but rendered as URLs.
-| Name | Type | ID |
-| -------------- |---------------------------|----------------------- |
-| Attributes | Relation \ | 9zBADaYzyfzyFJn4GU1cC |
-| Relation Types | Relation \ | TarUQath6Kyh3jfnRv3hy7 |
+## 6. Identifiers
-### 7. Attributes
+Every core object in the GRC-20 graph (Entities, Relations, Types, Properties, Edits, etc.) is referenced by a **globally unique identifier**. To ensure decentralization, interoperability, and minimal collision risk, we adopt **UUID version 4** for all IDs.
-Entities have attributes which are themselves defined as entities. An attribute describes a property of an entity.
+### 6.1 UUID Generation
-| Name | Type | ID |
-| --------------- |------|----------------------- |
-| Attribute | Type | GscJ2GELQjmLoaVrYyR3xm |
+* **Standard:** RFC 4122, version 4 (random).
+* **Entropy Source:** Cryptographically secure random number generator.
+* **Collision Risk:** Negligible at 2⁻¹²²; no central coordination or registration required.
-The Attribute type has the following attributes:
+### 6.2 On-Wire (Binary) Encoding
-| Name | Type | Description |
-| -------------- |--------| -------------------------------------------------------------------- |
-| Value Type | Text | The type ID a triple for this attribute should have. There are entities for the native types |
+* **Format:** 16-byte array, network byte order (big-endian).
+* **Protobuf Definition:**
-Attributes are used for native types like Text, Number and Time. The Value Types should reference the entity IDs created for the native types.
+ ```proto
+ // Any `bytes id = 1;` field carries a raw 16-byte UUID4.
+ message SomeEntity {
+ bytes id = 1; // 16 bytes
+ // …
+ }
+ ```
-| Name | ID |
-| ------------| ---------------------- |
-| Value Type | WQfdWjboZWFuTseDhG5Cw1 |
+### 6.3 JSON & String Representation
-The native type IDs are:
+* **Canonical Form:** 36-character, lowercase hexadecimal string with dashes.
+* **Example:**
-| Name | ID |
-| -------------| ---------------------- |
-| Text | LckSTmjBrYAJaFcDs89am5 |
-| Number | LBdMpTNyycNffsF51t2eSp |
-| Checkbox | G9NpD4c7GB7nH5YU9Tesgf |
-| URL | 5xroh3gbWYbWY4oR3nFXzy |
-| Time | 3mswMrL91GuYTfBq29EuNE |
-| Point | UZBZNbA7Uhx1f8ebLi1Qj5 |
+ * Standard UUID4: `2a5fe010-078b-4ad6-8a61-7272f33729f4`
-### 8. Relations
+### 6.4 ID Conversion
-Relations describe the edges of a graph. Relations are themselves entities that include details about the relationship. For example a Company can have Team Members. Each Team Member relation can have an attribute describing when the person joined the team. This is a model that is commonly called a property graph.
+For systems that already emit long or proprietary unique IDs, map them deterministically into GRC-20 UUID4s:
-Relations are ordered. They can be reordered independently without conflicts using Fractional Indexing with an arbitrary level of precision between the indices of the items the user wants to move the item between. A fractional index must include randomness to allow items to be inserted between items with minimal chance of collision. This way moving the order of an item doesn't require changing the index of any of the other items.
+1. Compute the MD5 hash of the original ID string (UTF-8).
+2. Use the 16-byte MD5 digest to seed a UUID4 generator (i.e., set version bits to 4, variant bits per RFC 4122).
+3. Encode the resulting UUID as 16-byte wire format or hex string.
-Relations must have Type: Relation
+This process yields a stable, collision-resistant UUID for any existing globally unique identifier.
-| Name | Type | ID |
-| ------------ |-----------|----------------------- |
-| Relation | Type | QtC4Ay8HNLwSd1kSARgcDE |
+---
-A relation has the following attributes:
+By enforcing a single, decentralized UUID4 scheme—binary on-wire and dash-stripped in text—GRC-20 ensures all nodes and edges can reference each other unambiguously across spaces, chains, and storage layers.
-| Name | Type | Description |
-| ------------ |--------| ------------------------------------------------------------------------------ |
-| From entity | Text | The entity ID this relation is from |
-| To entity | Text | The entity ID this relation is pointing to |
-| Index | Text | An alphanumeric fractional index describing the relative position of this item |
+## 7. Spaces & Governance
-| Name | Type | ID |
-| --------------- |-----------|----------------------- |
-| From entity | Attribute | RERshk4JoYoMC17r1qAo9J |
-| To entity | Attribute | Qx8dASiTNsxxP3rJbd4Lzd |
-| Index | Attribute | WNopXUYxsSsE51gkJGWghe |
+A **Space** encapsulates a self-contained knowledge graph along with its governance and access-control rules. Spaces let communities or individuals manage who can read, write, and anchor edits under a consistent policy.
-From entity, To entity and Index are required.
+---
-#### 8.1 Relation Types
+### 7.1 Space Categories
-A Relation Type is a definition of a relation similar to an attribute but specifically for one to one, one to many, and many to many relations. A Relation Type can have a name like `Team member`, `City` or a more graph style name like `Born in`. The relevent Relation Types are added as types along with the `Relation` type to a relation. Adding Relation Types to Relations is optional but strongly encouraged. An individual relation cannot have more than one Relation Type.
+* **Personal Spaces**
-| Name | Type | ID |
-| ------------- |-----------|----------------------- |
-| Relation Type | Type | 3WxYoAVreE4qFhkDUs5J3q |
+ * **Onchain only:** backed by a deployed smart contract.
+ * **Custom access controls:** personal spaces are publicly visible but centrally controlled by an individual or entity.
-A Relation Type is also of type `Type` and has the following attributes:
+* **Public Spaces**
-| Name | Type | Description |
-| ------------------------ |-------------------| ------------------------------------------------------------------------------ |
-| Relation value types | Relation \ | A list of types that the relation To entity may have. Used as a hint |
-| One max | Checkbox | Whether to limit the number of relations from a given entity to no more than 1 |
+ * **Onchain only:** backed by a deployed smart contract.
+ * **Public governance:** proposals, voting, and execution enforced by onchain rules.
-| Name | Type | ID |
-| ------------------------ |---------------|----------------------- |
-| Relation value types | Relation Type | SeDR2b1bdnb6tj2qmdcFdg |
-| One max | Checkbox | K1M9AEyda5oNB2WS38bDDW |
+* **Private Spaces**
-The term properties is used to describe the union of an entity's attributes and relation types.
+ * **Local-first:** operate entirely on a user’s device; edits queue offline.
+ * **Shared peer-to-peer:** propagate changes within a trusted group.
-### 9. Implicit entity properties
+---
-All entities implicitly have the Entity type which contains the following properties:
+### 7.2 Lifecycle & Conversion
-| Name | Type | Description |
-| --------------- |--------------------| --------------------------------------------------------- |
-| Name | Text | The name that shows up wherever this entity is referenced |
-| Types | Relation \ | The one or many types that this entity has |
-| Description | Text | A short description that is often shown in previews |
-| Cover | Image | A banner style image that is wide and conveys the entity |
-| Blocks | Relation \ | The blocks of rich content associated with this entity |
+Any entity can evolve into a Space when it requires its own governance:
-The ideal cover image dimensions is 2384x640px though other dimensions can be used.
+1. **Promote an Entity:** choose an existing entity UUID.
+2. **Deploy Space Contract:** publish a smart contract (L1 or L2) encoding roles, voting, or ACLs.
+3. **Bind Entity to Contract:** map the entity’s UUID to the contract address, enabling onchain anchoring.
+4. **Migrate Edits:** replay or import prior edits into the new Space (see §11 Importing & Migrations).
-| Name | ID |
-| ------------| ---------------------- |
-| Name | LuBWqZAu6pz54eiJS5mLv8 |
-| Types | Jfmby78N4BCseZinBmdVov |
-| Description | LA1DqP5v6QAdsgLPXGF3YA |
-| Cover | 7YHk6qYkNDaAtNb8GwmysF |
-| Blocks | QYbjCM6NT9xmh2hFGsqpQX |
+---
+### 7.3 Space Type
-### 10. System properties
+We model Space itself as a special **Type** so it can be referenced, inherited, and extended like any other schema element.
-System derived properties are not serialized but they are part of the standard for data that is computed by indexers and made available on entities. Clients should show these fields as non-editable.
+| Name | Type | UUID |
+| ----- | ---- | -------------------------------------- |
+| Space | Type | `362c1dbd-dc64-44bb-a3c4-652f38a642d7` |
-| Name | Type | Description |
-| -------------- |---------------------| --------------------------------------------------------------------------------------- |
-| Created at | Time | The time this entity was first seen by the indexer |
-| Updated at | Time | The most recent time this entity was updated by the indexer |
-| Created by | Text | The blockchain address of the account that signed the transaction to create this entity |
-| Versions | Relation \ | A reference to previous versions of this entity |
+---
+### 7.4 Space Hierarchy
-### 11. Space type
+Spaces can form hierarchies via relations. Their UUIDs are defined in the UUID glossary (Appendix §13).
-A space is also a type but public and personal spaces are special because they also include the deployment of a smart contract for governance and access controls. Any entity can also be a space. Once enough interest and specialization forms around an entity, it can be converted into its own space with its own governance.
+| Property | Relation‹Space› | Description |
+| ------------------ | --------------- | -------------------------------------------- |
+| **Broader spaces** | parent space(s) | The immediate parent(s) in a space hierarchy |
+| **Subspaces** | child space(s) | More specialized or granular subdomains |
-| Name | Type | ID |
-| --------- |------|----------------------- |
-| Space | Type | 7gzF671tq5JTZ13naG4tnr |
+This convention—Broader/Sub—mirrors natural language (“this is a subspace of that”) and lets clients traverse up or down a space tree.
-A space has the following properties:
+---
-| Name | Type | Description |
-| --------------- |--------------------| ------------------------------------------------------------------ |
-| Broader spaces | Relation \ | The spaces that this is a subspace of |
-| Subspaces | Relation \ | Spaces that are more granular for drilling down |
+### 7.5 Governance & Access Controls
-The Broader [thing] and Sub[thing] is a convention for relations to denote drilling down or up when something is hierarchical, chosen for natural language. The Broader spaces and Subspaces relations are system properties that can be queried as standard properties but are derived from the space contracts.
+* **Public Spaces (On-Chain):**
-### 12. Entity content types
+ * Smart contracts define who can propose, endorse, or apply edits.
-A separate Content spec will be provided with a standard set of content types. Two types are specified here since they are referenced in the _Implicit entity properties_ section.
+* **Personal Spaces:**
-#### 12.1 Image
+ * Client libraries enforce local ACLs (e.g., device keys, group permissions).
-Images are defined as a type with properties that can be used for provenance, attribution and other metadata. This way images can be reused in many places with proper attribution.
+* **Private Spaces (Off-Chain):**
-| Name | Type | Description |
-| -------------- |-------------------------------| ------------------------------------------------ |
-| Width | Number | The width in pixels |
-| Height | Number | The height in pixels |
+ * Peer-to-peer protocols carry edits; conflicts resolved via the same ordered Ops (§10).
-| Name | Type | ID |
-| ---------- |------|----------------------- |
-| Image | Type | Q1LaZhnzj8AtCzx8T1HRMf |
+Indexers and clients **must** respect each Space’s governance policy when accepting, anchoring, and indexing edits.
-#### 12.2 Block
+## 8. Serialization & Encoding
-Every entity can have blocks comprising the content for a page. Apps can choose to support different block types. The standard set of block types will be published in the Content spec.
+GRC-20 uses Protocol Buffers (proto3) for all core serialization, ensuring compact, language-neutral messages. For human-facing APIs or debugging, clients may also emit and consume equivalent JSON representations, following the conventions below.
-| Name | Type | ID |
-| ---------- |---------------|----------------------- |
-| Block | Relation Type | QYbjCM6NT9xmh2hFGsqpQX |
+---
-### 13. Ops
+### 8.1 Protocol Buffer Definitions
-An op represents a single atomic operation that produces or modifies knowledge. Ops are provided as an ordered list and must be processed in sequence.
+> **All** implementations **must** use these proto3 schemas verbatim to guarantee cross-language interoperability. Full definitions, including option messages (`TextOptions`, `NumberOptions`, `TimeOptions`, etc.), appear in Appendix §13.
```proto
+syntax = "proto3";
+package grc20;
+
+// --- Core Objects ---
+
+message Entity {
+ bytes id = 1; // 16-byte UUID4
+ repeated Value values = 2;
+}
+
+message Value {
+ bytes property = 1; // Property UUID
+ string value = 2; // UTF-8 literal
+ oneof options {
+ TextOptions text_options = 3;
+ NumberOptions number_options = 4;
+ }
+}
+
+message Relation {
+ bytes id = 1;
+ bytes type = 2;
+ bytes from_entity = 3;
+ optional bytes from_space = 4;
+ optional bytes from_version = 5;
+ bytes to_entity = 6;
+ optional bytes to_space = 7;
+ optional bytes to_version = 8;
+ bytes entity = 9;
+ optional string position = 10;
+ optional bool verified = 11;
+}
+
+message RelationUpdate {
+ bytes id = 1;
+ optional bytes from_space = 2;
+ optional bytes from_version = 3;
+ optional bytes to_space = 4;
+ optional bytes to_version = 5;
+ optional string position = 6;
+ optional bool verified = 7;
+}
+
+message UnsetRelationFields {
+ bytes id = 1;
+ optional bool from_space = 2;
+ optional bool from_version = 3;
+ optional bool to_space = 4;
+ optional bool to_version = 5;
+ optional bool position = 6;
+ optional bool verified = 7;
+}
+
+enum DataType {
+ TEXT = 0;
+ NUMBER = 1;
+ CHECKBOX = 2;
+ TIME = 3;
+ POINT = 4;
+ RELATION = 5;
+}
+
+message Property {
+ bytes id = 1; // property UUID
+ DataType data_type = 2;
+}
+
+// --- Operations & Versioning ---
+
message Op {
- OpType type = 1;
- Triple triple = 2;
+ oneof payload {
+ Entity update_entity = 1;
+ Relation create_relation = 2;
+ RelationUpdate update_relation = 3;
+ bytes delete_relation = 4;
+ Property create_property = 5;
+ UnsetEntityValues unset_entity_values = 6;
+ UnsetRelationFields unset_relation_fields = 7;
+ }
}
-```
-| Name | Value |
-| ---------------------- |-------|
-| Set triple | 1 |
-| Delete triple | 2 |
+message Edit {
+ bytes id = 1;
+ string name = 2;
+ repeated Op ops = 3;
+ repeated bytes authors = 4;
+ optional bytes language = 5;
+}
-```proto
-enum OpType {
- SET_TRIPLE = 1;
- DELETE_TRIPLE = 2;
+message ImportEdit {
+ bytes id = 1;
+ string name = 2;
+ repeated Op ops = 3;
+ repeated bytes authors = 4;
+ bytes created_by = 5;
+ string created_at = 6;
+ bytes block_hash = 7;
+ string block_number = 8;
+ bytes transaction_hash = 9;
}
-```
-#### 13.1 Set triple
+message Import {
+ // these strings are IPFS cids representing the import edit message
+ repeated string edits = 1;
+}
-When the OpType is `Set triple`, all 3 EAV fields of the triple must be included.
+message File {
+ string version = 1;
-| Name | Value | Description |
-| --------------- |-------| -------------------------------------------------- |
-| Entity | 1 | The entity ID for the triple that's being created |
-| Attribute | 2 | The attribute ID for the triple being created |
-| Value | 3 | A value with type, value, and optional options |
+ oneof payload {
+ Edit add_edit = 2;
+ Import import_space = 3;
+ bytes archive_space = 4;
+ }
+}
-#### 13.2 Delete triple
+---
-When the OpType is `Delete triple`, just the EA fields of the triple should be included.
+### 8.2 JSON Interchange Conventions
-| Name | Value | Description |
-| --------------- |-------| ----------------------------------------- |
-| Entity | 1 | The entity ID to delete the triple for |
-| Attribute | 2 | The attribute ID to delete the triple for |
+When exposing HTTP/REST or CLI interfaces, clients may map Protobuf messages to JSON with these rules:
-### 14. Edits
+* **`bytes` fields** → lowercase, dash-stripped hex strings
+* **`enum` fields** → numeric values
+* **`oneof`** → include only the present option
+* **`repeated`** → JSON arrays
-Changes are published to the knowledge graph through `edits`. An edit can include any number of changes to any entity in a space.
+#### 8.2.1 Example: Entity
-| Name | Type | Value | Description |
-| --------------- |-----------------|-------| --------------------------------------------------------- |
-| Version | string | 1 | A semver version string |
-| Type | ActionType | 2 | The type of action this edit is encoding |
-| ID | string | 3 | A valid ID representing this edit |
-| Name | string | 4 | The name of the edit (short commit message) |
-| Ops | Op[] | 5 | A list of triple operations to perform |
-| Authors | string[] | 6 | The list of authors who worked on this edit |
+```json
+{
+ "id": "2a5fe010-078b-4ad6-8a61-7272f33729f4",
+ "values": [
+ {
+ "property": "6ab0887f-b6c1-4628-9eee-2234a247c1d2",
+ "value": "San Francisco"
+ }
+ ]
+}
+```
-The corresponding protobuf message is:
+#### 8.2.2 Example: Relation
-```proto
-message Edit {
- string version = 1;
- ActionType type = 2;
- string id = 3;
- string name = 4;
- repeated Op ops = 5;
- repeated string authors = 6;
+```json
+{
+ "id": "29785ffb-5ce6-4a9b-b0dc-b138328ba334",
+ "type": "0509279a-713d-4667-a412-24fe3757f554",
+ "from_entity": "2a5fe010-078b-4ad6-8a61-7272f33729f4",
+ "to_entity": "386d9dde-4c10-4099-af42-0e946bf2f199",
+ "entity": "7f9b1c0a-9fbc-4d63-a2d3-da5c1e1a2b3c",
+ "position": "a",
+ "verified": false
}
+
```
-#### Example Edit in JSON
+#### 8.2.3 Example: Edit
-```jsonc
+```json
{
"version": "1.0.0",
- "type": 1, // Add edit
- "id": "JVrauVCjqsuKqArK3dutYb",
+ "type": 1,
+ "id": "386d9dde-4c10-4099-af42-0e946bf2f199",
"name": "Add a new city",
"ops": [
{
- "type": 1, // Create triple
- "triple": {
- "entity": "Gw9uTVTnJdhtczyuzBkL3X",
- "attribute": "7UiGr3qnjZfRuKs3F3CX61",
- "value": {
- "type": 1, // Text
+ "type": 2,
+ "entity": {
+ "id": "29785ffb-5ce6-4a9b-b0dc-b138328ba334",
+ "values": [
+ {
+ "property": "7f9b1c0a-9fbc-4d63-a2d3-da5c1e1a2b3c",
"value": "San Francisco"
- }
+ }
+ ]
}
}
],
- "authors": ["7UiGr3qnjZfRuKs3F3CX61"]
+ "authors": ["0x1A39E2Fe299Ef8f855ce43abF7AC85D6e69E05F5"],
+ "language": "en"
}
```
-### 15. Imports
+#### 8.2.4 Example: Import
-Spaces are abstracted from the underlying infrastructure. A space contract can be deployed on one L2 and then move to another L2. An import file includes all of the data from a previous space and can be used to bootstrap the space in the new environment.
+```json
+{
+ "version": "1.0.0",
+ "type": 4,
+ "previousNetwork": "Ethereum Mainnet",
+ "previousContractAddress": "0x1A39E2Fe299Ef8f855ce43abF7AC85D6e69E05F5",
+ "edits": [
+ "ipfs://QmVGF2e9WqF8g39W81eCQxecz7Bdi5o2DFSJ5BQxwfveYB"
+ ]
+}
+```
+
+---
+
+By combining a compact binary format for production with clear JSON fallbacks, GRC-20 ensures both performance and ease of integration across diverse environments.
+
+## 9. System & Implicit Properties
+
+Entities in GRC-20 carry two classes of built-in properties:
+
+1. **Implicit Entity Properties** – always present on every entity, exposed to clients as editable fields.
+2. **System Properties** – computed by indexers, read-only to clients.
+
+---
+
+### 9.1 Implicit Entity Properties
+
+Every entity automatically has these core fields. Clients **must** render them alongside any user-defined properties.
+
+| Name | Type | Description | UUID |
+| --------------- | --------------- | ---------------------------------------------------------------------- | -------------------------------------- |
+| **Name** | Text | Human-readable label for the entity | `a126ca53-0c8e-48d5-b888-82c734c38935` |
+| **Types** | Relation‹Type› | Zero or more classification types assigned to the entity | `8f151ba4-de20-4e3c-9cb4-99ddf96f48f1` |
+| **Description** | Text | Brief summary shown in previews or tooltips | `9b1f76ff-9711-404c-861e-59dc3fa7d037` |
+| **Cover** | Image | Wide banner image conveying the entity | `34f53507-2e6b-42c5-a844-43981a77cfa2` |
+| **Blocks** | Relation‹Block› | Ordered content blocks (rich text, media, etc.) attached to the entity | `beaba5cb-a677-41a8-b353-77030613fc70` |
+
+> **Cover Image Guidelines:**
+>
+> * Recommended dimensions: **2384 × 640 px** (other aspect ratios allowed)
+> * Clients should fetch image metadata (width/height) via the Image content spec before rendering.
+
+---
+
+### 9.2 System Properties
+
+These properties are **not** serialized in edits or exports. Indexers compute and populate them; clients **must** display them as read-only.
+
+| Name | Type | Description |
+| -------------- | ----------------- | -------------------------------------------------------------------------------------------- |
+| **Created at** | Time | Timestamp when the entity was first indexed |
+| **Updated at** | Time | Timestamp of the most recent edit applied |
+| **Created by** | Text | Blockchain address (or key ID) of the author who anchored the creating edit |
+| **Versions** | Relation‹Version› | References to prior `Edit` versions for this entity (e.g., for history or rollback purposes) |
+
+> **Note:** Clients should fetch `Versions` relations to present an edit history or allow “undo” operations, but must not modify these relations directly.
+
+## 10. Edits, Imports & Operations
+
+This section specifies how atomic changes (“Ops”) are composed into versioned edits, how full-space migrations are handled, and how all payloads are enveloped for IPFS storage.
+
+---
+
+### 10.1 Operations (`Op`)
+
+An **Op** is the smallest unit of change. It uses a `oneof` payload so each operation is unambiguous:
+
+```proto
+message Op {
+ oneof payload {
+ Entity update_entity = 1; // Create or upsert an entity’s values
+ bytes delete_entity = 2; // Remove an entity and its values
+ Relation create_relation = 3; // Add a new graph edge
+ RelationUpdate update_relation = 4; // Modify mutable edge fields
+ bytes delete_relation = 5; // Remove an edge link
+ UnsetEntityValues unset_entity_values = 6; // Remove specific properties from an entity
+ UnsetRelationFields unset_relation_fields = 7; // Clear specific fields on a relation
+ }
+}
+```
+
+* **`update_entity`**: carries a full `Entity` message with its `id` and new `values`.
+* **`delete_entity`**: the entity’s `id` to remove.
+* **`create_relation`** / **`update_relation`** / **`delete_relation`**: manage the lifecycle of relations, with `Relation` and `RelationUpdate` messages.
+* **`unset_entity_values`**: lists property-UUIDs to clear on an entity without deleting it.
+* **`unset_relation_fields`**: lists relation fields (`from_space`, `position`, etc.) to clear.
+
+---
+
+### 10.2 Edit
+
+An **Edit** packages one or more Ops into a single change set:
+
+```proto
+message Edit {
+ bytes id = 1; // UUID4 of this edit
+ string name = 2; // Short “commit” summary
+ repeated Op ops = 3; // Ordered operations
+ repeated bytes authors = 4; // UUIDs of contributors
+ optional bytes language = 5; // Default language tag for Text values
+}
+```
+
+* **`id`**: uniquely identifies the edit for de-duplication and history.
+* **`name`**: human-friendly description (e.g. “Add city entity”).
+* **`ops`**: must be applied in sequence by indexers.
+* **`authors`**: supports multi-authoring and attribution.
+* **`language`**: if set, applies to all Text values lacking individual language tags.
+
+Indexers deserialize each `Edit`, apply its `ops` in order, and record the edit’s `id` to support potential rollbacks or forks.
+
+---
+
+### 10.3 ImportEdit
+
+For onchain migrations or space bootstrapping, an **ImportEdit** extends `Edit` with blockchain metadata:
+
+```proto
+message ImportEdit {
+ bytes id = 1; // Edit UUID4
+ string name = 2;
+ repeated Op ops = 3;
+ repeated bytes authors = 4;
+ bytes created_by = 5; // Address or key ID that anchored this import
+ string created_at = 6; // ISO-8601 timestamp
+ bytes block_hash = 7; // Onchain block hash
+ string block_number = 8; // Block number as decimal string
+ bytes transaction_hash = 9; // Transaction hash anchoring the import
+}
+```
+
+Each `ImportEdit` encapsulates a full replay of prior edits along with provenance data, allowing downstream indexers to reconstruct not only state but the exact onchain context.
+
+---
+
+### 10.4 Import Manifest
+
+A lightweight **Import** manifest lists the IPFS CIDs of one or more `ImportEdit` messages:
```proto
message Import {
- string version = 1;
- ActionType type = 2;
- string previousNetwork = 3;
- string previousContractAddress = 4;
- repeated string edits = 5;
+ repeated string edits = 1; // IPFS CIDs, in chronological order
+}
+```
+
+Clients upload `ImportEdit` payloads to IPFS, collect their CIDs, then publish this manifest. Indexers fetch each CID, parse the corresponding `ImportEdit`, and apply its `ops` in sequence.
+
+---
+
+### 10.5 File Payload Envelope
+
+All edits, imports, and archival actions are wrapped in an **`File`** envelope for storage and retrieval:
+
+```proto
+message File {
+ string version = 1; // Spec version, e.g. "1.0.0"
+ oneof payload {
+ Edit add_edit = 2; // New content update
+ Import import_space = 3; // Migration manifest
+ bytes archive_space = 4; // Raw CID for archival marker
+ }
+}
+```
+
+* **`version`** ensures clients can detect deprecated formats.
+* **`add_edit`** carries an `Edit` to append to the space.
+* **`import_space`** carries an `Import` manifest for migrations.
+* **`archive_space`** is a raw CID indicating the archival of a space (no further edits).
+
+Clients and indexers must parse the `payload` one-of to dispatch accordingly:
+
+* On **`add_edit`**, apply the contained `Edit`.
+* On **`import_space`**, fetch and replay each `ImportEdit` in the manifest.
+* On **`archive_space`**, mark the space as read-only.
+
+---
+
+With this model—fine-grained Ops, concise Edits, metadata-rich ImportEdits, and a unified IPFS envelope—GRC-20 provides a clear, verifiable, and extensible mechanism for producing and evolving decentralized knowledge graphs.
+
+
+## 11. Imports & Migrations
+
+When a Space must be bootstrapped from—or migrated to—a new environment (e.g. L2 upgrade, new chain), we use **ImportEdit** messages and a lightweight **Import** manifest, all wrapped in the standard IPFS envelope. This section shows the updated definitions, workflow, and examples.
+
+---
+
+### 11.1 `ImportEdit`
+
+An `ImportEdit` is a special edit that replays one or more prior Ops **and** carries onchain provenance metadata:
+
+```proto
+message ImportEdit {
+ // Core edit fields
+ bytes id = 1; // UUID4 of this import-edit
+ string name = 2; // e.g. “Import from Mainnet v1”
+ repeated Op ops = 3; // All ops to replay
+ repeated bytes authors = 4; // UUIDs or addresses of original authors
+
+ // Onchain context
+ bytes created_by = 5; // Address or key ID that anchored this import
+ string created_at = 6; // ISO-8601 timestamp of the anchor tx
+ bytes block_hash = 7; // Hash of the block containing the anchor
+ string block_number = 8; // Decimal block number
+ bytes transaction_hash = 9; // Tx hash anchoring the import
}
```
-#### Example Import in JSON
+* **`ops`** should replay the exact sequence of original edits.
+* **`created_by`**, **`created_at`**, **`block_hash`**, **`block_number`**, and **`transaction_hash`** allow indexers to verify and audit the import against the target chain.
+
+---
+
+### 11.2 `Import` Manifest
+
+A minimal manifest that lists the IPFS CIDs of one or more `ImportEdit` payloads:
+
+```proto
+message Import {
+ // IPFS CIDs of ImportEdit messages, in chronological order
+ repeated string edits = 1;
+}
+```
+
+* Clients assemble this after uploading each `ImportEdit`; they need only publish the manifest.
+
+---
+
+### 11.3 Workflow
+
+1. **Deploy New Space Contract**
+ Release your Space contract on the target chain or L2.
+
+2. **Generate `ImportEdit` Messages**
+ For each batch of historic Ops (e.g. per original block or logical grouping), create an `ImportEdit` that replays those Ops and fills in the onchain metadata from the source network.
+
+3. **Publish to IPFS**
+
+ * Serialize each `ImportEdit` as raw protobuf.
+ * Upload to IPFS; note each resulting CID (e.g. `QmAbC123…`).
+
+4. **Construct `Import` Manifest**
+
+ ```proto
+ Import {
+ edits: [
+ "QmAbC123…",
+ "QmXyZ789…",
+ …
+ ]
+ }
+ ```
+
+5. **Envelope in `File`**
+
+ ```proto
+ File {
+ version: "1.0.0";
+ payload {
+ import_space: ;
+ }
+ }
+ ```
+
+6. **Anchor on-Chain**
+ Submit a transaction to the new Space contract that records the CID of the `File` envelope (with `import_space` payload).
+
+7. **Index & Replay**
+
+ * Indexers detect the onchain anchor, fetch the `File`, and parse out `import_space`.
+ * For each CID in `Import.edits`, fetch the corresponding `ImportEdit`, deserialize it, and apply its `ops` in order.
+ * Record imported edit IDs to support deduplication and provenance queries.
+
+8. **Verify State**
+ Confirm the reconstructed graph matches the original Space’s index on the source chain.
+
+---
+
+### 11.4 JSON Examples
+
+#### 11.4.1 Import Manifest
```json
{
- "version": "1.0.0",
- "type": "import",
- "previousNetwork": "7UiGr3qnjZfRuKs3F3CX61",
- "previousContract": "0x1A39E2Fe299Ef8f855ce43abF7AC85D6e69E05F5",
"edits": [
- "ipfs://QmVGF2e9WqF8g39W81eCQxecz7Bdi5o2DFSJ5BQxwfveYB"
+ "ipfs://QmAbC123…",
+ "ipfs://QmXyZ789…"
]
}
```
-### 16. Action Types
+#### 11.4.2 `File` Envelope
+
+```json
+{
+ "version": "1.0.0",
+ "payload": {
+ "import_space": {
+ "edits": [
+ "ipfs://QmAbC123…",
+ "ipfs://QmXyZ789…"
+ ]
+ }
+ }
+}
+```
+
+Clients and indexers following this pattern gain a transparent, auditable migration path—preserving both content and onchain context—while minimizing onchain footprint.
+
-Actions are logical functions that can be performed on a space in different environments. Public spaces should secure these actions behind a public governance system, personal spaces can secure these actions behind an access control system, and private spaces can run these actions locally. Actions can be used to describe a log of user intents as well as a log of a space's accepted actions.
+## 12. Entity Content Types
+
+Certain content-rich entities (e.g. videos, pdfs) rely on specialized types. A full Content Spec will define a comprehensive set; here we introduce the two types referenced by implicit entity properties (§9).
+
+---
+
+### 12.1 Image
+
+An **Image** entity encapsulates an asset plus metadata for provenance, attribution, and rendering. Clients store or retrieve the binary via a URL/URI property (e.g. IPFS or HTTP), then use these properties for layout or display.
+
+| Property | Value Type | Description | UUID |
+| -------- | ---------- | ---------------------- | -------------------- |
+| Width | Number | Image width in pixels | (Native Number type) |
+| Height | Number | Image height in pixels | (Native Number type) |
+
+| Name | Type | UUID |
+| ----- | ---- | -------------------------------------- |
+| Image | Type | `772172cb-7abf-422e-8b8b-10ef17738402` |
+
+Clients **must** include Width and Height when known; this enables correct aspect-ratio rendering before full asset download.
+
+---
+
+### 12.2 Block
+
+A **Block** represents a discrete piece of rich content—text, media embed, code snippet, etc.—that together form the body of a page or document. Blocks are ordered via relations to the parent entity.
+
+| Name | Type | UUID |
+| ----- | ------------- | -------------------------------------- |
+| Block | Relation Type | `beaba5cb-a677-41a8-b353-77030613fc70` |
+
+Each Block relation points to a separate content-typed entity (defined in the Content Spec). Clients render Blocks in ascending fractional index order (§4.2).
+
+---
+
+## 13. Appendix
+
+### 13.1 Complete Protobuf Schemas
```proto
-enum ActionType {
- ADD_EDIT = 1;
- ADD_SUBSPACE = 2;
- REMOVE_SUBSPACE = 3;
- IMPORT_SPACE = 4;
- ARCHIVE_SPACE = 5;
+syntax = "proto3";
+package grc20;
+
+// --- Value Option Messages ---
+
+message Options {
+ oneof value {
+ TextOptions text = 1;
+ NumberOptions number = 2;
+ }
}
-```
-#### 16.1 Add edit
+message TextOptions {
+ optional bytes language = 1;
+}
-Params: `edit` - The URI to the edit protobuf file. Edit files must be hosted on decentralized storage.
+message NumberOptions {
+ optional string format = 1;
+ optional bytes unit = 2;
+}
-#### 16.2 Add subspace
+// --- Core Graph Objects ---
-Params: `subspace` - The space entity ID to add as a subpace of the current space.
+message Entity {
+ bytes id = 1; // 16-byte UUID4
+ repeated Value values = 2;
+}
-#### 16.3 Remove subspace
+message Value {
+ bytes property = 1;
+ string value = 2;
+ optional Options options = 3;
+}
-Params: `subspace` - The space entity ID to remove as a subpace of the current space.
+message Relation {
+ bytes id = 1; // relation UUID4
+ bytes type = 2; // relation-type UUID4
+ bytes from_entity = 3; // source entity UUID4
+ optional bytes from_space = 4; // (opt) source Space UUID4
+ optional bytes from_version = 5; // (opt) source Edit/Version UUID4
+ bytes to_entity = 6; // target entity UUID4
+ optional bytes to_space = 7; // (opt) target Space UUID4
+ optional bytes to_version = 8; // (opt) target Edit/Version UUID4
+ bytes entity = 9; // UUID4 of the rich-relation entity
+ optional string position = 10; // (opt) fractional ordering key
+ optional bool verified = 11; // (opt) trust flag
+}
+
+message Property {
+ bytes id = 1; // property UUID4
+ DataType data_type = 2;
+}
+
+enum DataType {
+ TEXT = 0;
+ NUMBER = 1;
+ CHECKBOX = 2;
+ TIME = 3;
+ POINT = 4;
+ RELATION = 5;
+}
-#### 16.4 Import space
+// --- Operations & Versioning ---
-Params: `import` - The URI to the import protobuf file. Import files must be hosted on decentralized storage.
+message Op {
+ oneof payload {
+ Entity update_entity = 1;
+ Relation create_relation = 2;
+ RelationUpdate update_relation = 3;
+ bytes delete_relation = 4;
+ Property create_property = 5;
+ UnsetEntityValues unset_entity_values = 6;
+ UnsetRelationFields unset_relation_fields = 7;
+ }
+}
-#### 16.5 Archive space
+message RelationUpdate {
+ bytes id = 1;
+ optional bytes from_space = 2;
+ optional bytes from_version = 3;
+ optional bytes to_space = 4;
+ optional bytes to_version = 5;
+ optional string position = 6;
+ optional bool verified = 7;
+}
-Flags the space as unused. Indexers and clients can still index the space if desired but an archived space is no longer maintained. Public spaces whose data was stored on decentralized storage and anchored onchain should continue to be available forever to anyone who wants to use or reference them.
+message UnsetRelationFields {
+ bytes id = 1;
+ optional bool from_space = 2;
+ optional bool from_version = 3;
+ optional bool to_space = 4;
+ optional bool to_version = 5;
+ optional bool position = 6;
+ optional bool verified = 7;
+}
+
+message UnsetEntityValues {
+ bytes id = 1;
+ repeated bytes properties = 2;
+}
+
+enum ActionType {
+ ADD_EDIT = 1;
+ ADD_SUBSPACE = 2;
+ REMOVE_SUBSPACE = 3;
+ IMPORT_SPACE = 4;
+ ARCHIVE_SPACE = 5;
+}
+
+message Edit {
+ string version = 1; // SemVer, e.g. "1.0.0"
+ ActionType type = 2;
+ string id = 3; // Edit UUID4
+ string name = 4; // commit-like message
+ repeated Op ops = 5;
+ repeated string authors = 6; // author IDs (e.g. wallet addresses)
+ string language = 7; // default Text language tag
+}
+
+message Import {
+ string version = 1; // SemVer
+ ActionType type = 2; // IMPORT_SPACE
+ string previousNetwork = 3; // e.g. "Ethereum Mainnet"
+ string previousContractAddress = 4; // origin Space contract
+ repeated string edits = 5; // ordered Edit URIs (CIDs)
+}
+```
+
+---
+
+### 13.2 UUID Constants
+
+| Concept | UUID |
+| --------------------------- | ------------------------------------ |
+| **Type (schema)** | e7d737c5-3676-4c60-9fa1-6aa64a8c90ad |
+| **Relation Type** | c167ef23-fb2a-4044-9ed9-45123ce7d2a9 |
+| **Property Type** | 808a04ce-b21c-4d88-8ad1-2e240613e5ca |
+| **Space Type** | 362c1dbd-dc64-44bb-a3c4-652f38a642d7 |
+| **Image Type** | f3f790c4-c74e-4d23-a0a9-1e8ef84e30d9 |
+| **Block Relation Type** | beaba5cb-a677-41a8-b353-77030613fc70 |
+| **Property ▶ Value Type** | ee26ef23-f7f1-4eb6-b742-3b0fa38c1fd8 |
+| **Property ▶ Unit** | 386d9dde-4c10-4099-af42-0e946bf2f199 |
+| **Property ▶ Format** | c5d181a2-6593-4c2c-b0da-8396bab2d8fb |
+| **Property ▶ Has language** | (Checkbox on Property) |
+| **Relation ▶ Value Types** | 3b2dca52-f1bf-45c0-ab1c-b4f883cf51d1 |
+| **Relation ▶ One Max** | dfeb3c65-28f5-4962-9d66-6df94e2f9bb6 |
+| **Relation ▶ Cascades** | 69a2489b-1e2e-42d9-93f3-0779e44ebca6 |
+| **Native Text** | 9edb6fcc-e454-4aa5-8611-39d7f024c010 |
+| **Native Number** | 9b597aae-c31c-46c8-8565-a370da0c2a65 |
+| **Native Checkbox** | 7aa4792e-eacd-4186-8272-fa7fc18298ac |
+| **Native URL** | 283127c9-6142-4684-92ed-90b0ebc7f29a |
+| **Native Time** | 167664f6-68f8-40e1-976b-20bd16ed8d47 |
+| **Native Point** | df250d17-e364-413d-9779-2ddaae841e34 |
+| **Implicit ▶ Name** | a126ca53-0c8e-48d5-b888-82c734c38935 |
+| **Implicit ▶ Types** | 8f151ba4-de20-4e3c-9cb4-99ddf96f48f1 |
+| **Implicit ▶ Description** | 9b1f76ff-9711-404c-861e-59dc3fa7d037 |
+| **Implicit ▶ Cover** | 34f53507-2e6b-42c5-a844-43981a77cfa2 |
+| **Implicit ▶ Blocks** | beaba5cb-a677-41a8-b353-77030613fc70 |
+
+---
+
+With these full schemas and UUID tables, implementers have a single source of truth for all message formats, option types, and constant identifiers in the GRC-20 knowledge-graph standard.
## Copyright waiver
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
-