Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions skills/omnigraph/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: omnigraph
description: Operate OmniGraph graphs and deployments. Use for `.pg` schemas, `.gq` queries, OmniGraph CLI commands, `file://`/`s3://`/`az://` graph URIs, `cluster.yaml`, operator config, bearer-authenticated servers, graph-backed knowledge or memory, Blob values, embeddings, branches, commits, and change feeds. Apply especially before schema changes, bulk loads, and retries after uncertain remote outcomes.
license: MIT (see LICENSE at repo root)
compatibility: Validated against OmniGraph CLI and server 0.10.x. The CLI, server, and client bindings must be upgraded together.
compatibility: Covers released OmniGraph CLI and server 0.10.0. The CLI, server, and client bindings must be upgraded together.
metadata:
author: ModernRelay
version: "0.10.0"
Expand All @@ -13,6 +13,11 @@ metadata:

This skill captures the operational rules for working with a locally or remotely deployed Omnigraph. Follow them when authoring schema, writing queries, loading data, evolving schema, or automating graph operations.

Check `omnigraph version` and the command's `--help` before using these
instructions. This skill targets the [v0.10.0 release](https://github.com/ModernRelay/omnigraph/releases/tag/v0.10.0),
which reports `internal-schema 6`. Use the matching release's source and docs
when verifying behavior.

## The Seven Rules

1. **Lint before commit** — `omnigraph lint --schema schema.pg --query queries/foo.gq` validates both sides against each other. No running repo required.
Expand All @@ -23,7 +28,7 @@ This skill captures the operational rules for working with a locally or remotely
6. **Expose agent reads as aliases** — aliases decouple a read operation name
from its stored-query implementation. Aliases are read-only; invoke a served
stored mutation with `omnigraph mutate <name> --server ...`.
7. **Treat a lost remote response as unknown** — a successful JSON write response contains the exact commit published by that attempt, but a proxy can return 504 after publication. On timeout, verify the branch head or intended entity effect before retrying. See `references/remote-ops.md`.
7. **Treat a lost remote response as unknown** — an effectful `mutate --json` or `load --json` response contains the exact commit published by that attempt, but a proxy can return 504 after publication. On timeout, verify the intended branch/entity effect before retrying. See `references/remote-ops.md`.

## Essentials: Queries, Mutations, Loads

Expand All @@ -46,7 +51,7 @@ query get_signal($slug: String) {
- **Parameterize, never interpolate.** Declare `$var: Type` in the signature; pass via `--params '{"slug":"sig-foo"}'`. An empty signature still needs parens: `query foo() { ... }`.
- **Edge traversal is lowerCamelCase** even though the schema declares edges PascalCase (`FormsPattern` → `formsPattern`).
- **List/sort** by appending `order { $s.stagingTimestamp desc } limit 50` after `return`.
- **`nearest` and `rrf` require a trailing `limit N`** — omitting it is a compile error. `bm25` does not require a limit, but use one to keep ranked output bounded. Ranking operators live in `order { }`, not as filters; to read the score, project the same expression in `return` (`nearest(...) as score`, T33 requires it to match the leading order key). Scope with `match`/filters first, then rank (`order { nearest($d.embedding, $q) } limit 10`).
- **`nearest` and `rrf` require a trailing `limit N`** — omitting it is a compile error. `bm25` does not require a limit, but use one to keep ranked output bounded. Ranking operators live in `order { }`, not as filters. Scope with `match`/filters first, then rank (`order { nearest($d.embedding, $q) } limit 10`).

### Mutation (`.gq`)

Expand Down Expand Up @@ -83,7 +88,7 @@ omnigraph load --data delta.jsonl --from main --branch review --mode merge $GRAP
```

- `--mode`: `merge` (upsert by logical entity ID; keyed node IDs derive from their `@key` tuple) · `append` (fails on ID collision) · `overwrite` (destructive, staged). `--from <base>` forks a missing `--branch`; bare `load` needs an existing branch. Works local **and** remote.
- **Date values**: `mutate --params` takes a calendar day (`YYYY-MM-DD`) for `Date` and ISO 8601 for `DateTime`. `load` accepts calendar-day `Date` strings (`YYYY-MM-DD`, recommended) or integer epoch days, and ISO `DateTime` strings or integer epoch milliseconds; a `Date` string carrying a time of day (`2026-04-29T10:00:00Z`) is refused on every path, and any other JSON type for a date fails the load naming the property.
- **Date values**: use a calendar-day string (`YYYY-MM-DD`) for `Date` and an ISO timestamp for `DateTime`, in both `mutate --params` and JSONL. `load` also accepts integer epoch days for `Date`.

### Dispatching

Expand All @@ -92,13 +97,9 @@ omnigraph alias signal sig-foo # operator alias → its bound
omnigraph query get_signal --params '{"slug":"sig-foo"}' # served stored query by name (verb asserts read vs write)
omnigraph query -e 'query q() { match { $s: Signal } return { $s.slug } limit 5 }' # ad-hoc/inline (or: --query f.gq <name>)
omnigraph mutate add_signal --query mutations.gq --params '{"slug":"sig-foo","name":"Foo","brief":"Example","createdAt":"2026-04-14T00:00:00Z"}' # name positional; ad-hoc file source
omnigraph mutate -e 'branch create b0' # branch statement: control writes (create/delete/merge) go through mutate
omnigraph query -e 'branch list' --format table # branch statement: the listing is a read and goes through query
omnigraph lint --schema schema.pg --query queries/foo.gq # after EVERY .gq/.pg edit (no server needed)
```

A branch statement (`branch create <name> [from <parent>]`, `branch delete <name>`, `branch merge <source> [into <target>]`, `branch list`) names its branches itself: no `--branch`, `--snapshot`, `--if-commit`, positional name, or `--params` beside it. The wrong door refuses it (`statement 'branch merge' is a control write; use POST /mutate` (`mutate` from the CLI), `statement 'branch list' is a read; use POST /query` (`query` from the CLI)). Same effect and same policy check as the `branch` verbs.

### `.gq` grammar

The non-obvious facts that bite, then the full grammar:
Expand All @@ -109,8 +110,6 @@ The non-obvious facts that bite, then the full grammar:
- **Variable-hop traversal**: `$p knows{1,3} $f` — bounds are **required to be finite** (`{1,}` is rejected: "unbounded traversal is disabled").
- **Undirected traversal**: `$p <knows> $f` matches the edge in either direction, deduplicated (a pair connected both ways appears once). Same-endpoint-type edges only (e.g. `Related: Issue -> Issue`) — asymmetric edges are rejected (T22). Composes with bounds (`$p <knows>{1,3} $f`) and `not { }`.
- **Edge bindings**: an optional `$var:` prefix on the edge word — `$src $w:knows $dst`, undirected `$a $w:<related> $b` — binds the matched edge row, so edge properties work in filters (`$w.confidence = "asserted"`), projections (`return { $w.role }`), aggregates, and ordering. A bound traversal returns one row per edge (parallel edges stay distinct); binding a `{min,max}` multi-hop, rebinding a taken name, or projecting bare `$w` is rejected (T23).
- **Result columns**: each `return { }` entry is one column, named by its alias or its expression (`$s.slug` → `s.slug`); two entries that would produce one column name are rejected (T25) — alias them apart. `nearest(...)`/`bm25(...)` in `return` project the score the ordering used (must repeat the leading `order` key, T33; default column `d._distance`/`d._score`, `F32`); a rank expression under an aggregate (T32), `rrf(...)` in `return` (T37, for now), a search predicate in `return` (T35) and an alias projected a second time (T36) are rejected.
- **Result JSON spelling**: rows follow Arrow's JSON conventions (the `arrow-json` writer, RFC 0051): a null cell's key is **omitted** from its row; `Date` is `"2026-04-29"`, `DateTime` is `"2026-04-29T08:30:00"` (UTC, no `Z`, `.123` only when non-zero); integers of every width are bare numbers (beyond 2^53 `JSON.parse` rounds them); `F32` prints at 32-bit width (`0.99`); integral floats carry `.0`.
- **Literals & calls**: `now()`, `date("2026-04-29")`, `datetime("…T00:00:00Z")`, list `[…]`.
`starts_with`, `contains`, `>=`, `<=`, `!=`, `>`, `<`, `=`

Expand All @@ -129,13 +128,13 @@ Notation: `<x>` required · `[x]` optional · `<a|b>` choice · `…` repeatable
**Global addressing flags**: `--as <actor>` (direct-engine writes and actor-bound cluster operations; remote writes derive the actor from the bearer token), `--server <name|url>`, `--cluster <dir|uri>` (cluster-managed storage, primarily for maintenance), `--graph <id>` (selects within a `--server` or `--cluster` scope), `--profile <name>` (`$OMNIGRAPH_PROFILE`), `--store <uri>`. Commands with an open positional slot also accept `file://`, `s3://`, or preview `az://` directly. `--config <dir>` belongs only to `cluster` subcommands. Output: `--json`, or read queries take `--format <json|jsonl|csv|kv|table>`. **Write guards:** `--yes` skips non-local confirmation for destructive writes; `--quiet` suppresses the resolved-target echo.

**Data plane** — `any` (served via `--server`/`--profile`, or direct via `--store`/URI):
- `query` (alias `read`) `<name>` — a **served stored query** by name (via `--server`/`--profile`); or ad-hoc `[<name>] (--query <f.gq> | -e '<GQ>')` where `<name>` picks which query in the source. `[--params <json> | --params-file <p>] [--branch <b> | --snapshot <id>] [--format <fmt> | --json]`. No positional URI — address via `--server`/`--store`/`--profile`. The source may be the `branch list` statement (`-e 'branch list'`), which takes no name, params, `--branch`, or `--snapshot`.
- `mutate` (alias `change`) — same shape (served stored mutation by `<name>`, or ad-hoc `--query`/`-e`); `[--params …] [--branch <b>] [--if-commit <graph_commit_id>] [--json]`. The verb asserts kind; a failed precondition has no effect and exits 4. The source may be one control-write statement (`-e 'branch create b0'`, `'branch delete b0'`, `'branch merge b0 into main'`), which takes no name, params, `--branch`, or `--if-commit`; `branch delete` against a non-local target needs `--yes` or a TTY answer.
- `query` (alias `read`) `<name>` — a **served stored query** by name (via `--server`/`--profile`); or ad-hoc `[<name>] (--query <f.gq> | -e '<GQ>')` where `<name>` picks which query in the source. `[--params <json> | --params-file <p>] [--branch <b> | --snapshot <id>] [--format <fmt> | --json]`. No positional URI — address via `--server`/`--store`/`--profile`.
- `mutate` (alias `change`) — same shape (served stored mutation by `<name>`, or ad-hoc `--query`/`-e`); `[--params …] [--branch <b>] [--if-commit <graph_commit_id>] [--json]`. The verb asserts kind; a failed precondition has no effect and exits 4.
- `load --data <f.jsonl> --mode <overwrite|append|merge> [--branch <b>] [--from <base>] [--json]` — `--mode` required; `--from` forks a missing `--branch`; overwrite replaces only represented types
- `blob <get|stat> <node|edge> <TYPE> <ID> <PROPERTY>` — dedicated Blob-cell reads; `get` supports ranges/`--out`, `stat` returns metadata
- `snapshot [--branch <b>] [--json]`
- `export [--branch <b>] [--type <T>…]` (streams JSONL)
- `branch <create <name> [--from <base>] | list | delete <name> | merge <source> --into <target> [--delete-branch]> [--json]`; or as GQ statements: `mutate -e 'branch create|delete|merge …'`, `query -e 'branch list'`
- `branch <create <name> [--from <base>] | list | delete <name> | merge <source> --into <target> [--delete-branch]> [--json]`
- `commit <list [--branch <b>] | show <commit_id> | changes <commit_id> [filters…]> [--json]`
- `changes <poll [--start now|beginning|after:<id> | --cursor <c>] | baseline --out <snapshot.jsonl>> [filters…] [--json]`
- `schema apply --schema <f.pg> [--allow-data-loss] [--json]` · `schema show` (alias `get`) — `apply` **refuses a cluster-managed graph** (evolve those via `cluster apply`)
Expand Down Expand Up @@ -289,8 +288,6 @@ These are the traps most likely to bite. Scan this table before debugging any pa
| Expecting `@embed` to populate vectors during load | missing/stale vectors | `@embed` is metadata; run the offline `omnigraph embed ... --reembed-all` file pipeline, then load its output |
| `schema apply` with feature branches open | rejected | Merge or delete branches first |
| `nearest(...)` / `rrf(...)` without `limit` | compile error | Add `limit N`; a BM25-only query may omit it, though bounded output is recommended |
| `bm25(...) as score` in `return` without the same `bm25(...)` leading `order` | compile error (T33) | Repeat the expression as the leading order key: `order { bm25($d.body, $q) desc }`; the projection reads that ordering's score |
| `rrf(...) as fused` in `return` | compile error (T37) | Not yet a column; order by `rrf(...)` and project plain columns |
| Adding non-nullable property without backfill | unsupported migration | Make optional → backfill; keep it optional (tightening `T?` → `T` is refused, OG-MF-106) |
| `omnigraph init --json` | `unexpected argument --json` | `init` doesn't support `--json`; drop the flag |
| `omnigraph init` on an already-initialized URI | `AlreadyInitialized` error | Never overwrite it. `--force` only replaces orphan schema artifacts after proving there is no graph manifest |
Expand Down Expand Up @@ -322,6 +319,7 @@ For anything beyond the basics, load the relevant reference file. Each is self-c
| [`references/blobs.md`](references/blobs.md) | Writing and reading managed/external Blob values, selectors/ranges, security and lifecycle boundaries |
| [`references/changes.md`](references/changes.md) | Exact read/write positions, conditional mutations, commit diffs, feed cursors, baselines, and retention gaps |
| [`references/remote-ops.md`](references/remote-ops.md) | Operating through `--server`: exact receipts, unknown 504 outcomes, conflict handling, and safe retry decisions |
| [`references/cluster.md`](references/cluster.md) | Cluster configuration, plan/apply, approvals, drift, and serving |
| [`references/search.md`](references/search.md) | Embeddings, `@embed`, vector/text ranking, scope-then-rank pattern |
| [`references/aliases.md`](references/aliases.md) | Defining aliases for agents, structured output, JSON args |
| [`references/stored-queries.md`](references/stored-queries.md) | Cluster stored-query registry: declaration, `queries validate/list --cluster`, served invocation, and `invoke_query` Cedar gating |
Expand Down
16 changes: 0 additions & 16 deletions skills/omnigraph/references/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,6 @@ omnigraph branch delete <branch-name> --store $REPO
All support `--json`. `--delete-branch` removes the source only after a
successful merge publication.

Each operation is also a GQ statement through the data verbs. Wrong-door rule:
`branch create`, `branch delete`, and `branch merge` are control writes and go
through `mutate`; `branch list` is a read and goes through `query`. A statement
takes no `--branch`, `--snapshot`, `--if-commit`, positional name, or `--params`.

```bash
omnigraph mutate -e 'branch create "<branch-name>" from main' --store $REPO
omnigraph query -e 'branch list' --format table --store $REPO
omnigraph mutate -e 'branch merge "<branch-name>" into main' --store $REPO
omnigraph mutate -e 'branch delete "<branch-name>"' --store $REPO # --yes or a TTY answer against a non-local target
```

A name outside the identifier alphabet `[a-z_][a-z0-9_]*` is quoted (see
[`data.md`](data.md)); quoting a name that needs no quotes is always allowed.

## Commits (History)

```bash
Expand Down Expand Up @@ -179,7 +164,6 @@ Aliases are read-only. Invoke a served stored mutation with `omnigraph mutate
<name> --server ...`.

> `query` and `mutate` also accept inline source via `-e/--query-string '<gq>'` instead of `--query <file>`.
> The source may be one branch statement: `mutate -e 'branch create|delete|merge …'`, `query -e 'branch list'` (see Branches above).

## Maintenance

Expand Down
26 changes: 2 additions & 24 deletions skills/omnigraph/references/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ edits.
> escapes the row ceiling but not the 32 MiB strict-input Arrow preflight
> (`strict_input_arrow_bytes`), so a bulk replacement above ~32 MiB is one
> `overwrite` chunk followed by `merge` chunks. Also: against a non-local
> target, `--mode overwrite` (like `cleanup` and `branch delete`, verb or
> statement) requires explicit `--yes` consent in non-interactive runs.
> target, `--mode overwrite` (like `cleanup` and `branch delete`) requires
> explicit `--yes` consent in non-interactive runs.
>
> **Direct and served are one command.** `load` works against a graph store
> (writing storage directly) *and* an `omnigraph-server` endpoint (the
Expand Down Expand Up @@ -181,28 +181,6 @@ All support `--json` for automation-friendly output. Address the graph with a
positional `file://`/`s3://`/preview `az://` URI (shown), `--store <uri>`, or
`--server <name>`.

The same four operations are GQ statements, for a client that already sends
`.gq` source. Wrong-door rule: the control writes go through `mutate`, the
listing through `query`; the other verb refuses the statement. A statement
names its branches itself, so `--branch`, `--snapshot`, `--if-commit`, a
positional name, and `--params` are refused beside it.

```bash
omnigraph mutate -e 'branch create "<branch-name>" from main' --store $REPO
omnigraph query -e 'branch list' --format table --store $REPO
omnigraph mutate -e 'branch merge "<branch-name>" into main' --store $REPO
omnigraph mutate -e 'branch delete "<branch-name>"' --store $REPO
```

A name outside the identifier alphabet `[a-z_][a-z0-9_]*` (an uppercase
letter, a leading digit, `/`, `-`, or `.`) is quoted: `branch create
"staging-2026-04-14"`. Quoting a name that needs no quotes is always allowed.
`from` and `into` default to `main`.
`--json` on a control write prints a `ChangeOutput` with `outcome.kind`
(`created`, `deleted`, `merged`) and, for a merge, `outcome.merge`; the
statement form has no `--delete-branch`, so delete the source with a second
statement.

## Inspecting State After Changes

```bash
Expand Down
4 changes: 2 additions & 2 deletions skills/omnigraph/references/migrations.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Migration and Retired Vocabulary

The rest of this skill describes OmniGraph 0.10.x. Use this page only to
The rest of this skill describes released OmniGraph 0.10.0. Use this page only to
recognize an older command, config, route, or upgrade boundary.

## Upgrade v0.9 to v0.10
Expand Down Expand Up @@ -40,7 +40,7 @@ boundary is required.
v0.10 also removes ambiguous client vocabulary such as `table_key`, `row_id`,
`manifest_version`, `rows_loaded`, and `export --table`. Use node/edge, type,
entity, property, graph-manifest, and published-dataset terms plus
`export --type`. See the canonical [upgrade procedure](../../../docs/user/operations/upgrade.md).
`export --type`. See the [v0.10.0 upgrade procedure](https://github.com/ModernRelay/omnigraph/blob/v0.10.0/docs/user/operations/upgrade.md).

## Pre-0.7 configuration

Expand Down
Loading
Loading