shacl2cypher
New Now on PyPI: pip install shacl2cypher validates graphs from Python SHACL → Cypher compiler

Validate a property graph with shapes, not hand-written queries.

shacl2cypher compiles standard W3C SHACL shapes into named, read-only Cypher queries. Run them against Neo4j or LadybugDB and get back every broken rule, the node or relationship that broke it, and the value at fault. Reports come as a table, JSON, JUnit or SARIF.

$ shacl2cypher validate shapes.ttl --ladybug graph.lbug --node-key id
STATUS      SEVERITY   VIOLATIONS  TIME(ms)  RULE
failed      Violation           1        31  PersonShape.name.minCount
            - Person id=p3: Person needs a name
failed      Warning             1         3  PersonShape.name.pattern
            - Person id=p1: ex:PersonShape violates sh:pattern on ex:name (value: "ann")
failed      Violation           1         8  PersonShape.worksFor.maxCount
            - Person id=p1: ex:PersonShape violates sh:maxCount on ex:worksFor

3 rules: 0 passed, 3 failed, 0 timed out, 0 errors, 0 skipped, 0 guaranteed by schema; 3 violations in 42 ms

The problem it removes

Property graphs built by applications have no native SHACL engine. The rules that keep the data sane end up spread across application code, half-enforced database constraints, and ad-hoc Cypher that someone runs by hand. shacl2cypher puts them in one declarative file and turns that file into queries.

Standard

Write SHACL, not a new DSL

Shapes are plain W3C SHACL in Turtle. The optional s2c: hints are ignored by other SHACL engines, so the same file still validates an RDF export with pySHACL.

Precise

One query per constraint

Each constraint becomes its own named query, so it can be run, timed and baselined on its own. A failure names the rule, the focus node and the offending value.

Safe

Read-only by construction

Neo4j queries run in a transaction that is always rolled back. LadybugDB files are opened read-only. Validation never changes your data.


How it works

Compilation is a pure, deterministic pipeline. The same shapes, schema snapshot and options always give a byte-identical manifest.

  1. Load

    Every shapes file, plus its owl:imports, is read into one union graph, and every triple remembers its file and line.

  2. Resolve

    Classes become labels, and predicates become properties or relationship types. The mapping uses naming conventions, then a schema snapshot, then explicit s2c: annotations, which always win.

  3. Lower and render

    Each constraint is lowered into a dialect-neutral IR and rendered as null-safe Cypher for Neo4j 5 or LadybugDB.

  4. Emit and run

    compile writes manifest.json and queries.cypher. validate runs every summary query, then detail queries for the rules that failed, and writes a report with a CI-friendly exit code.


What you get

Explained nested failures
When an sh:or or sh:node fails, the row lists which inner constraints failed. A standard SHACL report only names the outer one.
Schema-aware compilation
With a schema snapshot, typos and missing labels become static diagnostics. On LadybugDB, constraints the typed schema already guarantees need no query at all.
Stable names and fingerprints
Rule ids are structural, e.g. ex:PersonShape/ex:name/sh:minCount. Fingerprints change only when a rule's meaning changes, so CI can tell a rule changed even when its name did not.
Reports for people and pipelines
Table output for a terminal, JSON for scripts, JUnit for test dashboards, and SARIF that points at the shapes file and line of each violated constraint.
CLI, Python and Node.js
pip install shacl2cypher and npm install shacl2cypher run the same compiler in-process, with output byte-identical to the CLI's. Python on PyPI →
Tested against reference engines
Conformance fixtures run on Neo4j, LadybugDB and pySHACL, and the W3C SHACL Core suite runs on Neo4j. Every outcome is recorded.

Databases

DatabaseStatusNotes
Neo4j 5SupportedCypher without APOC. Schema snapshot optional. Connects over Bolt.
LadybugDBSupportedEmbedded and strictly typed. A schema snapshot is required and is read from the database file automatically.
FalkorDB 4.20In developmentA dedicated renderer is being built from spike findings. See the FalkorDB article.

Where to go next