<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Aditya Mukhopadhyay</title>
    <description>The latest articles on Forem by Aditya Mukhopadhyay (@adityamukho).</description>
    <link>https://forem.com/adityamukho</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F328347%2F94121027-ccde-49dd-b6c4-1f4ae61651a5.jpeg</url>
      <title>Forem: Aditya Mukhopadhyay</title>
      <link>https://forem.com/adityamukho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/adityamukho"/>
    <language>en</language>
    <item>
      <title>Minigraf 1.0: An Embedded Bi-Temporal Datalog Database in Rust</title>
      <dc:creator>Aditya Mukhopadhyay</dc:creator>
      <pubDate>Sat, 02 May 2026 10:54:03 +0000</pubDate>
      <link>https://forem.com/adityamukho/minigraf-10-an-embedded-bi-temporal-datalog-database-in-rust-4bg5</link>
      <guid>https://forem.com/adityamukho/minigraf-10-an-embedded-bi-temporal-datalog-database-in-rust-4bg5</guid>
      <description>&lt;p&gt;Today I'm releasing Minigraf 1.0 — a single-file embedded graph database written in Rust, with Datalog as its query language and bi-temporal semantics built in.&lt;/p&gt;

&lt;p&gt;If you've ever wanted Datomic but embedded, or SQLite but for connected data with full history, this is that. One &lt;code&gt;.graph&lt;/code&gt; file, no server, no clustering, no Java runtime. It runs natively, in WebAssembly, on Android, on iOS, and inside agent processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the problem
&lt;/h2&gt;

&lt;p&gt;Most agent memory today is one of two things: a vector store, or a pile of JSON files. Both are wrong for the same reason — they don't model the relational structure of what an agent knows, and they don't preserve &lt;em&gt;when&lt;/em&gt; it knew it.&lt;/p&gt;

&lt;p&gt;A coding agent that decided last Tuesday to use Postgres over MongoDB needs to remember not just the decision, but the rationale, the alternatives considered, and what the codebase looked like at the time. A vector store can find a similar-sounding chunk; it can't reconstruct the decision graph. A JSON pile can store the data; it can't query "show me every decision motivated by performance concerns made before the v2 refactor."&lt;/p&gt;

&lt;p&gt;That second query — graph traversal scoped by time — is what Minigraf is built for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 1.0 actually ships
&lt;/h2&gt;

&lt;p&gt;The core query model is Datalog over EAV triples (entity-attribute-value), which is the same model Datomic and XTDB use. Minigraf's contribution is the packaging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bi-temporal by design.&lt;/strong&gt; Every fact carries both transaction time (when it was recorded) and valid time (when it was true in the world). Retract a fact and the history is preserved — you can replay the database state at any past moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single file, embedded.&lt;/strong&gt; &lt;code&gt;Minigraf::open("data.graph")&lt;/code&gt; and you're running. No daemon, no port, no config. The entire database is one file you can ship, version, or sync.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Datalog rules.&lt;/strong&gt; Multi-hop graph traversals are native, not bolted on. Reachability, transitive closure, and path queries are one rule each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prepared statements.&lt;/strong&gt; Parse and plan once, execute thousands of times with &lt;code&gt;$slot&lt;/code&gt; bind tokens. Roughly the same ergonomics as &lt;code&gt;sqlite3_prepare_v2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Window functions in &lt;code&gt;:find&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;avg&lt;/code&gt;, &lt;code&gt;rank&lt;/code&gt;, &lt;code&gt;row_number&lt;/code&gt; with &lt;code&gt;:over (partition-by … :order-by …)&lt;/code&gt;. Aggregations without dropping out of Datalog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile and WASM.&lt;/strong&gt; Native Kotlin (&lt;code&gt;.aar&lt;/code&gt;) and Swift (&lt;code&gt;.xcframework&lt;/code&gt;) bindings via UniFFI. Browser WASM via &lt;code&gt;wasm32-unknown-unknown&lt;/code&gt;, server WASM via &lt;code&gt;wasm32-wasip1&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;minigraf&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Minigraf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OpenOptions&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;OpenOptions&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"agent.graph"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="nf"&gt;.execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r#"
    (transact [[:decision-42 :decision/chose "postgres"]
               [:decision-42 :decision/considered "mongodb"]
               [:decision-42 :motivated-by :perf-concern]])
"#&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// What did we believe at transaction 100?&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="nf"&gt;.execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r#"
    (query [:find ?choice
            :as-of 100
            :where [?d :decision/chose ?choice]
                   [?d :motivated-by :perf-concern]])
"#&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What it isn't
&lt;/h2&gt;

