xrayGraphDB  ›  Documentation

xrayGraphDB Documentation

Install the engine, connect a client, learn Cypher and GFQL, then explore the complete interactive reference of 395 functions and 125 procedures. Version 1, generated 2026-06-27.

Installation: Docker

Docker is the fastest way to start xrayGraphDB. The image ships with sensible defaults — storage path, ports, and encryption at rest. Pull it, bootstrap an admin on the first run, and you're up.

Before you run anything: raise the host's memory-map limit so the database can start: sudo sysctl -w vm.max_map_count=262144 (persist it in /etc/sysctl.d/).

First run — bootstrap an admin

The daemon refuses connections without an admin user. Pass --init-admin-user and --init-admin-password on the first start to create one. These flags are bootstrap-only — they only create a user when no users exist, and become silent no-ops on every subsequent boot once the admin record is on disk.

Shell — first run only
# Pull (or `docker load < xraygraphdb-4.9.4-docker.tar.gz` for the offline tarball)
docker pull xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4

# First run — creates admin/<your-password> on initial boot
docker run -d \
  --name xraygraphdb \
  --restart unless-stopped \
  -p 7689:7689 \
  -v xraygraphdb-data:/var/lib/xraygraphdb \
  -v xraygraphdb-logs:/var/log/xraygraphdb \
  xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 \
  --license-acknowledge-saved=true \
  --init-admin-user=admin \
  --init-admin-password=YourStrongPassword!23

# Wait ~5s, then confirm the daemon is listening
docker logs xraygraphdb | grep "xrayProtocol listening"
# Expected: "xrayProtocol listening on 0.0.0.0:7689 with 4 workers"

Security: rotate the bootstrap flags off after the first boot. Once the daemon confirms it's listening, the admin record is persisted in /var/lib/xraygraphdb/auth/ and the --init-admin-* flags do nothing on restart. But they remain visible in three places — docker inspect xraygraphdb (full Args[]), /var/lib/docker/containers/<id>/config.v2.json on the host, and ps aux inside the container. Recreate the container without the bootstrap flags so the password isn't sitting in process args:

Shell — every run after the first
docker stop xraygraphdb && docker rm xraygraphdb
docker run -d \
  --name xraygraphdb \
  --restart unless-stopped \
  -p 7689:7689 \
  -v xraygraphdb-data:/var/lib/xraygraphdb \
  -v xraygraphdb-logs:/var/log/xraygraphdb \
  xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 \
  --license-acknowledge-saved=true

