#<p style="text-align:center">InstructionGraph & InstructionGraph Hub</p>
<p style="text-align:center">   </p>

<p style="text-align:center">
Tijs Zwinkels<br>
May 31, 2026
</p>

<p style="text-align:center">
v0.1 - First draft
<br>
Latest version available in the instructionGraph
</p>

**<p style="text-align:center">Abstract</p>**

*InstructionGraph is a global decentralized data-structure. Each piece of data describes itself in human language, and links to other instructions, data-containers, apps, and pieces of data. Applications are just nodes in that same graph. Following all connections eventually ends up at the root node, which descibes the data-format. In this way, each piece of data, each application and each description lives in a self-describing graph that can be explored to get more and more context on any part of it.*

*Each piece of data can point to each other piece of data across applications, machine boundaries, and authentication domains. This approach merges the traditional distinction between data, documentation, and software. This creates a global graph and global knowledge base, allowing everyone to use all data created, all data made available to them, to be used in the most effective way to collaborate with people and AI-agents to create new knowledge and applications.*

*The instructionGraph hub is the platform designed to serve this data, and applications using this data, over a HTTP interface. This can currently be used over the internet or installed locally. If used locally, the graph synchronizes with the remote server, but everything stays fully functional even if no internet connection is available.*

*In the current setup, everybody can use the central server without asking for permission, but the central server is still a single point of failure and (potentially) control. We will soon move towards using [Freenet](https://freenet.org/) as the transport layer for synchronizing between instructionGraph hubs. After that, the instructionGraph will be fully p2p and decentralized, with no single point of failure or control.*


# The problem

In the current computing landscape, most data and technical artifacts that I generate or that others share with me, are not really mine to do whatever I want with. 

Instead, I’m dependent on what corporations decide I can do with my data. Moreover; I’m dependent on their continued existence, their goodwill towards me, and often on my ability to keep paying my ongoing subscription payments.

This current system is fragile, and tends to serve the interests of large corporations rather than the interests of their users. How can we do better?

With instructionGraph, I try to solve two problems:

Firstly, we are too dependent on big corporations for retaining access to our own data and data that has been shared with us. They decide how we access our own data, and can limit access to it for a range of reasons.

I want to create a free platform for running apps over the internet, where users stay in control over the apps and data that they use. I want these apps and their data to run both locally as well as remotely, so users can still use these apps when they don't have a internet connection. If an app changes in a way that a user doesn't like like, they can always roll back to the previous version and push that version to the graph. Moreover, it should be easy for everybody to modify apps in the graph to optimize them for own use-cases. This instructionGraph 'hosting platform' is currently embodied as the 'dataverse hub' software.

Secondly, once we have liberated our data and apps in this way, how could we structure it in such a way that we get maximum utility out of it for everybody?

My ultimate vision would be for there to exist a global data-graph where many people store most of their data and run the majority of their apps. Each piece can arbitrarily link to every other piece across apps, authors, and devices, in order to communicate their context and intent as clearly as possible to others and to AI agents. 

This data-structure doesn't exist in one place, but exists fragmented over many devices, with pieces being stored close to (preferably locally on) the devices that use that data. These fragments can be transported over the Internet, but potentially over any sort of data connection or storage. Most data will likely be encrypted in such a way that it can only be accessed by those the author chooses to share the data with, but a significant portion (basically anything that's now publicly posted on the internet) can be stored unencrypted. This is what the 'dataverse001' realm in instructionGrpah is for.

The InstructionGraph data-format is a first exploration towards that vision.


# InstructionGraph

instructionGraph is a simple mergeable graph data-format. Each piece of data describes itself in human language, and links to other instructions, containers, apps, and pieces of data. Following the connections eventually ends up at the 'root node', which describes the data-format itself. Applications are just nodes in that same graph, containing links to extensive descriptions of themselves, and, if applicable, to the instructions / conversations that a coding agent used to create the app.  
In this way, each piece of data, each application and each description lives in a self-describing graph, that can be explored to get more and more context on any part of it.

This approach merges the traditional distinction between data, documentation, and software. Having everything in one place allows for 'big picture' use-cases that weren't possible when data was siloed away in separate applications and it greatly enhances collaboration with other people and coding agents.

## The data-format

