Quick Start
Install Omnigraph, define a schema, load data, run a query, branch a change, and merge it back.
This guide walks through a complete Omnigraph workflow: define a typed schema,
load graph data, run a read query, make a change on a branch, and merge that
branch back into main.
Install
Fastest path:
curl -fsSL https://raw.githubusercontent.com/ModernRelay/omnigraph/main/scripts/install.sh | bashThat installs both omnigraph and omnigraph-server into ~/.local/bin
from published release binaries.
Homebrew:
brew tap ModernRelay/tap
brew install ModernRelay/tap/omnigraphManual source builds are still supported, but they are no longer the default install path. See Install for release channels, source builds, and platform details.
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 -> TaskThis 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-graphLoad 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.jsonlWrite 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-authThe 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 \
--jsonVerify 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 --jsonAfter the merge, main reflects the completed auth task and api becomes
the next unblocked task.