The named volumes xraygraphdb-data and xraygraphdb-logs persist the database state and logs across container recreations. The data path inside the image is /var/lib/xraygraphdb (matches the daemon's default --data-directory).

Enterprise license (optional)

If you have a license file, mount it read-only at /etc/xraygraphdb/license.xglicense. The daemon auto-detects and validates it on startup:

Shell
docker run -d \
  --name xraygraphdb \
  -p 7689:7689 \
  -v xraygraphdb-data:/var/lib/xraygraphdb \
  -v /path/to/license.xglicense:/etc/xraygraphdb/license.xglicense:ro \
  xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4 \
  --license-acknowledge-saved=true

docker logs xraygraphdb | grep "License loaded"
# Expected: "License loaded: xg-ent-... tier=enterprise org=..."

Without a license, the community-tier graph algorithms (PageRank, BFS, triangle count, betweenness, community detection, and more) run unrestricted. An enterprise license unlocks the additional commercial procedure namespaces.

Docker Compose

YAML — docker-compose.yml
services:
  xraygraphdb:
    image: xraygraphdb.emtailabs.com/xraygraphdb:v4.9.4
    restart: unless-stopped
    ports:
      - "7689:7689"
    volumes:
      - xraygraphdb-data:/var/lib/xraygraphdb
      - xraygraphdb-logs:/var/log/xraygraphdb
      # Optional: Enterprise license
      # - ./license.xglicense:/etc/xraygraphdb/license.xglicense:ro
    command:
      - --license-acknowledge-saved=true
      # --- FIRST RUN ONLY: uncomment for the first `docker compose up`,
      # --- then comment back out and `docker compose up -d --force-recreate`.
      # - --init-admin-user=admin
      # - --init-admin-password=YourStrongPassword!23

volumes:
  xraygraphdb-data:
  xraygraphdb-logs:
Shell
docker compose up -d
docker compose logs -f xraygraphdb | grep "xrayProtocol listening"

Verify the Server

Shell
# Container status
docker ps --filter name=xraygraphdb

# Daemon ready check — xrayProtocol on 7689 (Bolt is OFF by default; opt-in via --bolt-server-name)
docker logs xraygraphdb | grep "xrayProtocol listening"
# Expected: "xrayProtocol listening on 0.0.0.0:7689 with 4 workers"

# Test connection (Python xray_protocol_client; HELLO must carry a database name)
python3 -c 'import xray_protocol_client as xg
conn = xg.connect(host="localhost", port=7689,
                  auth_token="admin:YourStrongPassword!23",
                  database="xraygraphdb")
print(conn.execute_query("MATCH (n) RETURN count(n) AS n_count"))'

Installation: Linux

Two install paths on Ubuntu 24.04 LTS: the .deb package (recommended — auto-resolves runtime deps via apt) or the portable .tar.gz (everything bundled, runs against the system glibc).

.deb — Ubuntu / Debian

Shell
# 1. Download
wget https://xraygraphdb.emtailabs.com/downloads/xraygraphdb_4.9.4_amd64.deb

# 2. Install — use `apt install -f` so apt auto-resolves the libgdal34t64 + python3 deps.
#    `dpkg -i` directly will FAIL the first time with "depends on libgdal34t64; however ...".
sudo apt install -f ./xraygraphdb_4.9.4_amd64.deb

.tar.gz — portable build (any glibc ≥ 2.39)

The tarball ships every C/C++ runtime we need (libstdc++, libLLVM, libsolclient, libssl, libcrypto, libxraygraphdb_module_support) under lib/. The install.sh wrapper drops them at /usr/lib/xraygraphdb/lib, registers the path with ldconfig, installs the systemd unit, and apt-installs the one external dep (libgdal34t64).

Shell
wget https://xraygraphdb.emtailabs.com/downloads/xraygraphdb-4.9.4-linux-x86_64.tar.gz
tar xzf xraygraphdb-4.9.4-linux-x86_64.tar.gz
cd xraygraphdb-4.9.4-linux-x86_64
sudo ./install.sh

Configure — required systemd drop-in

The default /lib/systemd/system/xraygraphdb.service ships an empty ExecStart sentinel so you can layer site-local flags via a drop-in without forking the unit file. Create the drop-in before the first systemctl start:

Shell
sudo mkdir -p /etc/systemd/system/xraygraphdb.service.d
sudo tee /etc/systemd/system/xraygraphdb.service.d/local.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/lib/xraygraphdb/xraygraphdb \
    --data-directory=/var/lib/xraygraphdb \
    --bolt-port=7687 \
    --xray-port=7689 \
    --storage-properties-on-edges=true \
    --log-level=WARNING \
    --license-acknowledge-saved=true \
    --bolt_listen_mode=off
EOF

sudo systemctl daemon-reload
sudo systemctl start xraygraphdb
sudo systemctl status xraygraphdb
ss -tlnp | grep :7689     # xrayProtocol
Multi-tenant encryption at rest.

Enterprise multi-tenant deployments can encrypt each tenant's data at rest using your own key management system (HashiCorp Vault, AWS KMS, or a compatible KMS). Setup is covered in the licensed admin guide. Single-tenant and evaluation installs work out of the box with no additional configuration.

Critical: Always stop xrayGraphDB with SIGTERM (graceful shutdown). Never use kill -9. A forced kill skips the final snapshot and may result in data loss on next recovery.

Installation: macOS

macOS is supported for development only. For production workloads use Linux or Docker.

Shell
# Download macOS binary (Apple Silicon or Intel)
curl -LO https://releases.emtailabs.com/xraygraphdb/xraygraphdb-v4.9.4-macos-arm64.tar.gz

# Extract and run
tar xzf xraygraphdb-v4.9.4-macos-arm64.tar.gz
cd xraygraphdb-v4.9.4
./bin/xraygraphdb-wrapper

On macOS you may also use Docker Desktop, which is the recommended approach for local development.

First Boot: Bootstrap Admin

Fresh installs ship with no users in the auth store. The daemon will not let you create the first admin user over the wire (chicken-and-egg), so you must run the one-time bootstrap helper before the database is usable. This step does not apply to replica nodes — replicas inherit the admin user from the cluster's MAIN; see Cluster Setup.

Shell
sudo xraygraphdb-bootstrap-admin

The helper:

  1. Generates a 24-character random password.
  2. Displays it once on your terminal in red.
  3. Asks you to retype it to confirm you copied it.
  4. Writes the username/password to /run/xraygraphdb/bootstrap.env — this is a tmpfs file, never on disk — and starts the daemon.
  5. Schedules an ExecStartPost hook that wipes the env file ~15 seconds after the daemon comes up.
The password is shown exactly once. The script does not write it to any persistent file on this server. Copy it to your password manager when prompted. If you lose it, the only recovery is to wipe /var/lib/xraygraphdb and re-run the bootstrap — the existing user data is unrecoverable.

Loading datasets — where to put files

The default systemd unit ships with PrivateTmp=true for sandbox hardening. That gives the daemon its own private /tmp/ namespace, separate from the host's /tmp/. Anything you place in the host's /tmp/ is invisible to the daemon, and bulk-import calls against those paths fail-fast with 0 vertices / 0 edges in under a second — no error in the journal.

Do not put datasets in /tmp/. Even though the dataset file is world-readable, the daemon cannot see it. Use /var/lib/xraygraphdb/import/ instead — this path is in the unit's ReadWritePaths=, owned by the xraygraphdb user, and shares the daemon's namespace.
Shell
# Right way — daemon can read it:
sudo mkdir -p /var/lib/xraygraphdb/import
sudo mv ~/com-friendster.ungraph.txt /var/lib/xraygraphdb/import/
sudo chown -R xraygraphdb:xraygraphdb /var/lib/xraygraphdb/import

# Then in your bench/import script:
client.bulk_import_file("/var/lib/xraygraphdb/import/com-friendster.ungraph.txt")

# Wrong way — daemon's PrivateTmp namespace makes this invisible:
#   client.bulk_import_file("/tmp/com-friendster.ungraph.txt")    ← returns 0/0 in 1s

If you need a different dataset path (e.g. a large NVMe mount at /data/), add it to the systemd unit's ReadWritePaths= via a drop-in:

/etc/systemd/system/xraygraphdb.service.d/datasets.conf
[Service]
ReadWritePaths=/data

Then systemctl daemon-reload && systemctl restart xraygraphdb, and the daemon can read/write under /data/.

If the host is going to join an existing cluster as a replica, skip this section and use xraygraphdb-cluster-join instead.

Creating a Database

xrayGraphDB has no default database. Every connection must name one, either in the connection string or with USE DATABASE — a connection that names none is rejected. So creating a database is the first thing you do after bootstrapping admin.

Cypher
-- Connect AS the user who should own this database, then:
CREATE DATABASE myapp;

-- Confirm it exists and switch to it
SHOW DATABASES;
USE DATABASE myapp;
Create the database while connected as the user who will own it — not as admin on their behalf. The creating user becomes the database's permanent owner, recorded once at creation, and that owner binding is what the analytics and embedding procedures check before returning anything. Create a database as admin, then connect as alice, and ordinary queries work perfectly — but xray.embed, the analyzers and the vector-index procedures all return zero rows with no error, because alice does not own it. The failure is silent and looks exactly like "there is no data". If analyzers return nothing on a database that plainly has data, check who created it first.

The owner is fixed at creation and there is no command to change it afterwards. If a database was created under the wrong user, the supported fix is to drop it and recreate it as the correct owner:

Cypher
-- Destructive: this deletes the data. Re-import afterwards.
DROP DATABASE myapp;

-- Now reconnect AS the intended owner and create it again
CREATE DATABASE myapp;

Two more conditions must hold for the owner binding to be recorded, and both are easy to trip over:

  • Pick a name other than xraygraphdb. That is the built-in bootstrap database, which every node creates independently at startup. It is deliberately excluded from the ownership catalog, so it can never carry an owner and the analyzers will always return zero rows on it. Use it to connect and administer; create your own database for your data.
  • Create it on the MAIN, not on a replica. Replicas receive databases through replication; a database created directly on a replica has no owner binding.

Ownership is per database, and it is a boundary, not a preference: it is what stops one tenant's analytics from reading another's graph. Granting a user access to a database lets them query it; it does not make them its owner.

Options

CREATE DATABASE accepts an optional WITH clause:

Cypher
CREATE DATABASE analytics WITH
  storage_mode = 'mmap',        -- overrides the server's --storage-engine default
  mmap_reservation_gb = '64',   -- per-database mmap ceiling, fixed when the files open
  wal = 'true',
  snapshot_interval = '300';

Unknown properties are ignored with a warning in the server log rather than failing the statement, so check the log if an option appears to have had no effect.

Cluster Setup

A cluster is one or more coordinators (which hold the replicated cluster state and issue leases) plus the data instances that serve queries. A data instance joins by being registered with a coordinator; it inherits the admin user from the cluster's MAIN, so you do not run the bootstrap helper on a replica.

Cypher
REGISTER INSTANCE inst_1 WITH CONFIG {
  "bolt_server":        "10.0.0.11:7687",
  "management_server":  "10.0.0.11:37801",
  "replication_server": "10.0.0.11:37811"
};

Run that against a coordinator. Cluster statements require the CONFIG privilege, so the account you use must hold it. Inter-node traffic is mutually authenticated TLS and fails closed: a cluster-role node will refuse to start without valid certificate material.

Licence Seats & Replacing a Node

Your licence grants a number of seats. A seat is a concurrency limit — the maximum number of data instances attached to the cluster at any one moment. It is not a lifetime activation count, so there is no penalty for replacing hardware. You may swap machines as often as you need; only the number attached at once is counted.

If more nodes attach than you have seats for, the excess enter an overage grace state rather than being cut off abruptly, and the oldest waiting node is promoted automatically as soon as a seat frees up.

Replacing a failed node — the normal path

This path is entirely self-service. You do not need to contact eMTAi.

  1. Release the seat. On a coordinator, unregister the dead instance. The seat is freed immediately and any node waiting in overage grace is promoted into it.
Cypher
UNREGISTER INSTANCE inst_1;
  1. Provision the replacement with a fresh, empty data directory.
  2. Register it with REGISTER INSTANCE as above. It takes the freed seat and replication rebuilds its data from the cluster.

Both the release and the registration are recorded as audit events for your SIEM, emitted only when the change actually completed.

Reusing the failed node's data directory

Restoring the old data directory onto different hardware is a separate case and is refused by design. A data directory is cryptographically bound to the machine that activated it — that binding is what prevents a directory being copied to run extra unlicensed instances.

This needs a recovery certificate. When a restored data directory boots on new hardware the daemon refuses to adopt it and writes a recovery request file. Send that request to eMTAi; you will receive a signed recovery certificate that rebinds the directory to the new machine. The certificate is single-use and is marked spent once applied. To avoid this entirely, use a fresh data directory (the path above) and let replication repopulate the node.

Which should you choose? For an ordinary hardware failure, a fresh data directory is faster and needs no vendor round-trip. Reserve the recovery-certificate path for cases where the data itself must be preserved in place — for example a single-node deployment with no replica to rebuild from.

Checking seat usage

Use SHOW INSTANCES on a coordinator to see every attached instance and its current state, including any sitting in overage grace.

Cypher
SHOW INSTANCES;

Connect

First-party clients speak xrayProtocol on port 7689; the Bolt port 7689's companion 7687 is provided for triage compatibility. Pick your language below.

First Connection: Python

xrayGraphDB is compatible with the official Neo4j Python driver. Install it with pip and connect over the Bolt protocol.

Shell
pip install neo4j
Python
from neo4j import GraphDatabase

driver = GraphDatabase.driver(
    "bolt://localhost:7687",
    auth=("admin", "<your-password>")
)

with driver.session() as session:
    # Create a node
    session.run(
        "CREATE (n:Person {name: $name, age: $age})",
        name="Alice", age=30
    )

    # Read it back
    result = session.run(
        "MATCH (n:Person {name: $name}) RETURN n.name, n.age",
        name="Alice"
    )
    record = result.single()
    print(record["n.name"], record["n.age"])
    # Output: Alice 30

driver.close()

First Connection: JavaScript

Shell
npm install neo4j-driver
JavaScript
const neo4j = require('neo4j-driver');

const driver = neo4j.driver(
  'bolt://localhost:7687',
  neo4j.auth.basic('admin', '<your-password>')
);

const session = driver.session();

try {
  // Create a node
  await session.run(
    'CREATE (n:Person {name: $name, age: $age})',
    { name: 'Bob', age: 25 }
  );

  // Read it back
  const result = await session.run(
    'MATCH (n:Person {name: $name}) RETURN n',
    { name: 'Bob' }
  );

  console.log(result.records[0].get('n').properties);
} finally {
  await session.close();
  await driver.close();
}

First Connection: Java

Add the Neo4j Java driver to your Maven or Gradle project.

XML
<!-- Maven dependency -->
<dependency>
  <groupId>org.neo4j.driver</groupId>
  <artifactId>neo4j-java-driver</artifactId>
  <version>5.x</version>
</dependency>
Java
import org.neo4j.driver.*;

public class XRayExample {
    public static void main(String[] args) {
        var driver = GraphDatabase.driver(
            "bolt://localhost:7687",
            AuthTokens.basic("admin", "<your-password>")
        );

        try (var session = driver.session()) {
            session.run(
                "CREATE (n:Person {name: $name})",
                Values.parameters("name", "Carol")
            );

            var result = session.run(
                "MATCH (n:Person) RETURN n.name"
            );

            while (result.hasNext()) {
                System.out.println(result.next().get("n.name").asString());
            }
        }
        driver.close();
    }
}

First Connection: Go

Shell
go get github.com/neo4j/neo4j-go-driver/v5
Go
package main

import (
    "context"
    "fmt"
    "github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

func main() {
    ctx := context.Background()

    driver, err := neo4j.NewDriverWithContext(
        "bolt://localhost:7687",
        neo4j.BasicAuth("admin", "<your-password>", ""),
    )
    if err != nil { panic(err) }
    defer driver.Close(ctx)

    session := driver.NewSession(ctx, neo4j.SessionConfig{})
    defer session.Close(ctx)

    _, err = session.Run(ctx,
        "CREATE (n:Person {name: $name})",
        map[string]any{"name": "Dave"},
    )
    if err != nil { panic(err) }

    result, err := session.Run(ctx,
        "MATCH (n:Person) RETURN n.name", nil,
    )
    if err != nil { panic(err) }

    for result.Next(ctx) {
        fmt.Println(result.Record().Values[0])
    }
}

First Connection: .NET

Shell
dotnet add package Neo4j.Driver
C#
using Neo4j.Driver;

var driver = GraphDatabase.Driver(
    "bolt://localhost:7687",
    AuthTokens.Basic("admin", "<your-password>")
);

await using var session = driver.AsyncSession();

await session.RunAsync(
    "CREATE (n:Person {name: $name})",
    new { name = "Eve" }
);

var result = await session.RunAsync(
    "MATCH (n:Person) RETURN n.name"
);

var records = await result.ToListAsync();
foreach (var record in records)
{
    Console.WriteLine(record["n.name"].As<string>());
}

await driver.DisposeAsync();

Quick Start Tutorial

This tutorial walks through creating a small graph, querying it, and cleaning up. It assumes you have a running xrayGraphDB instance and a Python driver installed.

Cypher
// Step 1: Create some nodes
CREATE (alice:Person {name: "Alice", age: 30})
CREATE (bob:Person {name: "Bob", age: 25})
CREATE (carol:Person {name: "Carol", age: 35})
CREATE (proj:Project {name: "xrayGraphDB"})
RETURN alice, bob, carol, proj;

// Step 2: Create relationships
MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"})
CREATE (a)-[:KNOWS]->(b)
RETURN a, b;

MATCH (a:Person {name: "Alice"}), (p:Project {name: "xrayGraphDB"})
CREATE (a)-[:WORKS_ON {role: "lead"}]->(p)
RETURN a, p;

MATCH (b:Person {name: "Bob"}), (p:Project {name: "xrayGraphDB"})
CREATE (b)-[:WORKS_ON {role: "contributor"}]->(p)
RETURN b, p;

// Step 3: Query the graph
MATCH (p:Person)-[:WORKS_ON]->(proj:Project)
RETURN p.name, proj.name;

// Step 4: Update properties
MATCH (a:Person {name: "Alice"})
SET a.email = "alice@example.com"
RETURN a;

// Step 5: Clean up
MATCH (n) DETACH DELETE n;
Tip: Use parameterized queries in production code. Inline values in Cypher strings are shown here for readability but should be replaced with parameters ($name, $age, etc.) to prevent injection and improve plan cache hit rates.

MATCH

The MATCH clause is the primary read operation. It describes a pattern to find in the graph and binds matching subgraphs to variables.

Cypher
// Match all nodes with a specific label
MATCH (n:Person)
RETURN n;

// Match a relationship pattern
MATCH (a:Person)-[:KNOWS]->(b:Person)
RETURN a.name, b.name;

// Match with relationship variable
MATCH (a:Person)-[r:WORKS_ON]->(p:Project)
RETURN a.name, r.role, p.name;

// Match any direction
MATCH (a:Person)-[:KNOWS]-(b:Person)
RETURN a.name, b.name;

// Match with multiple labels
MATCH (n:Person:Employee)
RETURN n;

Patterns can include any combination of nodes, relationships, and directions. Nodes are enclosed in parentheses (), relationships in square brackets [], and direction is indicated by arrows -> or <-.

WHERE

The WHERE clause filters results from MATCH patterns. It supports comparison operators, boolean logic, string matching, list predicates, and null checks.

Cypher
// Comparison operators
MATCH (n:Person)
WHERE n.age > 25 AND n.age <= 40
RETURN n.name, n.age;

// String matching
MATCH (n:Person)
WHERE n.name STARTS WITH "A"
RETURN n;

// Regular expression
MATCH (n:Person)
WHERE n.email =~ ".*@example\\.com"
RETURN n;

// Null checks
MATCH (n:Person)
WHERE n.email IS NOT NULL
RETURN n;

// IN list
MATCH (n:Person)
WHERE n.name IN ["Alice", "Bob", "Carol"]
RETURN n;

// Pattern predicates (exists)
MATCH (n:Person)
WHERE (n)-[:WORKS_ON]->()
RETURN n.name;
OperatorDescriptionExample
=Equaln.age = 30
<>Not equaln.name <> "Alice"
<, >, <=, >=Comparisonn.age >= 18
AND, OR, NOTBoolean logicn.age > 20 AND n.active = true
INList membershipn.status IN ["active", "pending"]
STARTS WITHString prefixn.name STARTS WITH "Al"
ENDS WITHString suffixn.name ENDS WITH "ice"
CONTAINSString containsn.name CONTAINS "li"
=~Regex matchn.email =~ ".*@example\\.com"
IS NULLNull checkn.deleted IS NULL
IS NOT NULLNot nulln.email IS NOT NULL

RETURN

RETURN specifies which values to include in the result set. You can return nodes, relationships, properties, expressions, or aggregations.

Cypher
// Return specific properties
MATCH (n:Person)
RETURN n.name, n.age;

// Alias with AS
MATCH (n:Person)
RETURN n.name AS person_name, n.age AS years;

// Return all properties as a map
MATCH (n:Person)
RETURN properties(n);

// Return distinct values
MATCH (n:Person)-[:WORKS_ON]->(p:Project)
RETURN DISTINCT p.name;

// Expressions in RETURN
MATCH (n:Person)
RETURN n.name, n.age * 12 AS age_in_months;

ORDER BY / LIMIT / SKIP

Control the ordering and pagination of results.

Cypher
// Order by a property
MATCH (n:Person)
RETURN n.name, n.age
ORDER BY n.age DESC;

// Limit results
MATCH (n:Person)
RETURN n.name
ORDER BY n.name
LIMIT 10;

// Pagination with SKIP and LIMIT
MATCH (n:Person)
RETURN n.name
ORDER BY n.name
SKIP 20
LIMIT 10;

// Multiple sort keys
MATCH (n:Person)
RETURN n.name, n.age
ORDER BY n.age DESC, n.name ASC;

WITH

WITH acts as a pipeline separator, allowing you to chain query stages together. Variables not listed in WITH are not available in subsequent clauses.

Cypher
// Filter intermediate results
MATCH (p:Person)-[:WORKS_ON]->(proj:Project)
WITH proj, count(p) AS team_size
WHERE team_size > 3
RETURN proj.name, team_size
ORDER BY team_size DESC;

// Chain queries
MATCH (n:Person)
WITH n
ORDER BY n.age DESC
LIMIT 5
MATCH (n)-[:KNOWS]->(friend)
RETURN n.name, collect(friend.name) AS friends;

UNWIND

UNWIND expands a list into individual rows. Useful for bulk operations and working with list parameters.

Cypher
// Expand a list
UNWIND [1, 2, 3] AS x
RETURN x;

// Bulk create from parameters
UNWIND $people AS person
CREATE (n:Person {name: person.name, age: person.age});

// Combine with MATCH
UNWIND ["Alice", "Bob"] AS name
MATCH (n:Person {name: name})
RETURN n;

OPTIONAL MATCH

OPTIONAL MATCH works like MATCH but returns null for missing parts of the pattern instead of excluding the row entirely. Equivalent to a left outer join.

Cypher
// Return all people, even those without projects
MATCH (p:Person)
OPTIONAL MATCH (p)-[:WORKS_ON]->(proj:Project)
RETURN p.name, proj.name;

CREATE

CREATE adds new nodes and relationships to the graph. It always creates new elements (use MERGE to avoid duplicates).

Cypher
// Create a single node
CREATE (n:Person {name: "Frank", age: 28})
RETURN n;

// Create multiple nodes
CREATE (a:Person {name: "Grace"}),
       (b:Person {name: "Hank"});

// Create a node with multiple labels
CREATE (n:Person:Developer {name: "Ivy"});

// Create a relationship between existing nodes
MATCH (a:Person {name: "Grace"}), (b:Person {name: "Hank"})
CREATE (a)-[:KNOWS {since: 2024}]->(b)
RETURN a, b;

// Create a full path in one statement
CREATE (a:Module {name: "auth"})-[:IMPORTS]->(b:Module {name: "crypto"})
RETURN a, b;

MERGE

MERGE ensures a pattern exists in the graph. If the pattern is found, it is bound. If not found, it is created. Use ON CREATE SET and ON MATCH SET to conditionally set properties.

Cypher
// Merge a node (create if not exists)
MERGE (n:Person {name: "Alice"})
ON CREATE SET n.created = timestamp()
ON MATCH SET n.lastSeen = timestamp()
RETURN n;

// Merge a relationship
MATCH (a:Person {name: "Alice"}), (b:Person {name: "Bob"})
MERGE (a)-[r:KNOWS]->(b)
ON CREATE SET r.since = 2024
RETURN r;
Note: MERGE matches the entire pattern. If you merge on (a)-[:KNOWS]->(b) and the relationship does not exist, it creates only the relationship, not the nodes (they must already be bound by a preceding MATCH or MERGE).

SET

SET updates properties on nodes and relationships, or adds labels to nodes.

Cypher
// Set a property
MATCH (n:Person {name: "Alice"})
SET n.age = 31
RETURN n;

// Set multiple properties
MATCH (n:Person {name: "Alice"})
SET n.age = 31, n.email = "alice@example.com"
RETURN n;

// Replace all properties with a map
MATCH (n:Person {name: "Alice"})
SET n = {name: "Alice", age: 31, active: true}
RETURN n;

// Merge properties (add without removing existing)
MATCH (n:Person {name: "Alice"})
SET n += {department: "engineering"}
RETURN n;

// Add a label
MATCH (n:Person {name: "Alice"})
SET n:Employee
RETURN n;

REMOVE

REMOVE deletes properties from nodes/relationships and removes labels from nodes.

Cypher
// Remove a property
MATCH (n:Person {name: "Alice"})
REMOVE n.email
RETURN n;

// Remove a label
MATCH (n:Person:Employee {name: "Alice"})
REMOVE n:Employee
RETURN labels(n);

DELETE / DETACH DELETE

DELETE removes nodes and relationships. A node cannot be deleted if it still has relationships. Use DETACH DELETE to delete a node and all its relationships in one operation.

Cypher
// Delete a relationship
MATCH (a:Person)-[r:KNOWS]->(b:Person)
WHERE a.name = "Alice" AND b.name = "Bob"
DELETE r;

// Delete a node (must have no relationships)
MATCH (n:Person {name: "Frank"})
DELETE n;

// Detach delete (node + all relationships)
MATCH (n:Person {name: "Alice"})
DETACH DELETE n;

// Delete all nodes and relationships in the database
MATCH (n) DETACH DELETE n;
Warning: MATCH (n) DETACH DELETE n removes the entire graph. There is no undo. Make a snapshot before running destructive queries on production data.

Variable-length Paths

Variable-length path patterns match paths of varying depth using the * syntax inside relationship brackets.

Cypher
// Paths of exactly 2 hops
MATCH (a:Person)-[:KNOWS*2]->(c:Person)
RETURN a.name, c.name;

// Paths of 1 to 5 hops
MATCH (a:Person)-[:KNOWS*1..5]->(c:Person)
RETURN a.name, c.name;

// Paths of any length (use with caution)
MATCH (a:Person {name: "Alice"})-[:KNOWS*]->(c:Person)
RETURN DISTINCT c.name;

// Capture the path
MATCH path = (a:Person {name: "Alice"})-[:KNOWS*1..3]->(c:Person)
RETURN path, length(path) AS hops;
Note: Unbounded variable-length paths (* without limits) can be expensive on large graphs. Always set an upper bound when possible.

shortestPath / allShortestPaths

Not supported in v5. shortestPath() and allShortestPaths() are not yet in the Cypher grammar and will fail to parse. Verified against the engine on 2026-08-13. Use a bounded variable-length pattern and take the shortest match: MATCH p=(a)-[:REL*1..5]->(b) RETURN length(p) ORDER BY length(p) LIMIT 1 — or min(length(p)). Both are verified working. Note this enumerates paths rather than stopping at the first, so bound the depth on large graphs.

Find the shortest path(s) between two nodes.

Cypher
// Find one shortest path
MATCH (a:Person {name: "Alice"}),
      (b:Person {name: "Eve"})
MATCH p = shortestPath((a)-[*..10]-(b))
RETURN p, length(p) AS hops;

// Find all shortest paths (same length)
MATCH (a:Person {name: "Alice"}),
      (b:Person {name: "Eve"})
MATCH p = allShortestPaths((a)-[*..10]-(b))
RETURN p;

// With relationship type filter
MATCH (a:Person {name: "Alice"}),
      (b:Person {name: "Eve"})
MATCH p = shortestPath((a)-[:KNOWS|WORKS_WITH*..10]-(b))
RETURN p;

BFS Traversal

Not supported in v5. The BFS edge-modifier syntax (-[:REL BFS]->) is not in the Cypher grammar and will fail to parse. Verified against the engine on 2026-08-13. Use an ordinary variable-length pattern: MATCH p=(a)-[:REL*1..3]->(b), which is verified working and breadth-bounded by the depth you give it.

Breadth-first search traversal is available for exploring graphs level by level. BFS guarantees that nodes are visited in order of increasing distance from the start node.

Cypher
// BFS with upper bound
MATCH (start:Person {name: "Alice"})
MATCH path = (start)-[:KNOWS BFS]->(target)
RETURN target.name, length(path) AS distance
ORDER BY distance;

BFS traversal is the default algorithm used by shortestPath. Use the explicit BFS syntax when you need to enumerate all reachable nodes by distance layer.

Aggregation

Aggregation functions operate on groups of rows. Non-aggregated columns in RETURN act as implicit group keys (similar to SQL GROUP BY).

Cypher
// Count
MATCH (n:Person)
RETURN count(n) AS total_people;

// Group and count
MATCH (p:Person)-[:WORKS_ON]->(proj:Project)
RETURN proj.name, count(p) AS team_size
ORDER BY team_size DESC;

// Sum, average, min, max
MATCH (n:Person)
RETURN
  sum(n.age) AS total_age,
  avg(n.age) AS avg_age,
  min(n.age) AS youngest,
  max(n.age) AS oldest;

// Collect into a list
MATCH (p:Person)-[:WORKS_ON]->(proj:Project)
RETURN proj.name, collect(p.name) AS members;

// Standard deviation and percentile
MATCH (n:Person)
RETURN
  stDev(n.age) AS std_dev,
  percentileCont(n.age, 0.5) AS median;
FunctionDescriptionExample
count(expr)Number of non-null valuescount(n)
sum(expr)Sum of numeric valuessum(n.salary)
avg(expr)Average of numeric valuesavg(n.age)
min(expr)Minimum valuemin(n.created)
max(expr)Maximum valuemax(n.score)
collect(expr)Collect values into a listcollect(n.name)
percentileCont(expr, p)Continuous percentile (interpolated)percentileCont(n.age, 0.5)
percentileDisc(expr, p)Discrete percentile (nearest value)percentileDisc(n.age, 0.9)
stDev(expr)Standard deviation (sample)stDev(n.score)
stDevP(expr)Standard deviation (population)stDevP(n.score)

Indexing & Constraints

Indexes accelerate lookups by property value. Constraints enforce data integrity rules.

Cypher
// Create a label-property index
CREATE INDEX ON :Person(name);

// Neo4j-compatible named index syntax
CREATE INDEX person_name_idx
FOR (n:Person)
ON (n.name);

// Composite index
CREATE INDEX ON :Person(name, age);

// Drop an index
DROP INDEX ON :Person(name);

// Unique constraint
CREATE CONSTRAINT ON (n:Person) ASSERT n.email IS UNIQUE;

// Existence constraint
CREATE CONSTRAINT ON (n:Person) ASSERT EXISTS (n.name);

// Show index info
SHOW INDEX INFO;

// List all constraints
SHOW CONSTRAINT INFO;
Tip: Always create indexes on properties used in WHERE clauses and MATCH patterns. Without an index, the engine must scan all nodes of a given label.

Transactions

Not supported in v5. Bare BEGIN; / COMMIT; / ROLLBACK; statements are not supported — none of BEGIN, COMMIT, ROLLBACK, TRANSACTION or EXPLICIT is an accepted top-level keyword. Verified against the engine on 2026-08-13. Use driver-managed transactions (the client example above: session.begin_transaction()tx.commit() / tx.rollback()). Every single statement is already atomic on its own, and SHOW TRANSACTIONS is available for inspection.

xrayGraphDB supports both auto-commit transactions (single query) and explicit transactions (multi-query).

Auto-commit Transactions

Every query sent via session.run() runs in its own auto-commit transaction. If the query succeeds, it is committed. If it fails, it is rolled back.

Explicit Transactions

Use explicit transactions when you need to execute multiple queries atomically.

Python
with driver.session() as session:
    tx = session.begin_transaction()
    try:
        tx.run("CREATE (a:Account {id: $id, balance: $bal})",
               id="A001", bal=1000)
        tx.run("CREATE (a:Account {id: $id, balance: $bal})",
               id="A002", bal=500)
        tx.commit()
    except Exception:
        tx.rollback()
        raise
Cypher
// Explicit transaction commands (Bolt protocol)
BEGIN;
CREATE (n:Temp {data: "test"});
COMMIT;

// Or rollback
BEGIN;
CREATE (n:Temp {data: "test"});
ROLLBACK;
Built-in Functions and Procedures. xrayGraphDB ships with a comprehensive library of built-in functions, procedures, and GFQL operators — every entry below is queryable at runtime via CALL xg.builtin_functions() and available in the Community edition at no cost.

GFQL Overview

Syntax corrected 2026-08-13. Earlier revisions of this page showed a fluent dot-chained API (chain().n(label='Person').filter(age >= 18)). That form does not parse. GFQL composes operations comma-separated inside chain(…), uses : for named arguments (not =), and expresses filters as object literals. Every example below was executed against the engine.

Sending a GFQL query

GFQL is a second language on the same connection, not a Cypher function. It is selected by the language byte of the xrayProtocol EXECUTE frame: 0 = Cypher, 1 = GFQL. There is no CALL gfql(…) procedure, and chain() / n() are not callable from Cypher — attempting either returns “Function 'chain' doesn't exist”.

# Python, via the xrayProtocol client
client.execute("chain(n(), e_forward(hops: 2), n())", language=1)   # 1 = GFQL
client.execute("MATCH (n) RETURN count(n)",           language=0)   # 0 = Cypher

Verified operations

Executed against a three-node graph (Alice → Bob → Carol, joined by KNOWS; complexity 12 / 3 / 20). The row counts are the actual results returned.

GFQLRowsMeaning
chain(n())3every node
chain(n(), e_forward(), n())2one-hop outgoing pairs
chain(n(), e_forward(hops: 2), n())1exactly two hops (Alice→Carol)
chain(n(), e_forward(min_hops: 1, max_hops: 3), n())3bounded range of hops
chain(n({complexity_gt: 10}))2object-literal filter (Alice 12, Carol 20)
chain(n(), e_reverse(), n())2incoming edges
chain(n(), distinct())3deduplicate
chain(n(), limit(2))2row cap

Named arguments take a colon (hops: 2, min_hops: 1). Analytic operations follow the same shape — e.g. betweenness_centrality_sampled(epsilon: 0.05). Enumerate everything available with CALL xg.procedures().

GFQL (Graph Frame Query Language) is a dataframe-native query language for graph traversal and analysis. It is designed for data scientists and developers who prefer chainable, functional-style operations over declarative pattern matching.

GFQL queries run natively inside the xrayGraphDB engine alongside Cypher. They operate on the same in-memory graph as Cypher queries, with the same transaction isolation guarantees.

Note: GFQL is available starting with xrayGraphDB v4.0. It can be used alongside Cypher in the same database without conflicts.

SET GFQL_CONTEXT

Before executing GFQL operations, set a query context that defines the working scope (labels, edge types, or property filters).

GFQL
// Set context to all Function nodes
SET GFQL_CONTEXT label='Function';

// Set context with edge filter
SET GFQL_CONTEXT label='Module', edge_type='IMPORTS';

// Set context with property filter
SET GFQL_CONTEXT label='Person', WHERE age > 25;

chain(), n(), e_forward(), e_reverse()

GFQL operations are chained together using a fluent API. The core primitives are:

FunctionDescriptionExample
chain()Start a GFQL operation chainchain()
n()Select nodes (optionally filtered)n(label='Person')
e_forward()Traverse outgoing edgese_forward(type='CALLS')
e_reverse()Traverse incoming edgese_reverse(type='CALLS')
.filter()Filter current frame.filter(complexity > 5)
.hop()Multi-hop traversal.hop(edge_type='CALLS', depth=3)
.select()Project specific columns.select('name', 'module')
.aggregate()Group and aggregate.aggregate(by='module', count='name')
GFQL
// Find high-complexity functions and their callees
chain()
  .n(label='Function')
  .filter(complexity > 10)
  .e_forward(type='CALLS')
  .select('source.name', 'target.name');

// Multi-hop traversal
chain()
  .n(label='Module', name='auth')
  .hop(edge_type='IMPORTS', depth=3)
  .select('name', '_hop_depth');

// Aggregate by module
chain()
  .n(label='Function')
  .aggregate(by='module', count='name', avg_complexity='complexity');

Filter Predicates

GFQL supports the following predicates inside .filter() expressions:

OperatorDescriptionExample
=, !=Equality / inequality.filter(status = 'active')
>, <, >=, <=Comparison.filter(age >= 18)
AND, ORLogical operators.filter(age > 18 AND active = true)
NOTLogical negation.filter(NOT deleted)
INList membership.filter(status IN ['active', 'pending'])
LIKEPattern matching (% wildcard).filter(name LIKE 'auth%')
IS NULLNull check.filter(email IS NULL)
IS NOT NULLNot null.filter(email IS NOT NULL)

Function Reference

489 built-in functions. Click a category in the sidebar to filter, or use the search box. Click any card to expand its full signature and details.

Procedure Reference

Enumerate the surface yourself. The engine self-documents: CALL xg.procedures() YIELD name, signature, description, mode lists every callable procedure with its full signature, and CALL xg.builtin_functions() YIELD name lists every function. Note the namespace is xg.mg.procedures() and mg.functions() do not exist on xrayGraphDB, nor do SHOW PROCEDURES / SHOW FUNCTIONS. Verified 2026-08-13.

284 callable procedures invoked with CALL.

Additional Procedure Namespaces

Generated from the engine's own metadata via CALL xg.procedures() on 2026-08-13. The engine exposes 284 callable procedures in total; the 76 below were not previously documented.

xg.* — 59 procedures

ProcedureSignatureDescriptionMode
xg._internal_repair_tenant_idxg._internal_repair_tenant_id() :: (repaired :: INTEGER, skipped :: INTEGER, total :: INTEGER)Internal maintenance procedure that repairs missing or invalid tenant identifiers on existing records.read
xg.allocator_purge_nowxg.allocator_purge_now() :: (elapsed_us :: INTEGER, ok :: BOOLEAN)Force the memory allocator to purge unused arenas immediately, returning whether it succeeded and the elapsed time.write
xg.chain_reclaim_statsxg.chain_reclaim_stats() :: (counter_name :: STRING, value :: INTEGER)Report counters for the version-chain reclamation subsystem.read
xg.compute_rabbit_orderxg.compute_rabbit_order(community_max_iter :: INTEGER, output_path :: STRING) :: (new_id :: INTEGER, num_communities :: INTEGER, old_id :: INTEGER, time_ms :: INTEGER)Compute a cache-friendly Rabbit-Order vertex permutation via community clustering and optionally write it to a file.read
xg.concept.listxg.concept.list() :: (concept_id :: INTEGER, dimension :: STRING, has_embedding :: BOOLEAN, name :: STRING, near_count :: INTEGER)List registered concept labels with their concept id, dimension, embedding presence, and near-neighbor count.read
xg.concept.nearxg.concept.near(label_name :: STRING) :: (concept_id :: INTEGER, name :: STRING, similarity :: FLOAT)List concepts most similar to a given label by embedding similarity.read
xg.concept.rebuild_nearxg.concept.rebuild_near() :: (rebuilt :: INTEGER)Rebuild the precomputed :NEAR concept-similarity edges from current concept embeddings.write
xg.concept.set_dimensionxg.concept.set_dimension(label_name :: STRING, dimension :: STRING) :: (dimension :: STRING, name :: STRING)Assign a semantic dimension to a concept label.write
xg.concept.set_embeddingxg.concept.set_embedding(label_name :: STRING, embedding :: LIST OF ANY) :: (dim :: INTEGER, has_embedding :: BOOLEAN, name :: STRING)Set the embedding vector for a concept label.write
xg.cptcs_truncatexg.cptcs_truncate(below_lsn :: INTEGER, operator_note :: STRING, operator_id :: STRING) :: (actual_below_lsn :: INTEGER, error_code :: STRING, lagging_replicas :: STRING, ok :: BOOLEAN, truncated_counOperator procedure to truncate the CPTCS catalog log below a given LSN, refusing if replicas are still lagging.write
xg.create_module_filexg.create_module_file(filename :: STRING, content :: STRING) :: (path :: STRING)Create a new query-module source file with the given filename and content.read
xg.delete_module_filexg.delete_module_file(path :: STRING) :: ()Delete a query-module source file at the given path.read
xg.disclosure_auditxg.disclosure_audit(query_text :: STRING, nodes_used :: LIST OF INTEGER, edges_used :: LIST OF INTEGER, columns_used :: LIST OF STRING, vectors_used :: LIST OF STRING, source_refs :: LIST OF STRING, aWrite a disclosure-grade audit record capturing the query, the nodes/edges/columns/vectors used, source references, assumptions, confidence, and model version.write
xg.envelope_validatexg.envelope_validate(prop_names :: LIST OF STRING, kind :: STRING) :: (missing :: LIST OF STRING, ok :: BOOLEAN)Validate that a set of property names satisfies the required envelope for a given kind, reporting any missing properties.read
xg.functionsxg.functions() :: (description :: STRING, is_editable :: BOOLEAN, mode :: STRING, name :: STRING, path :: STRING, signature :: STRING)List all registered functions (built-in and user-defined).read
xg.get_module_filexg.get_module_file(path :: STRING) :: (content :: STRING)Return the source content of a query-module file at the given path.read
xg.get_module_filesxg.get_module_files() :: (is_editable :: BOOLEAN, path :: STRING)List all query-module files with their path and whether they are editable.read
xg.governance_disclosure_textxg.governance_disclosure_text() :: (text :: STRING)Return the canonical governance/disclosure text for the deployment.read
xg.graphrag.retrievexg.graphrag.retrieve(query_text :: STRING, k :: INTEGER) :: (gid :: INTEGER, score :: FLOAT, signals :: STRING)Retrieve the top-k nodes for a natural-language query using native GraphRAG, returning each node's gid, score, and contributing signals.read
xg.kafka_set_stream_offsetxg.kafka_set_stream_offset(stream_name :: STRING, offset :: INTEGER) :: ()Set the consumer offset for a named Kafka ingestion stream so it resumes consuming from that position.read
xg.kafka_stream_infoxg.kafka_stream_info(stream_name :: STRING) :: (bootstrap_servers :: STRING, configs :: MAP, consumer_group :: STRING, credentials :: MAP, topics :: LIST OF STRING)Report configuration for a named Kafka ingestion stream: bootstrap servers, consumer group, topics, configs, and credentials.read
xg.knn_graph_buildxg.knn_graph_build(label :: STRING, vector_property :: STRING, config :: MAP) :: (ann_recall_estimate :: FLOAT, batch_count :: INTEGER, bridges_added :: INTEGER, components_after :: INTEGER, componentProcedure xg.knn_graph_build (write)write
xg.loadxg.load(module_name :: STRING) :: ()Load a single query module by name.read
xg.load_allxg.load_all() :: ()Reload all query modules from the modules directory.read
xg.model_version_stampxg.model_version_stamp(model_id :: STRING, version :: STRING, notes :: STRING) :: (model_vertex_id :: STRING, stamped_at_us :: INTEGER)Stamp a model version onto a :Model vertex, recording the model id, version, notes, and write timestamp.write
xg.node_count_by_labelxg.node_count_by_label() :: (count :: INTEGER, label :: STRING)Procedure xg.node_count_by_labelread
xg.plugins_disablexg.plugins_disable(name :: STRING) :: (message :: STRING, success :: STRING)Disable a running plugin (stops the process). License is kept but plugin won't auto-start. Args: name (string). Yields: success, message. Example: CALL xg.plugins_disable('swim') YIELD successread
xg.plugins_enablexg.plugins_enable(name :: STRING) :: (message :: STRING, success :: STRING)Enable a licensed plugin (starts the process). Requires valid license. Args: name (string). Yields: success, message. Example: CALL xg.plugins_enable('swim') YIELD successread
xg.plugins_licensexg.plugins_license(name :: STRING, key :: STRING) :: (message :: STRING, success :: STRING)Store and validate a license key for a plugin. The key is a JSON object with Ed25519 signature. Args: name (string), key (string — JSON). Yields: success, message. Example: CALL xg.plugins_license('swim', 'read
xg.plugins_listxg.plugins_list() :: (author :: STRING, crash_count :: INTEGER, description :: STRING, display_name :: STRING, last_error :: STRING, license_expires_at :: INTEGER, license_issued_to :: STRING, licenseList all discovered plugins with state, license, version, and process info. Yields: name, display_name, version, description, author, type, state, licensed, license_tier, license_issued_to, license_expires_at, pid, crashread
xg.plugins_revokexg.plugins_revoke(name :: STRING) :: (message :: STRING, success :: STRING)Revoke a plugin license. Stops the plugin if running, removes stored license. Args: name (string). Yields: success, message. Example: CALL xg.plugins_revoke('swim') YIELD messageread
xg.plugins_scanxg.plugins_scan() :: (message :: STRING, success :: STRING)Rescan the plugins directory for new or updated plugins. Loads stored licenses. Yields: success, message. Example: CALL xg.plugins_scan() YIELD messageread
xg.proceduresxg.procedures() :: (description :: STRING, is_editable :: BOOLEAN, is_write :: BOOLEAN, mode :: STRING, name :: STRING, path :: STRING, signature :: STRING)List all registered procedures with signature, mode, and description.read
xg.protocol_error_codesxg.protocol_error_codes() :: (category :: STRING, code :: INTEGER, description :: STRING, name :: STRING)List the xrayProtocol error codes with their numeric code, category, name, and description.read
xg.protocol_messagesxg.protocol_messages() :: (body :: STRING, category :: STRING, description :: STRING, direction :: STRING, name :: STRING, opcode :: STRING)List the xrayProtocol wire messages with their opcode, direction, category, body layout, and description.read
xg.read_mode_statusxg.read_mode_status() :: (mode :: STRING, source :: STRING, tenant :: STRING)Report the effective read mode for a tenant and the source that set it.read
xg.reclaim_chain_nowxg.reclaim_chain_now(tenant :: STRING, limit_gids :: INTEGER, cursor_in :: STRING) :: (cursor_out :: STRING, done :: BOOLEAN, error_code :: STRING, gids_reclaimed :: INTEGER, gids_visited :: INTEGER)Operator procedure that reclaims version-chain storage for a tenant in cursor-paged batches, returning the resume cursor and reclaimed count.write
xg.scenario_computexg.scenario_compute(booster_name :: STRING, op = "decommission" :: STRING) :: (audit_id :: STRING, baseline_launches :: INTEGER, baseline_payloads :: INTEGER, baseline_satellites :: INTEGER,Run an engine-side what-if scenario over a booster's downstream subgraph (e.g. decommission), stamping reproducible baseline counts and an audit record.write
xg.segment_repairxg.segment_repair(action :: STRING, tenant :: STRING, segment_id :: INTEGER, operator_note = "" :: STRING, operator_id = "" :: STRING, force = false :: BOOLEAN, expected_state = &qOperator procedure to repair a storage segment for a tenant (reconcile catalog vs. disk state) with optional force and expected-state guards.write
xg.segment_repair_remove_stalexg.segment_repair_remove_stale(tenant :: STRING, operator_note = "" :: STRING, operator_id = "" :: STRING, dry_run = false :: BOOLEAN, batch_cap = 100000 :: INTEGER) :: (dry_run ::Operator procedure to scan and remove stale storage segments for a tenant, with dry-run and batch-cap controls.write
xg.set_chain_retainxg.set_chain_retain(tenant :: STRING, retain :: BOOLEAN) :: (error_code :: STRING, ok :: BOOLEAN, retain :: BOOLEAN, tenant :: STRING)Operator procedure to enable or disable version-chain retention for a tenant.write
xg.set_read_modexg.set_read_mode(tenant :: STRING, mode :: STRING, operator_note = "" :: STRING, operator_id = "" :: STRING) :: (error_code :: STRING, mode :: STRING, ok :: BOOLEAN, tenant :: STRIOperator procedure to set the read mode for a tenant, with optional operator note and id for auditing.write
xg.source_confidence_enforcementxg.source_confidence_enforcement(label :: STRING, raw :: FLOAT) :: (capped :: FLOAT)Clamp a raw confidence value to the per-tier confidence ceiling for the given source label.read
xg.tenant_access_revokexg.tenant_access_revoke(tenant_id :: STRING) :: (error_code :: INTEGER, ok :: BOOLEAN, reversible :: BOOLEAN, tenant_id :: STRING)Operator procedure to revoke access for a tenant, reporting whether the action succeeded and is reversible.read
xg.tenant_crypto_shredxg.tenant_crypto_shred(tenant_id :: STRING) :: (dek_versions_destroyed :: INTEGER, error_code :: INTEGER, ok :: BOOLEAN, tenant_id :: STRING)Operator procedure to crypto-shred a tenant by destroying its data-encryption key versions, rendering its at-rest data unrecoverable.read
xg.tenant_encryption_provisionxg.tenant_encryption_provision(tenant_id :: STRING) :: (error_code :: INTEGER, error_message :: STRING, ok :: BOOLEAN, tenant_id :: STRING)Provision per-tenant encryption for a tenant, creating its key material and enabling at-rest encryption.read
xg.tenant_encryption_statusxg.tenant_encryption_status(tenant_id :: STRING) :: (current_write_version :: INTEGER, dek_versions :: INTEGER, kek_ref :: STRING, provisioned :: BOOLEAN, rotation_in_progress :: BOOLEAN, status :: STReport a tenant's encryption status: whether provisioned, KEK reference, DEK version count, current write version, and rotation state.read
xg.tenant_key_rotate_dekxg.tenant_key_rotate_dek(tenant_id :: STRING) :: (error_code :: INTEGER, new_version :: INTEGER, ok :: BOOLEAN, old_version :: INTEGER, tenant_id :: STRING)Rotate the per-tenant data-encryption key, advancing the write version.read
xg.tenant_key_rotate_kekxg.tenant_key_rotate_kek(tenant_id :: STRING, new_kek_ref :: STRING) :: (error_code :: INTEGER, new_kek_ref :: STRING, ok :: BOOLEAN, tenant_id :: STRING)Rotate the per-tenant key-encryption key to a new KEK reference.read
xg.transformationsxg.transformations() :: (is_editable :: BOOLEAN, name :: STRING, path :: STRING)List all registered stream transformations.read
xg.update_module_filexg.update_module_file(path :: STRING, content :: STRING) :: ()Overwrite the content of an existing query-module file at the given path.read
xg.vector.describe_indexxg.vector.describe_index(name :: STRING) :: (label :: STRING, name :: STRING, property :: STRING)Describe a named vector index, returning its label, property, and name.read
xg.vector.list_indexesxg.vector.list_indexes() :: (label :: STRING, name :: STRING, property :: STRING)List all vector indexes with their name, label, and property.read
xg.vector.searchxg.vector.search(name :: STRING, q :: LIST OF FLOAT, k :: INTEGER) :: (node :: NODE, score :: FLOAT)Find the k nearest vectors in a named vector index to a query vector, returning each node and its similarity score.read
xg.vector.search_by_nodexg.vector.search_by_node(name :: STRING, source :: NODE, k :: INTEGER) :: (node :: NODE, score :: FLOAT)Find the k nearest vectors in a named vector index to the vector of a given source node.read
xg.vector.search_edgesxg.vector.search_edges(name :: STRING, q :: LIST OF FLOAT, k :: INTEGER) :: (edge :: RELATIONSHIP, score :: FLOAT)Find the k nearest vectors in a named edge vector index to a query vector, returning each relationship and its score.read
xg.vector.search_radiusxg.vector.search_radius(name :: STRING, q :: LIST OF FLOAT, threshold :: FLOAT) :: (node :: NODE, score :: FLOAT)Find all vectors in a named vector index within a similarity threshold of a query vector.read
xg.w6b_router_statusxg.w6b_router_status(tenant :: STRING) :: (aead_fail :: INTEGER, auto_demoted :: BOOLEAN, coverage_miss :: INTEGER, dek_unavail :: INTEGER, drift :: INTEGER, effective_mode :: STRING, mmap_fault :: INReport W6B storage-router status for a tenant: effective mode, auto-demotion, and fault counters (AEAD, mmap, drift, coverage, DEK).read
xg.xray_vision_builtin_functionsxg.xray_vision_builtin_functions() :: (category :: STRING, description :: STRING, kind :: STRING, name :: STRING, signature :: STRING, tier :: STRING)List the XRay-Vision built-in functions with their category, kind, signature, description, and tier.read

prov.* — 7 procedures

Provenance — attach evidence to facts and explain how a conclusion was reached.

ProcedureSignatureDescriptionMode
prov.attach_evidenceprov.attach_evidence(fact_node :: NODE, evidence_type :: STRING, content :: STRING, source_url :: STRING) :: (evidence :: NODE)Attach an evidence node (with type, content, and source URL) to an existing provenance fact node.write
prov.create_factprov.create_fact(entity_type :: STRING, content :: STRING, source_id :: STRING, confidence :: FLOAT) :: (node :: NODE)Create a provenance fact node with an entity type, content, source identifier, and confidence score.write
prov.explainprov.explain(fact_node :: NODE) :: (depth :: INTEGER, relationship :: STRING, summary :: STRING, type :: STRING)Explain how a provenance fact was derived by walking its supporting relationships and summarizing each step.read
prov.lineageprov.lineage(start_node :: NODE, max_depth :: INTEGER) :: (depth :: INTEGER, node :: NODE, type :: STRING)Trace the provenance lineage of a node up to a maximum depth, yielding each ancestor node and its relationship type.read
prov.record_decisionprov.record_decision(decision_text :: STRING, reasoning :: STRING, fact_nodes :: LIST OF ANY) :: (decision :: NODE)Record a decision provenance node capturing the decision text, reasoning, and the fact nodes it relied on.write
prov.record_model_runprov.record_model_run(model_name :: STRING, prompt :: STRING, output :: STRING, fact_nodes :: LIST OF ANY) :: (model_run :: NODE)Record a model-run provenance node capturing the model name, prompt, output, and the fact nodes it relied on.write
prov.record_tool_callprov.record_tool_call(tool_name :: STRING, input :: STRING, output :: STRING, fact_nodes :: LIST OF ANY) :: (tool_call :: NODE)Record a tool-call provenance node capturing the tool name, input, output, and the fact nodes it relied on.write

xggpu.* — 5 procedures

GPU-accelerated graph algorithms.

ProcedureSignatureDescriptionMode
xggpu.gpu_bfsxggpu.gpu_bfs(source_id :: INTEGER) :: (distance :: INTEGER, node_id :: INTEGER, time_ms :: INTEGER)Procedure xggpu.gpu_bfsread
xggpu.gpu_kcorexggpu.gpu_kcore() :: (core_number :: INTEGER, max_core :: INTEGER, node_id :: INTEGER, time_ms :: INTEGER)Procedure xggpu.gpu_kcoreread
xggpu.gpu_label_propagationxggpu.gpu_label_propagation(iterations :: INTEGER) :: (community_id :: INTEGER, community_size :: INTEGER, iterations_actual :: INTEGER, node_id :: INTEGER, num_communities :: INTEGER, time_ms :: INTEProcedure xggpu.gpu_label_propagationread
xggpu.gpu_pagerankxggpu.gpu_pagerank(iterations :: INTEGER, damping :: FLOAT, label :: STRING) :: (iterations :: INTEGER, name :: STRING, node_id :: INTEGER, rank :: FLOAT, time_ms :: INTEGER)Procedure xggpu.gpu_pagerankread
xggpu.gpu_triangle_countxggpu.gpu_triangle_count() :: (edges_checked :: INTEGER, time_ms :: INTEGER, triangles :: INTEGER, vertices :: INTEGER)Procedure xggpu.gpu_triangle_countread

db.* — 3 procedures

Schema introspection — labels, relationship types and indexes.

ProcedureSignatureDescriptionMode
db.indexesdb.indexes() :: (labelsOrTypes :: STRING, name :: STRING, properties :: STRING, type :: STRING)List all indexes in the database with their label/type, name, properties, and index type.read
db.labelsdb.labels() :: (label :: STRING)List all node labels present in the database.read
db.relationshipTypesdb.relationshipTypes() :: (relationshipType :: STRING)List all relationship types present in the database.read

repl.* — 2 procedures

Replication control and status.

ProcedureSignatureDescriptionMode
repl.set_sync_policyrepl.set_sync_policy(address :: STRING, mode :: STRING, targets :: STRING) :: (status :: STRING)Set the replication synchronization policy (mode and sync targets) for a replica at the given address.write
repl.show_replicasrepl.show_replicas() :: (acked_lsn :: INTEGER, address :: STRING, status :: STRING, sync_mode :: STRING, sync_targets :: STRING)List configured replicas with their address, status, acked LSN, and synchronization mode and targets.read

GFQL Operators

Graph operators available through the GFQL chain syntax.