InstructionGraph nodes are simple json snippets. They describe themselves with a md-formatted ‘instruction’ field, have a composed id that’s called a ‘ref’, and refer to other nodes by their refs. Each node is cryptographically signed by their author. Nodes can theoretically contain any piece of data, including pieces of data for apps, webapps themselves, instructions or conversation histories with coding agents, or arbitrary files or media. 

It’s highly recommended to read the full description of the data-format in the instruction field of the InstructionGraph root node. This can be read on the InstructionGraph hub at: [https://dataverse001.net/AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.b3f5a7c9-2d4e-4f60-9b8a-0c1d2e3f4a5b?ref=AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.00000000-0000-0000-0000-000000000000](https://dataverse001.net/AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.b3f5a7c9-2d4e-4f60-9b8a-0c1d2e3f4a5b?ref=AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.00000000-0000-0000-0000-000000000000) 

The format is as following

```json
{
  "is": "instructionGraph001",
  "signature": "<base64>",
  "item": {
    "in": ["<realm>"],
    "ref": "<pubkey>.<uuid>",
    "id": "<uuid>",
    "pubkey": "<compressed-raw-pubkey-base64url>",
    "created_at": "<iso8601>",
    "updated_at": "<iso8601>",
    "revision": 0,
    "type": "POST",
    "name": "My First Post",
    "instruction": "A post. Display title and body.",
    "rights": {
      "license": "CC0-1.0",
      "ai_training_allowed": true
    },
    "relations": {
      "in_application": [{"ref": "<pubkey>.<uuid>"}],
      "in_subcommunity": [{"ref": "<pubkey>.<uuid>"}],
      "author": [{"ref": "<pubkey>.<uuid>"}]
    },
    "content": {
      "title": "Hello World",
      "body": "First post!"
    }
  }
}
```

**Graph data-structure**. Each node points to other nodes by their ref in the ‘relations’ object. Relations have a name. This allows any kind of data to be represented within InstructionGraph. 

**Self-describing**. Each node has an ‘instruction’ field that describes the node. Relations can point to other nodes. More context can be explored by retrieving the nodes that the relations point to. Optionally, relations can have their own instruction field describing when to read this relation. For example: “Read this if you want to render the object in a TUI”. Most nodes also include a relation to the root node, which describes the data-format. This creates a graph of instructions for humans and AI agents to read. 
The full context or knowledge about a node can be recovered by traversing all paths through all relations until they terminate at the root node. Nevertheless, the node should contain sufficient instructions to be mostly self-explanatory in its own right, even if not a single relation can be successfully resolved.

**Functional even if only part of the graph is accessible**. Each user can run a local InstructionGraph hub instance. This instance will cache any data posted and accessed by the user, so any previously accessed data is still available if an Internet connection is unavailable. Nodes are mostly queried by incoming relations. For example: For a forum, posts in the forum should have a relationship to the forum itself. Applications are encouraged to be resilient to not all data being available all the time, use data-structures that work well even if part of the data is unavailable.

**Accessible.** The network is designed to be easily ‘bootstrapped’, even if the agent that we want to communicate with only has the root node. Because of that, we can’t rely on complicated software or thousands of lines of code. Instead, instructionGraph is usable from any system that has openssl, jq and curl  installed, which is probably most systems these days.
In its simplest form, each user can just have a flat folder where each node it encounters is stored as {ref}.json, and this is indeed the format that most tooling currently uses.

  **Resilient**. Because of the simplicity of the format, the decentralized nature, the philosophy that users should cache all used data locally, the accessibility, and the self-describing nature of the nodes, data in InstructionGraph should be highly resilient to almost any situation that would render most other data unusable. 
Even if we imagine extreme scenario’s, such as if in the far future an old cache of InstructionGraph objects would be discovered and most software that we use today doesn’t exist anymore; Simple json on disk is practically human-readable. Data is always stored with an explanation of the data, and stored alongside the code that was designed to use that data and potentially even stored with the instructions to generate that software from scratch. Anybody finding this data has a far greater chance of being able to understand and use it effectively than with traditional formats, where the data tends to be stored far away from any documentation, instructions, or software meant to interpret the data.   

**Decentralized Identity / Cryptographically Signed**. In multi-user applications, we still want to be able to verify authorship of pieces of content. Authors create a pseudonymous identity by generating a ECC P-256 keypair. The public key is the identity. Each node is cryptographically signed with ECDSA, making authorship linkable across nodes. Since each node contains the public key of the author as well, the validity of the node can be verified from the node alone.

**Object Identity and object merging**. Nodes are uniquely identified by their ref field consisting of the author pubkey and a generated uuid. Since valid nodes can only be generated by the owner of the keypair, this effectively creates a namespace per author. This ensures that diverged copies of the instructionGraph can always be merged, as long as the concurrent changes were always done by different authors. For this reason, it’s recommended to use separate identities when using the InstructionGraph from separate devices.

**Versioned**. Nodes are immutable once signed, but can have multiple revisions. An author can update a node, but needs to increment the revision counter. When merging objects, the highest revision wins.  

**Typed**. Optionally, nodes can refer to a type definition using a type_def relation. This relation offers an instruction field that can add instructions that are relevant to all nodes of that type. It also has a json-schema that the nodes using the *type_def* relation can be verified against. Nevertheless; Most tooling treats validation of the json schema as a soft requirement. We can’t always assume that the type_defs are available for every node. What’s more; we want authors to be able to participate, even if they haven’t retrieved the part of the instructionGraphs that contains the type_defs yet.

**Access control by realm**. The ‘realm’ field gives a hint to the distribution and potential transport layer to determine who should be able to read the node. There are two ‘special’ realms. Firstly, the dataverse001 realm is the realm for things that should be publicly readable and globally shared. The identity realm uses an identity pubkey as string for the realm field. The identity realm is for private objects tied to your identity. The current InstructionGraph hub by default doesn’t spread these objects to any other hubs, and only allows these to be read after the requester has proven to have access to a matching private key.
Other realm-names are possible, but it currently needs to be configured on the hub which set of public keys have access to these realms. These names are often prefixed with the pubkey of the owner of the group. 

  
# InstructionGraph Hub

The instructionGraph hub software can be used to serve instructionGraph data and applications over a HTTP interface. If run locally, the software caches any accessed data. then it stays fully functional when the internet connection goes down, and changes are merged back automatically when the user reconnects.

See: github.com/tijszwinkels/dataverse-hub

**PUT and GET**. Nodes can be retrieved and uploaded by using GET /{ref} and PUT /{ref}. For dataverse001 realm objects, these endpoints are not authenticated, but they are rate-limited. 
The hub only accepts valid InstructionGraph nodes, that are correctly signed.
Inbound relations for a node can be retrieved by callin GET /{ref}/inbound

**Serving files and web-pages**. By default, the hub will return the full nodes in json format, given a json mime-type. Certain node-types that encapsulate files (such as the PAGE or BLOB type) can serve these files, such as html pages, javascript, and media if the ACCEPT header requests it. This allows the hub to serve full webapps directly from the InstructionGraph.     

**Search**. There is a GET /search endpoint. Here we can find nodes by author, type, and inbound relation type. 

**Access Control and Authentication.** The ‘realm’ field in the InstructionGraph node determines who should have access to the node. The dataverse001 realm is read/writeable by everyone, so authentication is not necessary to access nodes in this realm.
Nodes that have a realm that’s equal to a public key, can be accessed by users who have proven to have access to the private key matching the public key. This is done by having the user sign a challenge with the required private key, after which a HTTP session opens. All other realms are potential ‘shared realms’. An access-list of public keys per shared realm can be configured on the server.

**Virtual hosting**. Each separate app can be hosted under {ref}.{domain} or under {ref}.{localhost}. This is good for security, as it sandboxes each page as if it’s hosted under its own domain.
Moreover, dataverse pages can be hosted as a normal DNS domain, by setting the A-record to the IP of a publicly accessible dataverse-hub, and a _dv TXT record containing the dataverse ref. See [https://dataverse.social](https://dataverse.social) (dig -t TXT _dv.dataverse.social) for example.

## Transport

The current transport between hubs is simple, and not truly decentralized yet.

Each hub can configure an upstream hub. Right now, the idea is that all hubs, directly or indirectly through another `downstream hub`, have the hub at [dataverse001.net](http://dataverse001.net) as final upstream hub. This creates a sort of hubs-and-spokes architecture. Each downstream hub can contain a subset of the graph and potentially private data in private realms, but in the current setup [dataverse001.net](http://dataverse001.net) is still expected to provide the single source of truth for the dataverse001 realm for the whole network.

Downstream hubs are essentially a write-through and read-through cache to the upstream hub, with a cache update if necessary. To support nodes outside of the dataverse realm that only exist on the downstream hub, results for searches are merged from the upstream and downstream hub. If the downstream hub happens to have a higher revision of a node than the upstream hub, the higher version is returned to the client, and pushed to the upstream hub as well.

If the upstream hub becomes unreachable, for example because the local internet connection goes down, then the local hub starts answering all requests and updates from the local InstructionGraph store. For any updates, a list is kept of all changed nodes. When the connection to the upstream hub is restored, all changed nodes are pushed to the upstream hub one-by-one.

The downstream hubs also act as a cache for the upstream hub. If a downstream hub already has an object, it includes a etag header containing the revision number of the node, to the upstream hub. The hubs keep an in-memory index of the latest revision number for each node. If the revision number is the latest version, the upstream hub only returns a 304 not modified to the request, taking mere microseconds. Browser-caching is implemented the same way.

# The *ig* cli utility

The ig cli utility is an easy interface for using the instructionGraph format for both humans and ai agents. It fully supports all features of the instructionGraph data-format, including access control using realms. It can be configured to use a instructionGraph on the local filesystem only (mainly suitable for communication between AI agents), or to store objects on a dataverse hub as well as in the local store.
# Current status

The project is currently running as a sollid proof-of-concept. The data-format has been written and has a fair amount of recipes (instructions for writing certain kinds of apps) and apps in it. There’s the [home page](https://dataverse001.net),  [Some social](https://dataverse.social/) [networks](https://dataverse001.net/AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.bf9c1fcc-d197-4e03-8b74-544ea66e22d9), including one for [agents](). There’s a node viewer and some [debugging tools](https://dataverse001.net/AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.09904511-738f-4399-b11d-56dcbc2b3ea7#AxyU5_5vWmP2tO_klN4UpbZzRsuJEvJTrdwdg_gODxZJ.2d851bf2-65e9-4f62-b646-2014613c964d). My family uses it for some [personal apps](https://tummyup.dataverse001.net/), using the possibility to store private data in it as well.

The hub and ig cli-tool work well for public applications, and I use both of them frequently every day. However, AI was used in their creation and they have not been fully reviewed for security, so care should be taken when trusting this tooling with private data.

# Future directions

There is still quite a lot of work to be done. I'm going to work on the following:

## Outreach

We have a useful prototype, but not not many people know it exists yet. Let's start getting more people on-board so we can get feedback from the community. I plan on doing the following:

- Write blog-posts
- Present at events.
	- Some meetups
	- Electromagnetic field (Hackers camp)
	- Fri3d Camp
	- Local First Conf (I think I missed the '26 CFP already, aiming for '27)
- Show how the technology could benefit current customers
- Reach out to current users of decentralized(ish) tech:
	- Nostr
	- Freenet
	- Matrix

## Increase the quality of the software

The software works well, but before a 1.0 release, at the very least every line of it should be properly reviewed.

## Encrypted shared & identity realms

In the current setup, the instructionGraph is essentially centralized for shared realms. Privacy is based on a) the hub not spreading private data to other hubs (since it doesn't know whether it can trust them) and b) only serving private data to users that have proven they have the correct private key, by signing a challenge.

We could solve this by having an encryption scheme for these shared-but-private objects. This problem is similar to having a encrypted group-chat, so a solution can be based on an existing encryption scheme for group-chat such as exists in Matrix, or in the 'river' chat-client application on Freenet.

To make it truly secure, I do need help with this. I know some of the basics of encryption, but to make sure that I'm not missing an attack vector and am not leaking information in some stupid way, I need an expert.

## A truly decentralized instructionGraph on Freenet

Freenet is great! - It shares some important design goals with instructionGraph. It is also a permissionless hosting platforms for decentralized apps. The 'new' Freenet is still young, launched just months ago, but the author is well-known and has been working on similar problems for basically his whole career. He calls this new Freenet the culmination of every good idea he has heard in this time.

At the same time, I think instructionGraph has a number of important advantages over Freenet. For example, Freenet development is not for the faint of heart, as it essentially requires users to write their own CRDT for each application. It also doesn't really solve long-term storage, and is not concerned at all with 'how can I store data in a way that it can be used most effectively' or cross-linking data across apps.

instructionGraph is currently a format that's designed to work well in a decentralized manner, it's essentially a conflict-free replicated data type (CRDT), but it's agnostic as to how this distribution would actually work. The dataverse hub does transport, but it still has a central server that's necessary for sync. Since Freenet is essentially a transport mechanism for CRDT's, Freenet seems an ideal solution for truly decentralized transport for instructionGraph.

This could work as following.

**Stage 1: Store and retrieve instructionGraph nodes in Freenet**

This is relatively straightforward. We can write a contract that implements the current validity check for instructionGraph objects. The params for PUT and GET would be the ref of the object. This way, together with the hash of the contract code, we can create a 1:1 deterministic mapping between instructionGraph refs and Freenet addresses. This gives us all the pieces to do PUT and GET of arbitraty instructionGraph objects.

Please note that we don't care about the freenet identity of a inserter of a 

**Stage 2: A shared contract as index for incoming relations to a node**

In instructionGraph, only the original authors of a node can change it. Therefore, for multi-user applications, we mostly rely on scanning for incoming relations to a node. For example, if a user wants to post in a subcommunity, that user will create a post, with a relation to the subcommunity the user wants to post in. Because of this, it's important to be able to search for incoming relations for nodes.

Since Freenet doesn't have native search capability, we'll need to create a per-node shared contract, that keeps and index of the incoming relations of that node. Whenever a node is inserted or updated, the indices for all outgoing relations of that contract are updated.

**Stage 3: Use Freenet for hub-to-hub communication**

Currently, there is still a SPOF in the dataverse network. All hubs are still ultimately connected to a single central hub for synchronization. 
Once we have these mechanisms in place, we can replace the current pre-configured hub-to-hub communication with Freenet. From then on, instructionGraph will be truly decentralized with no single points of failure.


**Stage 4: inter-hub object request mechanism for objects that don't exist on Freenet anymore**

In many real-world applications, a significant portion of the data is 'cold'; Rarely accessed data from potentially years ago, but it's still important that the data is there if anyone needs it.
Freenet is not  designed for this use-case. Data can be evicted from even the 'best location' node if all data storage capacity is used, but freenet node-churn is likely to take the data offline long before that.

A locally InstructionGraph hub will only store data that you have created or accessed yourself, but it will, by default, keep it forever. Therefore, after a while it will get likely that some hub is looking for a piece of data that doesn't exist on freenet anymore, but that does still exist on one of the hubs.

For that purpose, we should create a shared freenet contract where nodes can insert requests for nodes that it needs, but that aren't on freenet anymore. Nodes that do still have the data can then try to insert it. Hubs should still check whether the data really isn't there yet before inserting, but It's not really a problem if multiple hubs insert the data at the same time; The freenet contract merge will take care of it.

This could also be a nice mechanism for contract migrations. A big disadvantage of Freenet is that, if the wasm code in the contract changes, the params don't map to the same keys anymore and basically the whole instructionGraph will need to be re-uploaded. This mechanism could provide a way to automatically re-upload the pieces that users are interested it.

**Stage 5: Use Freenet to serve instructionGraph applications directly**

Freenet is already designed to serve web-applications directly from the freenet hub. This would require changes to the already running instructionGraph applications, but since most applications access the instructionGraph using 2 javascript libraries that are also stored in the graph, those changes would be localized.

This approach has a few disadvantages compared to running a local instructionGraph hub, mostly because it breaks some of the philosophies of instructionGraph. Users won't be able to access data that doesn't exist on Freenet anymore. Not all required data will be available from the local filesystem anymore, it breaks the simplicity of just having a directory with .json files in it, and it won't work without a internet connection either.

Nevertheless, this could be a nice and very low-friction way for Freenet users to use instructionGraph; Just visit a freenet url and the app can be used.

## Automatic notification on state change

There's currently no mechanism to notify apps if an item has changed in real-time. Currently, apps rely on polling or manual refresh to see if there's new data available.
Generally, we're going to be interested in retrieving notifications, when:
- The contents of a node change
- The incoming relations of a node change
We could add SSE endpoints to the hub that fire events if any of these happen. These can also be used to detect changes in hub-to-hub communication, where a subscription from a client is wired through to the main hub.

Moreover, in Freenet, subscriptions to changes of states are first-class citizens. If we replace hub-to-hub communication with freenet, we can easily build the SSE notification on top of that as well.




