Omnigraph

Quick Start

Install Omnigraph, define a schema, load data, run a query, branch a change, and merge it back.

This guide walks you through a complete Omnigraph workflow: defining a typed schema, loading graph data, running a read query, making a change on a branch, and merging that branch back into main.

Install

Build the Omnigraph CLI from source:

git clone https://github.com/ModernRelay/omnigraph.git
cd omnigraph
cargo build --release -p omnigraph-cli

The compiled binary is at target/release/omnigraph.

Define a schema

Create a file called schema.pg:

node Task {
    slug: String @key
    title: String @index
    status: enum(pending, in_progress, completed)
}

edge DependsOn: Task -> Task

This schema defines one node type and one edge type. Each Task has a stable key (slug), a searchable title, and a status enum. The DependsOn edge captures task dependencies directly in the graph.

Initialize a repository

Create a new graph repository at ./my-graph, using your schema:

omnigraph init --schema schema.pg ./my-graph

Load data

Create a file called data.jsonl:

{"type": "Task", "data": {"slug": "auth", "title": "Finish auth flow", "status": "pending"}}
{"type": "Task", "data": {"slug": "api", "title": "Ship API endpoint", "status": "pending"}}
{"type": "Task", "data": {"slug": "frontend", "title": "Connect frontend", "status": "pending"}}
{"edge": "DependsOn", "from": "api", "to": "auth"}
{"edge": "DependsOn", "from": "frontend", "to": "api"}

Each line is either a node or an edge. Edge records reference nodes by their @key value (slug). Load the file:

omnigraph load ./my-graph --data data.jsonl

Write a query and a mutation

Create a file called queries.gq:

query unblocked_tasks() {
    match {
        $t: Task { status: "pending" }
        not {
            $t dependsOn $dep
            $dep.status != "completed"
        }
    }
    return { $t.slug, $t.title }
}

query mark_completed($slug: String) {
    update Task set {
        status: "completed",
    }
    where slug = $slug
}

Run the query on main

omnigraph read ./my-graph \
    --query queries.gq \
    --name unblocked_tasks \
    --json
[
  { "slug": "auth", "title": "Finish auth flow" }
]

Only auth is unblocked. api depends on auth, and frontend depends on api.

Create a branch

omnigraph branch create --uri ./my-graph --from main finish-auth

The branch starts as an exact copy of main. Any changes you make on it are isolated until you merge.

Apply a change on the branch

omnigraph change ./my-graph \
    --query queries.gq \
    --name mark_completed \
    --params '{"slug": "auth"}' \
    --branch finish-auth \
    --json

Verify the branch state

omnigraph read ./my-graph \
    --query queries.gq \
    --name unblocked_tasks \
    --branch finish-auth \
    --json
[
  { "slug": "api", "title": "Ship API endpoint" }
]

Because auth is completed on finish-auth, api is now unblocked. main still returns auth.

Merge back to main

omnigraph branch merge --uri ./my-graph finish-auth --into main --json

After the merge, main reflects the completed auth task and api becomes the next unblocked task.

On this page