&lt;p&gt;Minigraf is deliberately not distributed, not cluster-scale, and not client-server. It's optimised for sub-million-node graphs that live next to a single process — an agent, a mobile app, a browser tab. If you have a billion nodes and a fleet of services, you want XTDB or Neo4j. If you have an agent that needs to remember a month of decisions and replay any past state, you want Minigraf.&lt;/p&gt;

&lt;p&gt;It's also not a time-series database. Time-series tools (InfluxDB, Prometheus) are optimised for measurements at a point in time. Minigraf is optimised for facts with full retraction history — different problem, different shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why now
&lt;/h2&gt;

&lt;p&gt;The bi-temporal-graph thesis isn't new. Datomic has had it since 2012; XTDB built on the idea; my own previous project, RecallGraph, was pursuing the same vision in 2019. What's new is the audience.&lt;/p&gt;

&lt;p&gt;Agents are the use case bi-temporal databases were waiting for. An agent's memory has all the structural properties — entities with relationships, beliefs that get corrected, decisions with provenance, states that need to be reconstructed at past moments — that bi-temporal Datalog was designed for. The vector store wave gave us "find similar," but agents that &lt;em&gt;reason&lt;/em&gt; need "what did I believe and why." Minigraf is built for that second question.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;minigraf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add minigraf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo is at github.com/project-minigraf/minigraf. The README has a quickstart, the wiki has a Datalog reference and a comparison page (vs XTDB, Cozo, Neo4j, SQLite), and there's a working agent memory skill at github.com/project-minigraf/temporal_reasoning that demonstrates the bi-temporal model end to end.&lt;/p&gt;

&lt;p&gt;If you build something on Minigraf, I want to hear about it — open a Discussion on the repo or reach out directly. The next phase of the project is shaped by what people actually use it for, and 1.0 is when that conversation starts.&lt;/p&gt;

&lt;p&gt;⭐ Star the repo if the thesis resonates — it helps surface the project to others working on similar problems.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>database</category>
      <category>datalog</category>
      <category>agents</category>
    </item>
    <item>
      <title>CivicGraph is now RecallGraph</title>
      <dc:creator>Aditya Mukhopadhyay</dc:creator>
      <pubDate>Thu, 01 Oct 2020 10:10:28 +0000</pubDate>
      <link>https://forem.com/adityamukho/civicgraph-is-now-recallgraph-57o2</link>
      <guid>https://forem.com/adityamukho/civicgraph-is-now-recallgraph-57o2</guid>
      <description>&lt;p&gt;I had &lt;a href="https://dev.to/adityamukho/civicgraph-a-versioning-data-store-for-time-variant-graph-data-1pja"&gt;posted earlier&lt;/a&gt; about an open source temporal graph database that I have built, named CivicGraph.&lt;/p&gt;

&lt;p&gt;I am thrilled to follow up on that with a lineup of exciting announcements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CivicGraph is now renamed to &lt;em&gt;RecallGraph&lt;/em&gt;. This was deemed necessary to avoid confusion with another identically named (but functionally different) product by Microsoft. Also, the new name serves as a useful reminder for what the product is designed to do.&lt;/li&gt;
&lt;li&gt;RecallGraph has its own sparkling new home. Check out &lt;a href="https://recallgraph.tech/"&gt;https://recallgraph.tech/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;There is also a dedicated documentation website, replete with concepts, terminologies and a comprehensive guide to getting started with the product. Check out &lt;a href="https://docs.recallgraph.tech/"&gt;https://docs.recallgraph.tech/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;New API endpoints to support advanced functionalities like purge and restore.&lt;/li&gt;
&lt;li&gt;Built-in support for distributed tracing, based on the &lt;a href="https://opentracing.io/"&gt;OpenTracing&lt;/a&gt; standard.&lt;/li&gt;
&lt;li&gt;More improvements, both major and minor, all listed at &lt;a href="https://docs.recallgraph.tech/working-with-recallgraph/changelog#1-0-0"&gt;https://docs.recallgraph.tech/working-with-recallgraph/changelog#1-0-0&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Support for Foxx's &lt;a href="https://www.arangodb.com/docs/3.7/foxx-guides-dependencies.html"&gt;service linking&lt;/a&gt;, documented at &lt;a href="https://recallgraph.github.io/RecallGraph/"&gt;https://recallgraph.github.io/RecallGraph/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A community support forum hosted at &lt;a href="https://gitter.im/RecallGraph/community"&gt;Gitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Swagger API documentation (standalone) at &lt;a href="https://app.swaggerhub.com/apis-docs/RecallGraph/RecallGraph/1.0.0#/"&gt;https://app.swaggerhub.com/apis-docs/RecallGraph/RecallGraph/1.0.0#/&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are still miles to go, with a long development roadmap ahead. I am indeed grateful to all of you who have supported and encouraged me to keep building and improving this project! I hope it provides productive service in your tech stack(s) some day.&lt;/p&gt;

