Persistent store with Git semantics: lazy reads, delayed writes, content-addressing
OCaml 93.7%
Perl 3.3%
Standard ML 1.6%
Dune 0.4%
Shell 0.1%
Other 0.9%
67 1 0

Clone this repository

https://tangled.org/gazagnaire.org/irmin https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/irmin
git@git.recoil.org:gazagnaire.org/irmin git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/irmin

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

Irmin 4.0#

Content-addressable tree store for OCaml. Irmin models data as lazy, hash-linked trees that can be read from and written to pluggable backends. It supports both Git object format and ATProto PDS (DAG-CBOR) trees, and can expose any store over HTTP as a read-only ATProto PDS.

Architecture#

┌─────────────────────────────────────────┐
│  Link API (typed, schema-driven)        │  ← User-facing, type-safe
│  - Typed paths with encode/decode       │
│  - get/set with 'a leaf accessors       │
└────────────────┬────────────────────────┘
                 │ compiles to
┌────────────────▼────────────────────────┐
│  Tree API (lazy reads, delayed writes)  │  ← Staging area
│  - Nodes loaded on-demand               │
│  - Writes accumulate until flush        │
│  - Like Git's index/staging             │
└────────────────┬────────────────────────┘
                 │ compiles to
┌────────────────▼────────────────────────┐
│  KV/Backend (raw content-addressed)     │  ← Storage
│  - read/write by hash                   │
│  - refs for mutable pointers            │
│  - Memory, Git, Pack implementations    │
└─────────────────────────────────────────┘

Design Principles#

  1. One functor, used once. The Make functor takes a format. Pre-instantiated as Git and Pds.
  2. One module, one concern. Hash in Hash. Node encoding in Codec. Storage in Backend.
  3. Explicit is better than implicit. No magic, no hidden state.
  4. Consistent error handling. All fallible operations return result.

Features#

  • Phantom-typed hashes: SHA-1 and SHA-256 can't be mixed
  • Lazy reads: Nodes loaded on-demand from backend
  • Delayed writes: Changes accumulate until flush
  • Multiple formats: Git trees and ATProto PDS
  • Subtree operations: For monorepo workflows (replaces git subtree shelling)
  • XRPC serving: Expose any store as a read-only ATProto PDS over HTTP (irmin serve)

Usage#

(* Create a memory backend *)
let backend = Irmin.Backend.Memory.create_sha1 () in
let store = Irmin.Store.Git.create ~backend in

(* Get an empty tree *)
let tree = Irmin.Store.Git.tree store () in

(* Add content - writes are delayed *)
let tree = Irmin.Tree.Git.add tree ["src"; "main.ml"] "let () = ()" in

(* Commit - this flushes the tree to backend *)
let commit = Irmin.Store.Git.commit store ~tree ~parents:[]
  ~author:"me" ~message:"init" in

(* Set branch head *)
Irmin.Store.Git.set_head store ~branch:"main" commit

Tree Formats#

Module Hash Format
Irmin.*.Git SHA-1 Git object format
Irmin.*.Pds SHA-256 ATProto DAG-CBOR PDS

Module Structure#

Irmin
├── Hash          # Phantom-typed SHA-1/SHA-256
├── Codec         # Format.S signature + Git/Pds implementations
├── Backend       # KV storage (Memory, Git, layered, cached)
├── Tree          # Lazy tree with delayed writes
├── Commit        # Commit operations
├── Store         # High-level API (tree + commits + branches)
├── Subtree       # Monorepo subtree operations
└── Git_interop   # Git repository I/O

CLI#

irmin serve [-p PORT] [--did DID]   Serve store as read-only ATProto PDS over XRPC

References#