Changelog

What changed.

Version-by-version. Newest first. For the story behind releases, see Announcements.

2026.08.31 — v1.2.0

v1.2.0

Added

  • Multi-predicate index-seek intersection. A structured query with several has() filters now seeks every indexed predicate and intersects the matching id sets, instead of seeking one and scanning every seeded vertex for the rest. Filtered searches that ran for multiple seconds return in <100 ms on a 70k-vertex graph. The optimization is order-independent — it fires whether hasLabel() or a has() comes first — and any predicate on a non-indexed key falls back to a per-survivor residual check. Single-predicate and bare hasLabel() paths are unchanged.

Fixed

  • has(key, lt(x)) and has(key, lte(x)) on an indexed property returned no rows — the index cursor was positioned past every matching entry before the scan began. It now walks the property's key range from the start and stops at the boundary; lte includes the boundary value. gt/gte/between/inside were already correct.

2026.08.29 — v1.1.0

v1.1.0

Added

  • explodeSymbolic() Gremlin step — materializes a stored SymbolicExpr into first-class SymbolicOp/Var/Lit/Call vertices and left/right/operand/arg_N edges, so formal logic is traversable with Gremlin — not just an opaque blob handed to Z3. It is an explicit, opt-in write; proving never mutates the graph.
  • smtProve() now accepts a logic-root vertex directly (g.V().hasLabel('SymbolicOp').smtProve()), rebuilding the assertion from the tree and deriving each variable's SMT sort from its SymbolicVar node — the manual typeMap argument is now optional.

Fixed

  • Variable sorts (Int/Real/Bool/String) now survive a graph round-trip instead of collapsing to Int.
  • Multi-argument logic calls keep their positional argument order through serialization and reconstruction.

2026.08.26 — v1.0.4

v1.0.4

Fixed

  • asanagidb could crash with "reached unreachable code" the moment a client (including the Admin UI) requested list_databases against a server started with no explicit data-path configuration — the default relative data path was never resolved to an absolute one before an internal directory check that requires it. Only the completely flag-free invocation was affected; any server started with --config or an explicit data-path override was never at risk.
  • Shipped release binaries no longer embed the build machine's absolute filesystem paths in debug info or compiled-in assertion strings.

2026.08.12 — v1.0.2

v1.0.2

Fixed

  • Resolved an issue in asanagidb where the server failed to populate uds_path from YAML instance configuration files (--config), causing instances to fall back to /tmp/asanagidb.sock instead of respecting custom socket paths.

2026.08.12 — v1.0.1

v1.0.1

Fixed

  • Web Admin UI <base href="/admin/" /> routing fixes for seamless standalone dashboard execution.

2026.08.09 — v1.0.0

v1.0.0

Added

  • Thirty-one new Gremlin steps, taking AsanagiDB from roughly a third of the TinkerPop traversal vocabulary to about two thirds.
  • match() — declarative pattern matching with variable binding, using the same greedy pattern-selection algorithm TinkerPop ships.
  • branch()/option(), plus choose()'s value-matching switch form.
  • Set operations — combine(), conjoin(), difference(), disjunct(), intersect(), product(), merge().
  • Path filters (simplePath(), cyclicPath()), tree(), sack(), math(), local(), sideEffect(), propertyMap(), index(), loops(), timeLimit(), coin(), fail().
  • Date and formatting steps — asDate(), dateAdd(), dateDiff(), format() — plus asBool()/asNumber() and the all()/any() collection predicates.

Fixed

  • otherV() wasn't implemented at all, despite being a standard edge-traversal step — any query ending in it errored out.
  • element() silently dropped every traverser that was already a vertex or edge, instead of passing it through.
  • group()/groupCount() with .by(propertyKey) ignored any key other than the vertex label, silently grouping by vertex identity instead.

Security

  • Fixed an SMT-LIB injection in the logic_prove tool. Type names supplied by the caller were written verbatim into the generated solver script, so a crafted value could close the enclosing expression and append its own assertions — making the solver answer a different question and report a false "proven" result. Identifiers are now validated against the SMT-LIB symbol grammar.
  • The solver subprocess now enforces a wall-clock timeout, an output-size cap and an input-size bound. Previously a hard or hostile query could hang the caller indefinitely or buffer unbounded output.

2026.08.08 — v0.25.3

v0.25.3

Added

  • Text/string manipulation step family: asString(), substring(), trim()/lTrim()/rTrim(), toUpper()/toLower(), replace(), split(), length(), reverse(), and concat().
  • sample() — both global (a true reducing barrier) and Scope.local forms.
  • cap() to read back named side-effects from store()/aggregate().
  • Date and Timestamp GraphBinary values now decode correctly over the wire.
  • group() now supports multi-step .by() reducers, not just single-step ones.
  • TextP predicates (containing(), startingWith(), endingWith(), etc.) now decode and evaluate correctly.
  • filter(), and(), map(), flatMap(), and choose() for the standard predicate/traversal forms.

