Repository navigation
Releases
v1.0.0
Release notes
Highlights
- The embedded core, tidied for 1.0 — an experiment retires, and an error message learns to speak plainly:
- CDC replication slots are withdrawn:
register_cdc_slot,ack_cdc_slot,drop_cdc_slot,cdc_slots,cdc_records_after, andset_apply_only/apply_onlyare gone, along withcdc/slots.json. Checkpoint recycle no longer waits on a consumer ack (ADR-0574). - Opening an
s3://URI now reports that object storage belongs to the clients embedding Relate.
- CDC replication slots are withdrawn:
What's Changed
- chore(cli): drop the preview-host fallback and the token prefix from the upgrade path (ADR-0550, ADR-0250) by @oskarhane in #168
- refactor(scripts): one usage-text printer shared by premerge-check and prebuilt-bin (LABS-1366) by @jexp in #173
- fix(release): grant the publish jobs the attestations read permission by @oskarhane in #180
- fix(installer): resolve the latest release via the file host's releases.json (ADR-0571, LABS-1385) by @oskarhane in #178
- feat(release): drop the npm guards — trusted publishing is configured by @oskarhane in #182
- fix(release): npm-publish passes an explicit local-path spec by @oskarhane in #184
- fix(release): npm jobs resolve the publish action from the dispatch ref by @oskarhane in #185
- fix(release): npm provenance attaches only from public repositories by @oskarhane in #188
- feat(release): enable the crates.io job and make its publish loop re-dispatchable by @oskarhane in #189
- fix(cli): strip internal ADR/LABS identifiers from user-facing output (LABS-1397) by @oskarhane in #191
- Withdraw CDC replication slots by @triha74 in #186
- docs(adr): name embedding clients instead of MemoryDB Cloud by @triha74 in #183
- fix(release): grant the publish-registries caller the attestations read permission by @oskarhane in #206
Full Changelog: v0.1.3...v1.0.0
v0.1.3
Release notes
Highlights
-
Shortest paths take the shortest route — every spelling of a shortest-path query — the
shortestPath()expression,SHORTEST kselectors, quantified relationships, auto-parameterized templates — now rides the dedicated shortest-route engine instead of walking hop by hop.relate ./friends -c "MATCH p = shortestPath((a:Person {name: 'Alice'})-[:FRIENDS_WITH*]-(b:Person {name: 'Bob'})) RETURN length(p) AS hops" -
dbms.listCapabilitiesreports what this engine can do — a client can now ask the database itself whether fulltext and vector indexes are available, which Cypher dialect it speaks, and which pattern engine is in force — one row per capability, no guessing, and no rows mirrored from a server Relate is not.relate "CALL dbms.listCapabilities()" -
Errors report their own class — a cluster of fixes so the class on a rejection names the stage that raised it, which is the only thing a client's retry logic should have to read:
- Front-end rejections report
SyntaxErrorwhere a later stage used to take the blame - Dynamic label and relationship-type rejections carry
TypeError toInteger()out of range carriesArgumentError- Argument-value and procedure rejections carry the class the live run reports
- A non-numeric
substring()/left()/right()argument raises the type rejection range()arity is enforced at the front end, before anything runs
- Front-end rejections report
Other changes
MATCHwith OR'd labels and a key predicate now serves as a union of per-label seeks instead of one scanMATCHoutput streams into aggregation instead of buffering intermediate rows, and a routedMATCHcharges theLIMITcap so scans halt early- Each commit's redo is encoded once at admission, and Parquet checkpoints cap row groups at 1024 rows
- The adjacency store is now sealed-plus-delta with watermark compaction, rebuilt in one sorted pass per (node, type) run
- The Go and Swift clients decode notification severity/category strictly and sanitize echoed wire values; the Java client sanitizes its echoes too
- New task guide: bulk-import durability and batch-size recipes
- One release workflow now publishes the Rust crate, the Python wheel, and the npm packages to crates.io, PyPI, and npm
What's Changed
- fix(show): synthesize the default lookup indexes as SHOW-only rows + F8 ordering fixes by @jexp in #93
- refactor(core): shorten the element-id segment to rl-id / rl-onto (ADR-0554 revision) by @jexp in #109
- test(cli): one PTY driver kit for the egg tests (LABS-1182) by @jexp in #107
- refactor(eggs): shared width probe, SGR helpers, one argument policy (LABS-1182) by @jexp in #108
- refactor(cli): one expect helper and prompt_ready for the PTY egg drivers (LABS-1182) by @jexp in #113
- perf(executor): the shortest route pushes rows into its consumer instead of returning a vector (ADR-0555) by @jexp in #112
- refactor(executor): list only the procedures an embedded engine can answer (ADR-0557) by @jexp in #111
- test(executor): shortest-route anchor arms, property endpoints and write-view routing (LABS-1296) by @jexp in #117
- fix(ddl): non-admitted OPTIONS keys carry live's message text by @jexp in #118
- perf(executor): the shortest fan emits each BFS layer as it completes and stops when its consumer halts (ADR-0555, LABS-1289) by @jexp in #121
- refactor(storage): wide-column parts are the Parquet checkpoint format (ADR-0553) by @jexp in #99
- fix(engine): NumberOutOfRange sites carry the ArgumentError class (LABS-1304) by @jexp in #119
- ci(release): gate every first-party extension crate's suite pre-tag by @oskarhane in #122
- ci(docker): apt retries everywhere, Ubuntu images on the Azure mirror by @jexp in #130
- docs(executor): repair the procedure-catalogue doc comment and note ADR-0557 by @jexp in #127
- feat(executor): dbms.listCapabilities lists this engine's own capabilities (ADR-0561) by @jexp in #133
- fix(java): sanitize untrusted wire values echoed in enum-decode exceptions (LABS-1291) by @jexp in #115
- perf(storage): encode each commit's redo once at admission (LABS-867, ADR-0558) by @jexp in #114
- fix(engine): toInteger() out-of-range carries the ArgumentError class (LABS-1305) by @jexp in #120
- refactor(eggs): the width probe owns the 80-column default (LABS-1297) by @jexp in #128
- refactor(convert): the InvalidArgumentValue token composes from the kind constructor (LABS-1308) by @jexp in #137
- refactor(executor): one assert_number_out_of_range helper for the string tests (LABS-1311) by @jexp in #135
- fix(cypher): range() arity is enforced at the front end (LABS-1307) by @jexp in #140
- ci(spec-harness): a merge to main produces its own coverage number (LABS-1323) by @jexp in #136
- refactor(executor): the graph-type schema family moves to its own module with one per-kind policy (LABS-1309, LABS-1310) by @jexp in #139
- fix(string): a non-numeric substring()/left()/right() argument raises the type rejection (LABS-1306) by @jexp in #141
- fix(testing): row-per-row relate side and middle elision in the differential DIFF message (LABS-1322) by @jexp in #134
- fix(executor): kernel MATCH emission charges each row before landing (LABS-1077) by @oskarhane in #146
- perf(executor): the shortest route probes its seek endpoints at the pair bound instead of listing every match (ADR-0555, LABS-1318) by @jexp in #131
- refactor(eggs): resolve rows once, share statement helper, tidy tetris preview (LABS-1297) by @jexp in #143
- perf(storage): the Parquet row-group cap is 1024 rows (ADR-0563, LABS-1278) by @jexp in #147
- Run Sonic stages on the hardened gosonic by @triha74 in #90
- perf(engine): OR'd-label keyed MATCH serves as a union of per-label seeks (LABS-1083) by @oskarhane in #145
- test(query-latency): pokec_profile --group/--sample/--profile for expansion RCA (LABS-1116) by @jexp in #116
- refactor(executor): split dag_layers' stop protocol and pin the shortest-route anchor arms (LABS-1316, LABS-1317) by @jexp in #132
- docs(guides): bulk-import durability and batching recipes by @jexp in #153
- fix(executor): a selector or routed MATCH charges the LIMIT cap, so the input-row loop halts (LABS-1301) by @jexp in #150
- docs(design): shortest selectors on the frontier NFA, research note (LABS-1288) by @jexp in #129
- fix(executor): the routed shortest-path sink keeps one name after the merge (LABS-1301) by @jexp in #155
- perf(storage): charge the workspace as the commit redo is encoded (LABS-1292) by @jexp in #148
- docs(agents): the merge bar is the merged tree, with a script that checks it by @jexp in #156
- fix(cypher): dynamic label/type rejections carry the TypeError class (LABS-1338) by @jexp in #149
- fix(executor): stream MATCH output into aggregation; guard new Vec operators (LABS-1261, LABS-1200) by @jexp in #110
- fix(executor): an auto-parameterized SHORTEST 1 takes the shortest route (LABS-1326) by @jexp in #158
- perf(executor): sealed+delta adjacency store with watermark compaction (ADR-0551, ADR-0552) by @jexp in #144
- fix(engine): argument-value and procedure rejections carry the class live reports (LABS-1337) by @jexp in #151
- docs(adr): shortest selectors as physical operators of the one pattern evaluator (ADR-0568) by @jexp in #163
- refactor(storage): one rule per commit-encode fact, neutral bounded sink (LABS-1292) by @jexp in #161
- ci: compile the tree that lands, not the head by @jexp in #162
- feat(datasets): bulk-loadtest durability ladder and commit-timing capture by @jexp in #160
- fix(clients): Go and Swift decode notification severity/category strictly and sanitize echoed wire values (LABS-1279) by @jexp in #159
- fix(ci): the fingerprint stamper tolerates a list-valued ops knob by @jexp in #166
- fix(cypher): front-end rejections report SyntaxError where the executor reported a later stage (LABS-1336) by @jexp in https://git...
ideas 0.1.0
relate-extensions-ideas-0.1.0 Release relate-extensions-ideas-0.1.0
git-to-graph 0.13.0
relate-extensions-git-to-graph-0.13.0 Release relate-extensions-git-to-graph-0.13.0
fs-to-graph 0.13.0
relate-extensions-fs-to-graph-0.13.0 Release relate-extensions-fs-to-graph-0.13.0
dungeon 0.1.0
relate-extensions-dungeon-0.1.0 Release relate-extensions-dungeon-0.1.0
v0.1.2
Release notes
Highlights
-
Element IDs now name their database —
elementId()output gains the namespace segment, so the first node reads4:relate-neo4j:n0instead of4:relate:n0— in the shell, in JSON, and over Bolt; anything parsing element IDs will want the new shape. Example:relate --json "CREATE (n:Person) RETURN elementId(n)" -
Shortest paths meet in the middle — a
shortestPathwhose endpoints are property maps now seeks both ends and searches as a pair instead of balling out from one side, measured two orders of magnitude faster on hub-heavy graphs — and every traversal in the engine saves one read per hop besides. Example:relate -d ./friends "MATCH p = shortestPath((a:Person {name: 'Alice'})-[*..6]-(b:Person {name: 'Bob'})) RETURN p" -
Cleanly-closed stores skip the reopen index rebuild — when the WAL replays nothing, open no longer rebuilds the indexes, so a tidily shut-down store gets to its first row sooner. Example:
relate query --database ./friends
Other changes
relate upgradeno longer prints the rename notice after its status line — just the facts, then the skill refresh.
What's Changed
- perf(storage): skip the post-replay index rebuild when the WAL replayed nothing (LABS-1112) by @jexp in #92
- test(research): land the per-structure heap-census harness by @jexp in #97
- chore(executor,front): bar() polish (LABS-1176) by @jexp in #103
- chore(eggs): egg polish — shared helpers, one Rng, panic payload (LABS-1182) by @jexp in #102
- ci(release): fold the retry re-stamp into the bump commit with --amend by @oskarhane in #106
- fix(core): make the element-id namespace segment dash-bearing (ADR-0554) by @jexp in #101
- feat(cli): drop the cypherlite rename notice from relate's upgrade by @oskarhane in #105
- perf(executor): shortest-path walk core and pair search for property-seekable endpoints (LABS-914, ADR-0556) by @jexp in #104
Full Changelog: v0.1.1...v0.1.2
v0.1.1
Release notes
Highlights
-
Wide-column Parquet snapshots —
--snapshot-formatlearnsparquet-wide: the Parquet codec writes one typed column per promoted property key beside a residual tagged-JSON tail, and the next checkpoint pins the choice into the manifest so every later open keeps the store wide. Works on the query session and onserve.relate --snapshot-format parquet-wide ./friends -
Full-text search learned Lucene manners — fulltext
SEARCHand thedb.index.fulltext.query*procedures now pass the query syntax straight to the index (AND/NOTare operators, a lowercaseandstays a term), rank hits with live BM25 pinned against Neo4j's own scores, page withSKIP/OFFSET, and evaluateWITH ANALYZERper row — English stemming included.relate ./movies "MATCH (m:Movie) SEARCH m IN (FULLTEXT INDEX moviePlots FOR 'princess AND NOT snow' LIMIT 5) RETURN m.title" -
A quiet tune-up — the engine got faster in three places you'll notice and none you'll have to think about:
- POINT indexes moved to an R*-tree backend — radius and bounding-box seeks probe a packed tree instead of walking grid cells, antimeridian wrap included.
- Label, relationship-type and property-key names resolve to token ids once per plan instead of hashing names per candidate.
MATCHpredicates push to their earliest clause, andUNWIND range()streams into aggregating projections instead of piling up rows first.
Other changes
- Java client: typed
QueryType/Namespace/Severity/Categoryenums replace raw strings, andPlanActualcarries the full wire plan shape. - The variable-shadowing notification now looks inside
EXISTS/COUNT/COLLECTexpression subquery bodies. SEARCHover complex patterns (thecomplex-search-patternspreview) countsLIMITsurvivors instead of pre-filter candidates.- Scalar fixes: decimal
round(), temporal sort order, nested-list type unions. - Runtime lists now coerce to predicates at
WHERE/FILTERpositions. - Duration fractions fold through Neo4j's approximate chain.
FINISHis legal after a row-producing catalog command; DDL commands are standalone.- The interactive REPL grew a hidden game cabinet —
.life,.snake,.tetris,.dash(Archie runs, jumps and ducks) — and.fortunelearned five new fortunes.
What's Changed
- feat(cli): --snapshot-format parquet-wide opts a store into the wide-column parts (ADR-0534) by @jexp in #83
- fix(search): fulltext query syntax, live BM25 ranking, one shared scan by @jexp in #61
- fix(planner): FINISH is legal after a row-producing catalog command; DDL commands are standalone by @jexp in #36
- fix(temporal): fold duration fractions through Neo4j's approximate chain by @jexp in #43
- POINT index backend: R*-tree via rstar (ADR-0549) by @johnymontana in #71
- feat(eggs): playable .life, .snake and .tetris (games feature, ADR-0547) by @jexp in #57
- fix(stellar-prep): merge-base fallback when last_head diverged (LABS-955) by @jexp in #70
- feat(notifications): descend into expression subquery bodies for 03N60 by @jexp in #42
- docs(design): lazy-indexes load-memory investigation + proposal (LABS-1110 follow-on) by @jexp in #85
- fix(scripts): release-bump typed npm reads + dirty-tree guard (LABS-1160) by @jexp in #81
- fix(executor): stream UNWIND range() into an aggregating projection (LABS-1246) by @jexp in #86
- test(cli): shift the releases.json fixture tags below the v0.1.0 line by @oskarhane in #88
- perf(planner,executor): resolve names to token ids once per plan (ADR-0541) by @jexp in #87
- refactor(parser,front): one visit-ordered expr edge enumeration (LABS-1146) by @jexp in #80
- docs(adr): port the sealed-delta adjacency design and its proptest-model ADR (ADR-0551/0552) by @jexp in #89
- fix(scalar): decimal round, temporal sort order, nested list type unions by @jexp in #74
- fix(executor): coerce runtime lists to predicates at WHERE/FILTER positions by @jexp in #76
- fix(planner,executor): push MATCH predicates to their earliest clause; order selector rows by @jexp in #77
- refactor(core): temporal pattern ymd helper, Era enum, accept_zone, ClockKind reuse (LABS-1145) by @jexp in #82
- docs(adr): operators stream rows; unbounded results are never accumulated (ADR-0555) by @jexp in #95
- feat(eggs): .dash, Archie runs, jumps and ducks (games feature) by @jexp in #94
- fix(search): the SEARCH LIMIT counts survivors for complex patterns only by @jexp in #91
- ci(release): fetch+rebase+rebuild retry on the version-bump push by @oskarhane in #98
- feat(java): typed QueryType/Namespace/Severity/Category enums; full PlanActual wire shape (LABS-947, LABS-1183) by @jexp in #96
- feat(eggs): add five fortunes to the .fortune pool by @johnstegeman in #100
New Contributors
- @johnstegeman made their first contribution in #100
Full Changelog: v0.1.0...v0.1.1
v0.1.0
Release notes
Highlights
-
One binary, one file, nothing to deploy — Relate is an embedded, in-memory property-graph engine that answers Cypher; a graph is a
.rlfile, a directory, or pure memory, and there is no server to babysit. Example:relate "RETURN 1 + 2 AS sum" -
Durable by construction — every committed write rides a fsync'd WAL, with Parquet checkpoints for fast reopens;
clonepacks a store into a single portable file for backup or transfer. Example:relate clone ./friends ./friends-backup.rl -
One engine, every front door — the same engine sits behind each of these, so a query that works in the shell works everywhere:
- the
relateCLI shell, interactive or one-shot - Python, Node.js, browser WASM, Rust, Java, Go, and Swift bindings over one typed C ABI
relate serve— one process speaking Bolt, the HTTP Query API v2, and MCP
- the
Other changes
- openCypher is the language contract:
MATCH/MERGE, subqueries, schema DDL, 80+ built-in functions, quantified path patterns — the openCypher TCK is the measured dialect floor. - Vector search:
vector()properties,vector.similarity.*scoring,CREATE VECTOR INDEX, and theSEARCHclause for index-backed top-K. - Geospatial: WGS-84 and Cartesian points,
point.distance(), bounding-box predicates, and R-tree point indexes. EXPLAINandPROFILErender the plan tree with per-operator rows and timing.--read-only=livelets a second process follow a store's WAL while another writes it.pullandpushmirror subgraphs between Relate and a Neo4j/Aura instance over the Query API v2.relate skill installdrops a skill bundle into detected AI agents so they drive the CLI correctly the first time.- Userland extensions mount as
relate run <name>; first-party packages import a filesystem tree or a git history as a graph. - Anonymous usage metrics are on by default with a layered opt-out (
relate telemetry off); query text and paths are structurally never collected.
What's Changed
- docs: add ADR writing guidance (scope + line budget) to AGENTS.md by @oskarhane in #2
- ci(spec-harness): flip the harness checkout to the relatedb home by @oskarhane in #3
- fix(temporal,pattern): live-Neo4j error classes for CIP-223 format patterns and CIP-190 where-variable patterns by @jexp in #7
- fix(build): release artifacts stop shipping DWARF and LTO bitcode — FFI tarball 69 -> ~22 MB by @jexp in #10
- feat(dialect): graduate the FOR clause from the gql-for preview gate (ADR-0533) by @jexp in #11
- fix(functions): coll.max returns null on any null element, matching live Neo4j by @jexp in #14
- feat(notifications): the 03N95 dynamic-property notification (ADR-0363) by @jexp in #15
- Add initial contribution guidance for AI tooling by @linyaru in #16
- feat(test-support): deterministic synthetic pokec-shaped in-memory fixture by @jexp in #12
- fix(executor): count-style aggregates over a repeated node variable count only self-loops by @jexp in #13
- docs(design): capture the kernel-composition design direction by @jexp in #18
- Add a pull-request gate for memory controls by @triha74 in #4
- docs(adr): ADR-0536 — the frontier NFA over the regular-pattern space by @jexp in #19
- docs(design): capture the kernel coverage inventory and candidate roadmap by @jexp in #21
- fix(executor): fold aggregates under unary/IS TYPE/chrono-compare positions (LABS-744) by @jexp in #26
- feat(notifications): the 01N31/01N30 planner-hint notifications (ADR-0535) by @jexp in #20
- fix(swift): roll back when commit() throws inside transaction(_:) (LABS-957) by @jexp in #27
- fix(java): polish LABS-839 stellar review nits (zip.stream listing, IT mode enum, user.home sentinel) by @jexp in #33
- fix(scripts): resolve LABS-1081 deferred stellar findings (pom.py, ADR check, release-bump) by @jexp in #31
- test(scripts): consolidate the scripts/tests child-env scrub policy (LABS-784) by @jexp in #34
- fix(executor): price unlabeled and untyped hops in the chain kernel's cost gate (LABS-991) by @jexp in #41
- perf(executor): hoist the projection row's names and schema out of the per-row path by @jexp in #24
- feat(profile): report the traversal rung and pattern-engine mode by @jexp in #25
- perf(executor): FxHash used-sets and per-statement label interning for the expansion hot loop by @jexp in #35
- refactor(parser,front): Expr::children enumeration shared by the front walkers by @jexp in #30
- refactor(core,executor): typed invalid-argument constructors and the one unary-arity contract (LABS-727) by @jexp in #37
- refactor(scripts): one sink, one dedent, one inventory (LABS-1071) by @jexp in #38
- feat(storage): experimental rkyv and fjall snapshot codecs, default off (ADR-0537) by @jexp in #23
- refactor(parser,front): one element tail, one property lowering (LABS-1115) by @jexp in #49
- ci(release): prepare the first release from this repository (v0.1.0) by @oskarhane in #44
- perf(cli): telemetry delivery off the exit path — spool locally, drain on the next run (ADR-0545, LABS-1155) by @oskarhane in #45
- feat(observability): fine phase split and plan-cache outcome in every machine envelope (ADR-0540) by @jexp in #32
- refactor(executor): NodeTarget::unfiltered, drop dead pool conjunct (LABS-1098) by @jexp in #48
- fix(clients): refuse unknown query_type/namespace in JS/Java/Swift (LABS-956) by @jexp in #50
- refactor(scripts): shared perf_skip/perf_announce wording, unmask perf stderr in 03/05 (LABS-881) by @jexp in #51
- refactor(core,notifications): split the pattern module; dedup shape detectors (LABS-762) by @jexp in #39
- feat(executor): hidden engine-only bar() text-bar function (ADR-0542) by @jexp in #46
- test(planner): pin OPTIONAL-first FINISH as a read; extensions spec OPTIONAL MATCH clause (LABS-894) by @jexp in #52
- ci(tests): exempt relate-codec-lab from the shard-coverage guard by @jexp in #62
- Inline single-version rows and dense id stores for the memory floor by @triha74 in #22
- feat(cli): hidden dot-command seam (relate-eggs), Archie banner and prompt glyph (ADR-0543) by @jexp in #47
- test(planner): one endpoint-estimate spelling in the seek tests (LABS-875) by @jexp in #63
- feat(extensions): relate-ideas, a linked idea store seeded from the maintainer's vault by @jexp in #56
- feat(eggs): .matrix, .cowsay and .fortune hidden dot commands by @jexp in #55
- feat(eggs): .lolwut and .graph with a braille canvas and force layout by @jexp in #54
- fix(executor): reserve the match-sink row to its column count by @triha74 in #68
- Wide-column Parquet checkpoint shards as an opt-in (ADR-0534) by @jexp in #40
- chore(cookbook): move the cookbook to relate-web (ADR-0528) by @johnymontana in #6
- chore(playground): move the playground to relate-web (ADR-0530) by @johnymontana in #8
- fix(ffi): bind the empty STRING from a NULL zero-length buffer (LABS-1198) by @jexp in #72
- fix(functions): path toString and null string indexes match live Neo4j by @jexp in #59
- fix(storage): writes_wide is Parquet-gated again (LABS-1134) by @jexp in #73
- docs(adr): ADR-0541 — resolve token names to ids once per plan (proposed) by @jexp in #29
- refactor(http): import GQLSTATUS constants from relate-error (LABS-910) by @jexp in #53
- refactor(storage): drop the experimental fjall snapshot codec, keep rkyv (ADR-0537) by @jexp in #69
- fix(ci): authenticate GitHub release downloads by @triha74 in #78
- feat(eggs): .explain-art, a text flame graph of the query plan by @jexp in #58
- test(executor): split exec test_support into family modules (LABS-897) by @jexp in #67
- refactor(test-support): split fetch into pins, download and ensure (L...