{ "openapi": "3.1.0", "info": { "title": "Omnigraph API", "description": "HTTP API for the Omnigraph graph database", "license": { "name": "MIT", "identifier": "MIT" }, "version": "0.6.1" }, "paths": { "/branches": { "get": { "tags": [ "branches" ], "summary": "List all branches.", "description": "Returns branch names sorted alphabetically. Read-only.", "operationId": "listBranches", "responses": { "200": { "description": "List of branches", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BranchListOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] }, "post": { "tags": [ "branches" ], "summary": "Create a new branch.", "description": "Forks `name` off of `from` (defaults to `main`). The new branch shares\ntable data with its parent until it is mutated. Returns 409 if `name`\nalready exists.", "operationId": "createBranch", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BranchCreateRequest" } } }, "required": true }, "responses": { "200": { "description": "Branch created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BranchCreateOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "409": { "description": "Branch already exists", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/branches/merge": { "post": { "tags": [ "branches" ], "summary": "Merge one branch into another.", "description": "Merges `source` into `target` (defaults to `main`). Outcome is one of\n`already_up_to_date`, `fast_forward`, or `merged`. Returns 409 with the\nlist of conflicts if the merge cannot be completed; the target is left\nunchanged in that case. **Destructive** to `target` on success.", "operationId": "mergeBranches", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BranchMergeRequest" } } }, "required": true }, "responses": { "200": { "description": "Branches merged", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BranchMergeOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "409": { "description": "Merge conflict", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/branches/{branch}": { "delete": { "tags": [ "branches" ], "summary": "Delete a branch.", "description": "**Irreversible.** Removes the branch pointer; commits remain reachable\nonly if referenced by another branch. Returns 404 if the branch does not\nexist.", "operationId": "deleteBranch", "parameters": [ { "name": "branch", "in": "path", "description": "Branch name to delete", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Branch deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BranchDeleteOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "404": { "description": "Branch not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/change": { "post": { "tags": [ "mutations" ], "summary": "**Deprecated** — use [`POST /mutate`](#tag/mutations/operation/mutate) instead.", "description": "Apply a GQ mutation to a branch. Behavior is unchanged; the route is\nkept indefinitely for back-compat. New integrations should target\n`POST /mutate`, which has identical semantics and a name that pairs\ncleanly with `POST /query`. Responses from this route include\n`Deprecation: true` and `Link: ; rel=\"successor-version\"`\nheaders per RFC 9745 / RFC 8288 so SDKs and proxies can surface the\nsignal.", "operationId": "change", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeRequest" } } }, "required": true }, "responses": { "200": { "description": "Mutation results (response includes `Deprecation: true` + `Link: ; rel=\"successor-version\"`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "409": { "description": "Merge conflict", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "deprecated": true, "security": [ { "bearer_token": [] } ] } }, "/commits": { "get": { "tags": [ "commits" ], "summary": "List commits.", "description": "Filter by `branch` to get the commits on a single branch (most recent\nfirst); omit to list across all branches. Read-only.", "operationId": "listCommits", "parameters": [ { "name": "branch", "in": "query", "required": false, "schema": { "type": [ "string", "null" ] } } ], "responses": { "200": { "description": "List of commits", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommitListOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/commits/{commit_id}": { "get": { "tags": [ "commits" ], "summary": "Get a single commit.", "description": "Returns the commit's manifest version, parent commit(s), and creation\nmetadata. Read-only.", "operationId": "getCommit", "parameters": [ { "name": "commit_id", "in": "path", "description": "Commit identifier", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Commit details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommitOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "404": { "description": "Commit not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/export": { "post": { "tags": [ "queries" ], "summary": "Stream the contents of a branch as NDJSON.", "description": "Emits one JSON object per line (`application/x-ndjson`). Filter with\n`type_names` (node/edge type names) and/or `table_keys`; both empty\nstreams the entire branch. Suitable for large exports — the response is\nstreamed, not buffered. Read-only.", "operationId": "export", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExportRequest" } } }, "required": true }, "responses": { "200": { "description": "Exported data as NDJSON", "content": { "application/x-ndjson": {} } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/graphs": { "get": { "tags": [ "management" ], "summary": "List every graph currently registered with this server (MR-668).", "description": "Multi-graph mode only. In single mode, the route returns 405 — there's\nno registry to enumerate. Cedar-gated by the server-level policy via\nthe `graph_list` action against `Omnigraph::Server::\"root\"`.\n\nOrder: alphabetical by `graph_id` (server-sorted so clients see\ndeterministic output across requests).", "operationId": "listGraphs", "responses": { "200": { "description": "List of registered graphs", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GraphListResponse" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "405": { "description": "Method not allowed (single-graph mode)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/healthz": { "get": { "tags": [ "health" ], "summary": "Liveness probe.", "description": "Returns server status and version. Unauthenticated; safe to call from any\ncaller. Use this to confirm the server is reachable before invoking other\nendpoints.", "operationId": "health", "responses": { "200": { "description": "Server is healthy", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthOutput" } } } } } } }, "/ingest": { "post": { "tags": [ "mutations" ], "summary": "Bulk-ingest NDJSON data into a branch.", "description": "`data` is NDJSON with one record per line. `mode` controls behavior on\nexisting rows: `merge` upserts by id (default), `append` blindly inserts,\n`overwrite` replaces table contents. If `branch` does not exist it is\ncreated from `from` (defaults to `main`). **Destructive** when `mode` is\n`overwrite` or when ingest produces conflicting writes.", "operationId": "ingest", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IngestRequest" } } }, "required": true }, "responses": { "200": { "description": "Ingest results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IngestOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/mutate": { "post": { "tags": [ "mutations" ], "summary": "Apply a GQ mutation to a branch (canonical mutation endpoint).", "description": "Writes to the named `branch` (defaults to `main`). Mutations are atomic\nper call and produce a new commit. Returns counts of nodes and edges\naffected. **Destructive**: on success the branch is updated; rejected\nmutations may still acquire locks briefly. Returns 409 on merge conflict.\n\nPairs with `POST /query` (read-only). The legacy `POST /change` route\nhas identical semantics and is kept as a deprecated alias.", "operationId": "mutate", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeRequest" } } }, "required": true }, "responses": { "200": { "description": "Mutation results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "409": { "description": "Merge conflict", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/queries": { "get": { "tags": [ "queries" ], "summary": "List the graph's exposed stored queries as a typed tool catalog.", "description": "Returns the `mcp.expose == true` subset of the `queries:` registry, each\nwith its MCP tool name, read/mutate flag, description/instruction, and\ntyped parameters — enough for a client to register them as tools without\nfetching `.gq` source. Read-gated; the catalog is graph-wide (branch\nindependent — `read` is authorized against `main`). **Not** Cedar-filtered\nper query yet, so it can list a query whose `invoke_query` the caller\nlacks (a known gap until per-query authorization lands).", "operationId": "list_queries", "responses": { "200": { "description": "Stored-query catalog (the mcp.expose subset, with typed params)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueriesCatalogOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/queries/{name}": { "post": { "tags": [ "queries" ], "summary": "Invoke a curated, server-side stored query by name.", "description": "The query source comes from the graph's `queries:` registry, not the\nrequest body — callers send only runtime inputs (`params`, `branch`,\n`snapshot`). Gated by the `invoke_query` Cedar action at the boundary;\na stored *mutation* additionally passes the engine's `change` gate\n(double-gated). An actor **without** `invoke_query` cannot tell a denied\nquery from a missing one — both return the same 404, so the catalog\ncan't be probed without the grant. Once `invoke_query` is held, the\ninner `read`/`change` gate may surface a 403 for an existing query the\nactor can't run (the intended double-gate signal).", "operationId": "invoke_query", "parameters": [ { "name": "name", "in": "path", "description": "Stored query name (the registry key)", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/InvokeStoredQueryRequest" } ] } } } }, "responses": { "200": { "description": "Read envelope (ReadOutput) or mutation envelope (ChangeOutput), serialized untagged", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InvokeStoredQueryResponse" } } } }, "400": { "description": "Bad request (param type error; snapshot on a stored mutation)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden (the inner `change` gate for a stored mutation)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "404": { "description": "Unknown stored query, or `invoke_query` denied — indistinguishable to a caller without the grant", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "409": { "description": "Merge conflict", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "500": { "description": "Policy evaluation error (a denial is reported as 404, not 500)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/query": { "post": { "tags": [ "queries" ], "summary": "Execute an inline read query (friendlier-named alternative to `POST /read`).", "description": "Designed for ad-hoc exploration and AI-agent tool-use: short field\nnames (`query`, `name`) match the CLI `-e` flag and the GQ `query`\nkeyword. Mutations (`insert`/`update`/`delete`) are rejected with 400\n-- use `POST /mutate` (or its deprecated alias `POST /change`) for\nwrite queries. Otherwise behaves identically to `POST /read`: same\ntarget semantics (branch xor snapshot), same Cedar action (Read),\nsame response shape.", "operationId": "query", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueryRequest" } } }, "required": true }, "responses": { "200": { "description": "Query results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadOutput" } } } }, "400": { "description": "Bad request - also returned when the query body contains mutations; use POST /mutate (or its deprecated alias POST /change) for write queries", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/read": { "post": { "tags": [ "queries" ], "summary": "**Deprecated** — use [`POST /query`](#tag/queries/operation/query) instead.", "description": "Execute a GQ read query. Behavior is unchanged from prior releases; the\nroute is kept indefinitely for byte-stable back-compat. New integrations\nshould target `POST /query`, which has clean field names (`query` /\n`name`) and a 400-on-mutation guard. Responses from this route include\n`Deprecation: true` and `Link: ; rel=\"successor-version\"`\nheaders per RFC 9745 / RFC 8288 so SDKs and proxies can surface the\nsignal.", "operationId": "read", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadRequest" } } }, "required": true }, "responses": { "200": { "description": "Query results (response includes `Deprecation: true` + `Link: ; rel=\"successor-version\"`)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "deprecated": true, "security": [ { "bearer_token": [] } ] } }, "/schema": { "get": { "tags": [ "schema" ], "summary": "Read the current schema source.", "description": "Returns the project's schema as a single string in `.pg` source form.\nUseful for clients that want to introspect available types and tables\nbefore constructing GQ queries. Read-only.", "operationId": "getSchema", "responses": { "200": { "description": "Current schema source", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SchemaOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/schema/apply": { "post": { "tags": [ "mutations" ], "summary": "Apply a schema migration.", "description": "Diffs `schema_source` against the current schema and applies the resulting\nmigration steps (add/drop type, add/drop column, etc.). **Destructive**:\nsome steps drop data. Returns the list of steps applied; if `applied` is\nfalse the diff was unsupported and no changes were made.", "operationId": "applySchema", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SchemaApplyRequest" } } }, "required": true }, "responses": { "200": { "description": "Schema apply results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SchemaApplyOutput" } } } }, "400": { "description": "Bad request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "429": { "description": "Per-actor admission cap exceeded; honor `Retry-After` header", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } }, "/snapshot": { "get": { "tags": [ "snapshots" ], "summary": "Read the current snapshot of a branch.", "description": "Returns the manifest version plus per-table metadata (path, version, row\ncount) for every table on the branch. Defaults to `main` when `branch` is\nomitted. Read-only.", "operationId": "getSnapshot", "parameters": [ { "name": "branch", "in": "query", "required": false, "schema": { "type": [ "string", "null" ] } } ], "responses": { "200": { "description": "Database snapshot", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SnapshotOutput" } } } }, "401": { "description": "Unauthorized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } }, "403": { "description": "Forbidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorOutput" } } } } }, "security": [ { "bearer_token": [] } ] } } }, "components": { "schemas": { "BranchCreateOutput": { "type": "object", "required": [ "uri", "from", "name" ], "properties": { "actor_id": { "type": [ "string", "null" ] }, "from": { "type": "string" }, "name": { "type": "string" }, "uri": { "type": "string" } } }, "BranchCreateRequest": { "type": "object", "required": [ "name" ], "properties": { "from": { "type": [ "string", "null" ], "description": "Parent branch to fork from. Defaults to `main`." }, "name": { "type": "string", "description": "Name of the new branch. Must not already exist." } } }, "BranchDeleteOutput": { "type": "object", "required": [ "uri", "name" ], "properties": { "actor_id": { "type": [ "string", "null" ] }, "name": { "type": "string" }, "uri": { "type": "string" } } }, "BranchListOutput": { "type": "object", "required": [ "branches" ], "properties": { "branches": { "type": "array", "items": { "type": "string" } } } }, "BranchMergeOutcome": { "type": "string", "enum": [ "already_up_to_date", "fast_forward", "merged" ] }, "BranchMergeOutput": { "type": "object", "required": [ "source", "target", "outcome" ], "properties": { "actor_id": { "type": [ "string", "null" ] }, "outcome": { "$ref": "#/components/schemas/BranchMergeOutcome" }, "source": { "type": "string" }, "target": { "type": "string" } } }, "BranchMergeRequest": { "type": "object", "required": [ "source" ], "properties": { "source": { "type": "string", "description": "Source branch whose commits will be merged." }, "target": { "type": [ "string", "null" ], "description": "Target branch that will receive the merge. Defaults to `main`." } } }, "ChangeOutput": { "type": "object", "required": [ "branch", "query_name", "affected_nodes", "affected_edges" ], "properties": { "actor_id": { "type": [ "string", "null" ] }, "affected_edges": { "type": "integer", "minimum": 0 }, "affected_nodes": { "type": "integer", "minimum": 0 }, "branch": { "type": "string" }, "query_name": { "type": "string" } } }, "ChangeRequest": { "type": "object", "required": [ "query" ], "properties": { "branch": { "type": [ "string", "null" ], "description": "Target branch. Defaults to `main`." }, "name": { "type": [ "string", "null" ], "description": "Name of the mutation to run when `query` declares multiple.\n\nAccepts the legacy field name `query_name` as a deserialization alias." }, "params": { "description": "JSON object whose keys match the mutation's declared parameters." }, "query": { "type": "string", "description": "GQ mutation source containing `insert`, `update`, or `delete` statements.\nMay declare multiple named mutations; pick one with `name`.\n\nAccepts the legacy field name `query_source` as a deserialization alias.", "example": "query insert_person($name: String, $age: I32) {\n insert Person { name: $name, age: $age }\n}" } } }, "CommitListOutput": { "type": "object", "required": [ "commits" ], "properties": { "commits": { "type": "array", "items": { "$ref": "#/components/schemas/CommitOutput" } } } }, "CommitOutput": { "type": "object", "required": [ "graph_commit_id", "manifest_version", "created_at" ], "properties": { "actor_id": { "type": [ "string", "null" ] }, "created_at": { "type": "integer", "format": "int64", "description": "Commit creation time as Unix epoch microseconds.", "example": 1714000000000000 }, "graph_commit_id": { "type": "string" }, "manifest_branch": { "type": [ "string", "null" ] }, "manifest_version": { "type": "integer", "format": "int64", "minimum": 0 }, "merged_parent_commit_id": { "type": [ "string", "null" ] }, "parent_commit_id": { "type": [ "string", "null" ] } } }, "ErrorCode": { "type": "string", "enum": [ "unauthorized", "forbidden", "bad_request", "not_found", "method_not_allowed", "conflict", "too_many_requests", "internal" ] }, "ErrorOutput": { "type": "object", "required": [ "error" ], "properties": { "code": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ErrorCode" } ] }, "error": { "type": "string" }, "manifest_conflict": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ManifestConflictOutput", "description": "Set when the conflict is a publisher CAS rejection\n(`ManifestConflictDetails::ExpectedVersionMismatch`). The caller's\npre-write view of `table_key` was at version `expected` but the\nmanifest is now at `actual`. Refresh and retry." } ] }, "merge_conflicts": { "type": "array", "items": { "$ref": "#/components/schemas/MergeConflictOutput" } } } }, "ExportRequest": { "type": "object", "properties": { "branch": { "type": [ "string", "null" ], "description": "Branch to export. Defaults to `main`." }, "table_keys": { "type": "array", "items": { "type": "string" }, "description": "Restrict the export to these table keys. Empty exports all tables." }, "type_names": { "type": "array", "items": { "type": "string" }, "description": "Restrict the export to these node/edge type names. Empty exports all types." } } }, "GraphInfo": { "type": "object", "description": "One entry in the response from `GET /graphs`. Cluster operators\nconsume this list to discover which graphs the server is currently\nserving. The shape is intentionally minimal — `graph_id` and `uri`\nare the only fields a routing client needs.", "required": [ "graph_id", "uri" ], "properties": { "graph_id": { "type": "string" }, "uri": { "type": "string" } } }, "GraphListResponse": { "type": "object", "description": "Response from `GET /graphs`. Lists every graph registered with the\nserver in alphabetical order by `graph_id` (sorted server-side so\nclients get deterministic output across requests).", "required": [ "graphs" ], "properties": { "graphs": { "type": "array", "items": { "$ref": "#/components/schemas/GraphInfo" } } } }, "HealthOutput": { "type": "object", "required": [ "status", "version" ], "properties": { "source_version": { "type": [ "string", "null" ] }, "status": { "type": "string" }, "version": { "type": "string" } } }, "IngestOutput": { "type": "object", "required": [ "uri", "branch", "base_branch", "branch_created", "mode", "tables" ], "properties": { "actor_id": { "type": [ "string", "null" ] }, "base_branch": { "type": "string" }, "branch": { "type": "string" }, "branch_created": { "type": "boolean" }, "mode": { "$ref": "#/components/schemas/LoadMode" }, "tables": { "type": "array", "items": { "$ref": "#/components/schemas/IngestTableOutput" } }, "uri": { "type": "string" } } }, "IngestRequest": { "type": "object", "required": [ "data" ], "properties": { "branch": { "type": [ "string", "null" ], "description": "Target branch. Created from `from` if it does not yet exist. Defaults to `main`." }, "data": { "type": "string", "description": "NDJSON payload: one record per line, each shaped\n`{\"type\": \"\", \"data\": {...}}`.", "example": "{\"type\": \"Person\", \"data\": {\"name\": \"Alice\", \"age\": 30}}\n{\"type\": \"Person\", \"data\": {\"name\": \"Bob\", \"age\": 25}}" }, "from": { "type": [ "string", "null" ], "description": "Parent branch used to create `branch` if it does not exist. Defaults to `main`." }, "mode": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/LoadMode", "description": "How existing rows are handled. Defaults to `merge`." } ] } } }, "IngestTableOutput": { "type": "object", "required": [ "table_key", "rows_loaded" ], "properties": { "rows_loaded": { "type": "integer", "minimum": 0 }, "table_key": { "type": "string" } } }, "InvokeStoredQueryRequest": { "type": "object", "description": "Body for `POST /queries/{name}` — invokes the server-side stored query\nnamed in the path. The query source and name come from the registry,\nnever the body; only the runtime inputs are supplied here.", "properties": { "branch": { "type": [ "string", "null" ], "description": "Branch to run against. Defaults to `main`; for a stored mutation the\nwrite targets this branch." }, "params": { "description": "JSON object whose keys match the stored query's declared parameters." }, "snapshot": { "type": [ "string", "null" ], "description": "Snapshot id to read from (read queries only — rejected for a stored\nmutation). Mutually exclusive with `branch`." } } }, "InvokeStoredQueryResponse": { "oneOf": [ { "$ref": "#/components/schemas/ReadOutput" }, { "$ref": "#/components/schemas/ChangeOutput" } ], "description": "Response for `POST /queries/{name}`: the read envelope for a stored\nread, or the mutation envelope for a stored mutation. Serialized\n**untagged**, so the wire shape is exactly [`ReadOutput`] or\n[`ChangeOutput`] — classification follows the stored query, not a\nwrapper field." }, "LoadMode": { "type": "string", "description": "Shadow enum for documenting [`LoadMode`] in the OpenAPI schema.", "enum": [ "overwrite", "append", "merge" ] }, "ManifestConflictOutput": { "type": "object", "description": "Structured details for a publisher-level OCC failure. Surfaces alongside\nHTTP 409 when a write was rejected because the caller's pre-write view of\none table's manifest version was stale relative to the current head. The\nexpected/actual fields tell the client which table to refresh.", "required": [ "table_key", "expected", "actual" ], "properties": { "actual": { "type": "integer", "format": "int64", "minimum": 0 }, "expected": { "type": "integer", "format": "int64", "minimum": 0 }, "table_key": { "type": "string" } } }, "MergeConflictKindOutput": { "type": "string", "enum": [ "divergent_insert", "divergent_update", "delete_vs_update", "orphan_edge", "unique_violation", "cardinality_violation", "value_constraint_violation" ] }, "MergeConflictOutput": { "type": "object", "required": [ "table_key", "kind", "message" ], "properties": { "kind": { "$ref": "#/components/schemas/MergeConflictKindOutput" }, "message": { "type": "string" }, "row_id": { "type": [ "string", "null" ] }, "table_key": { "type": "string" } } }, "ParamDescriptor": { "type": "object", "description": "One declared parameter of a stored query, projected for the catalog.", "required": [ "name", "kind", "nullable" ], "properties": { "item_kind": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ParamKind", "description": "Element kind when `kind == list` (always a scalar — the grammar\nforbids lists of vectors or nested lists)." } ] }, "kind": { "$ref": "#/components/schemas/ParamKind" }, "name": { "type": "string" }, "nullable": { "type": "boolean", "description": "`false` → the caller must supply it; `true` → optional." }, "vector_dim": { "type": [ "integer", "null" ], "format": "int32", "description": "Dimension when `kind == vector`.", "minimum": 0 } } }, "ParamKind": { "type": "string", "description": "The kind of a stored-query parameter, decomposed so a client (e.g. an\nMCP server) can build a typed input schema with a closed `match` and\nnever re-parse omnigraph's type spelling. `bigint`/`date`/`datetime`/\n`blob` are carried as JSON strings on the wire: a 64-bit integer past\n2^53 loses precision as a JSON number, and Date/DateTime are ISO\nstrings, Blob a blob-URI string.", "enum": [ "string", "bool", "int", "bigint", "float", "date", "datetime", "blob", "vector", "list" ] }, "QueriesCatalogOutput": { "type": "object", "description": "Response for `GET /queries`: the `mcp.expose` subset of a graph's\nstored-query registry, each with typed parameters.", "required": [ "queries" ], "properties": { "queries": { "type": "array", "items": { "$ref": "#/components/schemas/QueryCatalogEntry" } } } }, "QueryCatalogEntry": { "type": "object", "description": "One entry in the stored-query catalog (`GET /queries`).", "required": [ "name", "tool_name", "mutation", "params" ], "properties": { "description": { "type": [ "string", "null" ] }, "instruction": { "type": [ "string", "null" ] }, "mutation": { "type": "boolean", "description": "`true` for a stored mutation → an MCP read-only hint of `false`." }, "name": { "type": "string", "description": "Registry key / invoke path segment (`POST /queries/{name}`)." }, "params": { "type": "array", "items": { "$ref": "#/components/schemas/ParamDescriptor" } }, "tool_name": { "type": "string", "description": "MCP tool id (the `tool_name` override, else `name`)." } } }, "QueryRequest": { "type": "object", "description": "Inline read-query request for `POST /query`.\n\nFriendlier-named alternative to [`ReadRequest`] for ad-hoc reads and\nAI-agent integration. Mutations are rejected with 400 — use `POST\n/mutate` (or its deprecated alias `POST /change`) for write queries.\nField names are deliberately short (`query`, `name`) to match the GQ\nkeyword and the CLI `-e` flag.", "required": [ "query" ], "properties": { "branch": { "type": [ "string", "null" ], "description": "Branch to read from. Mutually exclusive with `snapshot`. Defaults to `main`." }, "name": { "type": [ "string", "null" ], "description": "Name of the query to run when `query` declares multiple. Optional when\nonly one query is declared." }, "params": { "description": "JSON object whose keys match the query's declared parameters." }, "query": { "type": "string", "description": "GQ read-query source. May declare one or more named queries; pick one\nwith `name` when more than one is declared. Mutations\n(`insert`/`update`/`delete`) get 400 — use `POST /mutate` (or its\ndeprecated alias `POST /change`) instead.", "example": "query get_person($name: String) {\n match {\n $p: Person { name: $name }\n }\n return { $p.name, $p.age }\n}" }, "snapshot": { "type": [ "string", "null" ], "description": "Snapshot id to read from. Mutually exclusive with `branch`." } } }, "ReadOutput": { "type": "object", "required": [ "query_name", "target", "row_count", "rows" ], "properties": { "columns": { "type": "array", "items": { "type": "string" } }, "query_name": { "type": "string" }, "row_count": { "type": "integer", "minimum": 0 }, "rows": {}, "target": { "$ref": "#/components/schemas/ReadTargetOutput" } } }, "ReadRequest": { "type": "object", "required": [ "query_source" ], "properties": { "branch": { "type": [ "string", "null" ], "description": "Branch to read from. Mutually exclusive with `snapshot`. Defaults to `main`." }, "params": { "description": "JSON object whose keys match the query's declared parameters." }, "query_name": { "type": [ "string", "null" ], "description": "Name of the query to run when `query_source` declares multiple. Optional\nwhen only one query is declared." }, "query_source": { "type": "string", "description": "GQ query source. May declare one or more named queries; pick one with\n`query_name` if there is more than one.", "example": "query get_person($name: String) {\n match {\n $p: Person { name: $name }\n }\n return { $p.name, $p.age }\n}" }, "snapshot": { "type": [ "string", "null" ], "description": "Snapshot id to read from. Mutually exclusive with `branch`." } } }, "ReadTargetOutput": { "type": "object", "properties": { "branch": { "type": [ "string", "null" ] }, "snapshot": { "type": [ "string", "null" ] } } }, "SchemaApplyOutput": { "type": "object", "required": [ "uri", "supported", "applied", "step_count", "manifest_version", "steps" ], "properties": { "applied": { "type": "boolean" }, "manifest_version": { "type": "integer", "format": "int64", "minimum": 0 }, "step_count": { "type": "integer", "minimum": 0 }, "steps": { "type": "array", "items": {} }, "supported": { "type": "boolean" }, "uri": { "type": "string" } } }, "SchemaApplyRequest": { "type": "object", "required": [ "schema_source" ], "properties": { "allow_data_loss": { "type": "boolean", "description": "When true, promote every `DropMode::Soft` step in the plan to\n`DropMode::Hard`, making the prior column data unreachable\nafter the apply. Matches the CLI's `--allow-data-loss` flag.\nDefaults to `false` (drops remain reversible via time travel)." }, "schema_source": { "type": "string", "description": "Project schema in `.pg` source form. The diff against the current\nschema produces the migration steps that will be applied.", "example": "node Person {\n name: String @key\n age: I32?\n}\n\nedge Knows: Person -> Person" } } }, "SchemaOutput": { "type": "object", "required": [ "schema_source" ], "properties": { "schema_source": { "type": "string" } } }, "SnapshotOutput": { "type": "object", "required": [ "branch", "manifest_version", "tables" ], "properties": { "branch": { "type": "string" }, "manifest_version": { "type": "integer", "format": "int64", "minimum": 0 }, "tables": { "type": "array", "items": { "$ref": "#/components/schemas/SnapshotTableOutput" } } } }, "SnapshotTableOutput": { "type": "object", "required": [ "table_key", "table_path", "table_version", "row_count" ], "properties": { "row_count": { "type": "integer", "format": "int64", "minimum": 0 }, "table_branch": { "type": [ "string", "null" ] }, "table_key": { "type": "string" }, "table_path": { "type": "string" }, "table_version": { "type": "integer", "format": "int64", "minimum": 0 } } } }, "securitySchemes": { "bearer_token": { "type": "http", "scheme": "bearer" } } } }