Fixed

  • order().by(key) used to keep elements missing that key, just unordered; it now drops them, matching real TinkerPop semantics. String-keyed sorts (order().by("name")) also work correctly now — string comparison was never actually implemented before, only numeric.
  • group()/groupCount() with .by(propertyKey) ignored any key other than the vertex label — grouping by an arbitrary property silently used the vertex's own identity as the key instead, making group().by("name")-style queries completely non-functional. Fixed.

2026.08.05 — v0.25.0

v0.25.0

Added

  • asna — a new interactive Gremlin console (macOS and Linux). Connect over a Unix socket, plain TCP, or WebSocket (ws:///wss://), with line editing, history, and named connection profiles for switching between instances. Run a single script and exit, or drop into a REPL.
  • --central/--public federation (memory_share/memory_fetch) is now fully functional end to end for the first time — publishing and fetching entities between two MCP instances now actually moves data, not just establishes a connection.

Fixed

  • elementMap() only ever handled edges — g.V().elementMap() silently returned nothing for every vertex. It now returns t.id/t.label/properties for vertices too.
  • A wire-protocol offset bug in the MCP server's --remote/--central client corrupted any response carrying real data, and a related bug caused a single matching result to be returned in the wrong shape. Both fixed.
  • An unrecognized Gremlin step name (e.g. a typo) used to fail silently, returning zero results with no indication anything was wrong. It now returns a clear error.
  • --public mTLS certificate provisioning could crash outright on first use; certificate generation now uses a key type the TLS layer actually supports.

2026.08.01 — v0.24.4

v0.24.4

Fixed

  • valueMap(key1, key2, ...) ignored the requested key list and always returned every property on the vertex or edge. It now filters to just the requested keys, matching standard TinkerPop behavior; valueMap() with no arguments still returns everything.
  • The MCP memory_context tool returned neighbor entries with their body text still base64-encoded, while the entity's own body and every other memory tool already returned plain text. Neighbor bodies are now decoded consistently.
  • Every Gremlin valueMap()/values() call against an edge leaked a small internal iterator allocation. Found via a new regression test while fixing the key-filter issue above.

2026.07.31 — v0.24.3

v0.24.3

Fixed

  • A long-running server could eventually reject new connections with an internal MDB_BAD_RSLOT error after many client connect/disconnect cycles over time. The server now reclaims stale internal reader state on every new connection.

2026.07.30 — v0.24.2

v0.24.2

Fixed

  • valueMap() on edges could silently drop a custom property when it was the only one an edge had — has() and values() were unaffected and always returned it correctly.

2026.07.30 — v0.24.1

v0.24.1

Fixed

  • A Gremlin wire-protocol gap where results of a bytecode-submitted traversal (the standard way any real gremlin-driver client talks to AsanagiDB, as opposed to Gremlin Console's string-script mode) weren't wrapped in the Traverser envelope the wire protocol requires — causing driver clients to throw a cast exception on writes such as addV()/property()/.next(). Console and script-eval usage were unaffected.

2026.07.24 — v0.24.0

v0.24.0

Added

  • AsanagiLIS: --mcp-url flag to point tool calls at any AsanagiDB MCP server instead of a hardcoded local address.

Fixed

  • A GraphBinary type-handling gap where clients with no native integer type (like gremlin-javascript) serialize numeric IDs and counts as Double instead of Int/Long — silently broke V(id), E(id), hasId(), addE().to()/.from(), mergeE's endpoints, limit(), range(), skip(), tail(), and repeat().times(). Java and Go clients were unaffected.
  • containing(), startingWith(), endingWith(), and their not* variants were case-sensitive despite memory_search's own tool description promising fuzzy matching. Now case-insensitive (ASCII).

2026.07.20 — v0.23.0

v0.23.0

Added

  • Gremlin: range, skip, tail, hasKey/hasValue/hasNot, mergeV/mergeE, subgraph(), explain(), and profile().
  • Gremlin: map and list literal syntax ([key: value, ...], [a, b, c]).
  • asanagidb-admin shutdown-mcp / shutdown-lis — stop a running MCP or AsanagiLIS instance from the command line.

Fixed

  • A Gremlin injection vulnerability in the MCP server, closed across every affected call site.
  • addE().to(V(...)) silently not creating the edge for certain nested-call forms.
  • The MCP server could crash on an oversized single line over stdio; it now recovers instead of taking the whole process down.
  • memory_search / memory_list now return decoded text directly instead of raw base64.
  • Very large individual memory bodies could fail on import in rare cases; large values now chunk automatically.
  • Windows builds were broken by an in-progress graceful-shutdown change; fixed.
  • License activation now binds to the activating machine, closing an unauthenticated-downgrade path.