</description>
      <category>temporal</category>
      <category>graph</category>
      <category>database</category>
    </item>
    <item>
      <title>CivicGraph - A versioning data store for time-variant graph data.</title>
      <dc:creator>Aditya Mukhopadhyay</dc:creator>
      <pubDate>Sat, 01 Feb 2020 15:01:01 +0000</pubDate>
      <link>https://forem.com/adityamukho/civicgraph-a-versioning-data-store-for-time-variant-graph-data-1pja</link>
      <guid>https://forem.com/adityamukho/civicgraph-a-versioning-data-store-for-time-variant-graph-data-1pja</guid>
      <description>&lt;p&gt;I would like to introduce an open source, Apache 2.0 licensed project of mine: &lt;a href="https://github.com/CivicGraph/CivicGraph"&gt;https://github.com/CivicGraph/CivicGraph&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CivicGraph is a versioned-graph data store - it retains all changes that its data (vertices and edges) have gone through to reach their current state. It supports point-in-time graph traversals, letting the user query any past state of the graph just as easily as the present.&lt;/p&gt;

&lt;p&gt;It is a &lt;a href="https://www.arangodb.com/why-arangodb/foxx/"&gt;Foxx Microservice&lt;/a&gt; for &lt;a href="https://www.arangodb.com/"&gt;ArangoDB&lt;/a&gt; that features VCS-like semantics in many parts of its interface, and is backed by a transactional event tracker. It is currently being developed and tested on ArangoDB v3.5, with support for v3.6 in the pipeline.&lt;/p&gt;

&lt;p&gt;CivicGraph is a potential fit for scenarios where data is best represented as a network of vertices and edges (i.e., a graph) having the following characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Both vertices and edges can hold properties in the form of attribute/value pairs (equivalent to JSON objects).&lt;/li&gt;
&lt;li&gt;Documents (vertices/edges) mutate within their lifespan (both in their individual attributes/values and in their relations with each other).&lt;/li&gt;
&lt;li&gt;Past states of documents are as important as their present, necessitating retention and queryability of their change history.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Its API is split into 3 top-level categories:&lt;/p&gt;

&lt;h3&gt;
  
  
  Document
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Create&lt;/strong&gt; - Create single/multiple documents (vertices/edges).&lt;br&gt;
&lt;strong&gt;Replace&lt;/strong&gt; - Replace entire single/multiple documents with new content.&lt;br&gt;
&lt;strong&gt;Delete&lt;/strong&gt; - Delete single/multiple documents.&lt;br&gt;
&lt;strong&gt;Update&lt;/strong&gt; - Add/Update specific fields in single/multiple documents.&lt;br&gt;
&lt;strong&gt;(Planned) Explicit Commits&lt;/strong&gt; - Commit a document's changes separately, after it has been written to DB via other means (AQL / Core REST API / Client).&lt;br&gt;
&lt;strong&gt;(Planned) CQRS/ES Operation Mode&lt;/strong&gt; - Async implicit commits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Log&lt;/strong&gt; - Fetch a log of events (commits) for a given path pattern (path determines scope of documents to pick). The log can be optionally grouped/sorted/sliced within a specified time interval.&lt;br&gt;
&lt;strong&gt;Diff&lt;/strong&gt; - Fetch a list of forward or reverse commands (diffs) between commits for specified documents.&lt;br&gt;
&lt;strong&gt;(Planned) Branch/Tag&lt;/strong&gt; - Create parallel versions of history, branching off from a specific event point of the main timeline. Also, tag specific points in branch+time for convenient future reference.&lt;br&gt;
&lt;strong&gt;(Planned) Materialization&lt;/strong&gt; - Point-in-time checkouts.&lt;/p&gt;

&lt;h3&gt;
  
  
  History
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Show&lt;/strong&gt; - Fetch a set of documents, optionally grouped/sorted/sliced, that match a given path pattern, at a given point in time.&lt;br&gt;
&lt;strong&gt;Filter&lt;/strong&gt; - In addition to a path pattern like in 'Show', apply an expression-based, simple/compound post-filter on the retrieved documents.&lt;br&gt;
&lt;strong&gt;Traverse&lt;/strong&gt; - A point-in-time traversal (walk) of a past version of the graph, with the option to apply additional post-filters to the result.&lt;/p&gt;

&lt;p&gt;I hope some of you may find this a useful service to address several types of data modelling challenges pertaining to retention and querying of historical graph data.&lt;/p&gt;

</description>
      <category>eventstore</category>
      <category>historicalgraph</category>
      <category>arangodb</category>
      <category>foxx</category>
    </item>
  </channel>
</rss>
