07.24.26 · Modern Relay · 7 min read
Omnigraph: a graph database designed for agents
Every database assumes you are one of three things: a user, a workflow, or an operator. An agent is all three at once, which changes what the database underneath it should be.
An agent working a task discovers it has nowhere to put a fact. It proposes the type that would hold it, saves the traversal it just worked out so the next agent can reuse it, and notices the permission it is missing. Then it waits, because each of those is a different surface, a different tool, and usually a different person.
Every database assumes you are one of three things. A user, who reads and writes through an application. A workflow: deterministic software moving data on a schedule someone else set. An operator, who owns the schema, the policies, the backups, and the deployment. The separation of roles was the feature, not a problem. It is what keeps a database safe when the people changing it are few, careful, and slow, and it is why the operator's caution exists at all.
An agent is none of those things and all three at once. What follows is the premise we reason from, the six things that become declarative because of it, and what changes once the graph is built this way.
Agents collapse the trinity
In 2026, things look very different. In a typical hour, three agents working on one task read thirty-four thousand nodes. They propose four schema migrations: two enum extensions, a new node type, a new edge type. They save fourteen traversals as queries, so no agent has to work them out again. They request six permissions they do not have. They open eight branches for enrichments they are not sure of, create four thousand nodes and eight thousand edges on them, and ask for review. Each of them is a user at pipeline throughput, a workflow that rewrites its own steps, and an operator who never applied for the job, and all three are doing it on the same graph at once.
[figure 01]
The design that made the separation a feature is exactly what the agent now runs into. Every one of those moves belongs to a different role, so every one of them waits on a different surface, a different tool, and usually a different person. A loop the agent could close in a minute is spread across three people's afternoons.
So the question worth asking is: what does a database look like when the same agent is simultaneously user, workflow, and operator?
Omnigraph
Omnigraph answers it with graph as code. Six things go fully declarative: schema, context, writes, policy, the UI, the deployment. One definition covers them, the way Terraform made an environment a declarative deployment, and the embeddings and pipelines come along inside it.
The whole database definition fits in context, so the agent sees the entire system at once. It can reason about the setup before it acts. And it can change the setup the way it writes any other code: as a diff you review and apply.
A conventional database scatters this. Migrations go through a CLI, policies live in a control panel, queries are strings buried in application code, and the deployment is a separate concern again. Nothing holds the whole picture, so nothing can reason about it. Omnigraph makes the definition itself the primary operating surface. Start with the map: where does an agent learn the shape of the domain?
[figure 02]
Schema as code
An agent needs a map of the domain before it can work in it. A `.pg` schema file declares that map: node and edge types, properties and constraints, cardinality, interfaces and annotations, embeddings.
[pg]
node Person {
name: String @key
role: String @index
bio: String?
embedding: Vector(3072) @embed("bio")
}
node Document {
title: String @key
summary: String?
embedding: Vector(3072) @embed("summary")
}
edge Wrote: Person -> Document @card(0..)Because it is declarative, an agent can inspect the schema before acting rather than discovering the shape of the data by failing against it. Types are enforced, so the agent cannot invent things on the go.
The schema is also operating context: the ontology the reasoning runs on. The agent retrieves facts and reasons over a domain model at the same time, instead of retrieving text and hoping the model of the business is somewhere in it.
When an agent finds a gap, it proposes the schema change as a diff. You review and apply it like a pull request. The careful, slow operator role becomes a review step.
A map says what exists. It does not say where to go. How does an agent assemble context?
Context as code
Assembling context is a traversal problem. The path an agent takes through the graph is a reasoning pathway, and a good one makes the agent measurably smarter on the next task.
So when an agent keeps needing the same context, it defines the query and saves it. Queries are type-checked against the schema, versioned with it, and exposed as stable tools.
[gq]
query plays_about($author: String, $q: String) {
match {
$a: Person { name: $author }
$a wrote $d
}
return { $d.title }
order { nearest($d.embedding, $q) }
limit 3
}[figure 03]
plays_about("Shakespeare", "a prince avenges his father's murder")
walksorder { nearest($d.embedding, "a prince avenges his father's murder") }the vector index is consulted here — once, on the 37 the walk reachedRetrieval is hybrid in one runtime: traversals, vector search, full-text, ranking, and filtering. That query walks one edge and ranks only what the walk reached, in a single plan, so there is no application-side join between a graph and a vector store. The same `order` clause can fuse a full-text score from `bm25` with `rrf`. There is no second system to reconcile.
The loop an agent runs is: follow an edge, search nearby text, rank semantic matches, inspect related nodes, return the result in a shape it can use and reuse.
Reading is the easy half. What happens when an agent writes, and gets it wrong?
Branches
Agents write too, constantly and in bulk, so writes have to be safe. In Omnigraph every agent gets its own branch and works in isolation. Useful work merges, slop is discarded. Autonomous writes become proposals you review rather than raw changes to live data.
The real unlock is that branches let agents make mistakes. A long-running agent enriching thousands of nodes will get some of them wrong: a bad merge, a mislabeled edge, an enum in the wrong place. On a branch the mess stays on the branch, and the main graph never sees it.
[figure 04]
Once mistakes are cheap the calculus flips. You can point agents at real data, at scale, because the downside is a thrown-away branch rather than a corrupted graph.
Branches also blur the old OLTP and OLAP split. Agents do not think in terms of a transactional system and an analytical one. In a single loop they write facts, assemble context, traverse relationships, search and rank matches, inspect history, and write the result back.
Branches make mistakes cheap. They do not say who was allowed to make them. Who decides what an agent may do?
Policies as code
An agent-first database needs boundaries that are clearly defined, visible, and versioned. Governance is declarative: who can do what, on which graph, on which branch, under which identity, with an audit trail behind it.
[yaml]
version: 1
groups:
agents: ["claude-code", "hermes"]
protected_branches: [main]
rules:
- id: agent-writes
allow:
actors: { group: agents }
actions: [change]
branch_scope: unprotected[figure 05]
First divergence: rules[agent-writes].branch_scope. The agent proposes a diff to base.policy.yaml; you decide whether to apply it.
Clear rules keep agents from thrashing against invisible walls. When an operation is blocked, the agent can inspect the policy path, see exactly which permission is missing, propose the change in config, and leave the decision to hit `apply` to you. Policy changes become part of the workflow instead of a hidden gate outside it.
Rules hold still. The graph does not. Which interface keeps up?
UI as code
The graph changes shape often, which is a problem for any fixed interface built on top of it.
Steve Jobs made this argument about the iPhone. Plastic keys are fixed at the factory, so a phone built from them can only ever be the phone it shipped as; a software surface can become whatever the app in front of it needs. Fixed software is rigid in the same way. A hand-built UI cannot keep up with a graph that changes this often.
So in Omnigraph the human UI is generative. Schemas and queries already define what can be seen and changed, and the interface is derived from them.
[yaml]
version: 1
title: Open decisions
cells:
- id: decisions
lens: Table
query:
kind: nodes
where: { type: Decision, status: open }
project: [id, title, urgency]
order_by: { field: urgency, direction: asc }
props:
columns:
- { key: title, label: Decision }
- { key: urgency, label: Urgency }[figure 06]
People still need familiar primitives to view, update, and review data. They get them without anyone rebuilding the UI every time the graph shape changes.
All of this, the schema, the queries, the policies, the interface, is one definition. Where does it run?
Deployment
Graph as code is a deployment paradigm, which makes it flexible and modular. Omnigraph runs as a conventional cloud cluster, fully air-gapped on-premise, or as a hybrid with an integrated control plane. Object storage scales independently of compute.
The same graph can be served through different surfaces, moved between clusters, and recreated from its definition with a single `apply`.
[yaml]
version: 1
storage: s3://your-bucket/clusters/knowledge
graphs:
knowledge:
schema: schema.pg
queries: queries/
policies:
base:
file: base.policy.yaml
applies_to: [graph.knowledge][figure 07]
And whose is it? As open-source models get better, AI sovereignty becomes a real deployment target rather than a preference. The graph is the organisation's memory; a corrupted one or a locked-in one is the failure. Branches guard against the first. Ownership guards against the second, and it cannot be conditional. An export button is not ownership: it means you fully control the data and the definition. Omnigraph is built on the open Lance format, fully open source, with no vendor lock-in.
Wrapping up
Legacy databases were shaped by a world of human-scale throughput, stable schemas, slow operators, and clear scenarios (OLTP or OLAP). That world is gone.
We think that rather than patch the old model, it's time to ask what a database looks like when its user is an agent. The hard and interesting part is figuring out the right primitives: the scoped units of a write or a deployment, where a boundary belongs, where correctness has to win over speed, and many more.
We don't think we have all of it right. We get feedback every day, and we make it better.
If you use Omnigraph, please don't hesitate to tell us what works and what breaks.