A Git-native runtime for shared causal history.
Offline-first, multi-writer, deterministic, and built for provenance-aware graphs.
git-warp is a Git-native system for storing and reading causal history.
Instead of treating a graph as one big in-memory object, git-warp treats history as the source of truth. Reads are bounded views over that history, and writes are appended as patches. It is one runtime in the Continuum stack (more below).
If that sounds abstract, the short version is:
- You can work offline.
- Multiple writers can contribute without central coordination.
- Conflicts resolve deterministically.
- Every value keeps provenance.
- Reads are designed to stay bounded, not accidentally materialize everything.
git-warp provides a causal history substrate and read/runtime layer for graph-shaped data.
It lets you:
- Commit patches into a shared causal log.
- Read the latest visible state through worldlines.
- Read historical coordinates without rewriting history.
- Use observers and apertures to control what a reader can see.
- Keep provenance attached to values and outcomes.
- Sync through normal Git transport.
v18.1.2 publishes the source-backed reference shelf for package entrypoints,
root API exports, CLI commands, structured CLI errors, and public error classes.
It also locks the release path to autotag the exact merged main commit, then
publish npm and JSR from a maintainer-dispatched workflow.
See CHANGELOG.md for the full in-repository release notes.
import { GitGraphAdapter, openWarpWorldline } from "@git-stunts/git-warp";
import GitPlumbing from "@git-stunts/plumbing";
const plumbing = new GitPlumbing({ cwd: "." });
const persistence = new GitGraphAdapter({ plumbing });
const events = await openWarpWorldline({
persistence,
worldlineName: "events",
writerId: "agent-1",
});
// Commit: admit a claim into shared causal history.
await events.commit((patch) => {
patch.addNode("user:alice").setProperty("user:alice", "role", "admin");
});
// Read: confirm what is visible through the worldline.
const visible = await events
.live()
.query()
.match("user:alice")
.select(["id"])
.run();The live() query above reads the latest visible state. When you instead want a bounded, coherent read pinned to a point in history, you read through an optic.
- An optic is the bounded question you ask of causal history — "which node, property, neighbor set, or traversal do I want?" It names the read you mean instead of materializing the whole graph to go looking.
- We use optics so reads stay scoped and coherent: an optic answers from a fixed position, so concurrent writes can't shift the result mid-read, and the runtime only touches the causal support the question actually needs.
- An optic basis is the bounded evidence that the read can be answered honestly from history — a verified checkpoint-tail basis.
prepareOpticBasis()establishes it. If no bounded basis exists yet, it fails closed withE_OPTIC_NO_BOUNDED_BASISrather than silently materializing everything. - An optic always reads through an observer coordinate:
coordinate()captures a stable, observer-relative position (a causal basis plus a ceiling). Later writes advance the live worldline, but reads through that coordinate keep answering from the captured position. - Missing non-empty nodes and properties read as absence data. Empty target identities are invalid optic schemas and fail with
E_OPTIC_FAILURE_SCHEMA.
So the order is: verify the basis, capture a coordinate, then read through it.
await events.prepareOpticBasis();
const coordinate = await events.coordinate();
const role = await coordinate.optic().node("user:alice").prop("role").read();For the Nerds™: Optics
In category theory, an optic from a whole
$(S, T)$ to a part$(A, B)$ is an element of a coend — an existential package over a residual object$M$ :
$$\mathrm{Optic}\big((S,T),,(A,B)\big) ;=; \int^{M} \mathcal{C}!\left(S,; M \otimes A\right) \times \mathcal{C}!\left(M \otimes B,; T\right)$$ That is a focus
$S \to M \otimes A$ paired with a put-back$M \otimes B \to T$ , where$M$ — everything you didn't look at — is sealed inside the existential and never named.git-warp's read model is the read-only half. The whole
$S$ is a coordinate (a reading over causal history); the part$A$ is the bounded question (.node(),.prop(), a traversal); the residual$M$ is the rest of history you deliberately do not materialize. The bounded support rule is that$M$ made small and explicit, andprepareOpticBasis()is the witness that a lawful factorization$S \to M \otimes A$ exists at the chosen coordinate. No witness ⇒E_OPTIC_NO_BOUNDED_BASIS: the runtime refuses the read rather than collapsing$M$ back into the whole graph.And
.node("user:alice").prop("role")is literal optic composition — composing optics tensors their residuals ($M_1 \otimes M_2$ ), so a chained read stays bounded by construction.
Two more shipped reads stay bounded without folding the whole graph. Both use the advanced openWarpGraph() surface.
const graph = await openWarpGraph({ persistence, graphName: "events", writerId: "agent-1" });
// What changed between two live Lamport ceilings — a frozen GraphDiff, not a wildcard scan.
const diff = await graph.comparison.diff({ from: 120, to: 135, targetId: "user:alice" });
// One entity's backward causal cone, replayed on its own (a diagnostic read).
const slice = await graph.provenance.materializeSlice("user:alice");See examples/ for runnable versions and Optic reads for the model.
git-warp's concepts span how history is written, positioned, read, accelerated, proven, and persisted. The map marks runtime posture directly. Status markers: no mark = shipped runtime truth, ~ = transition (the noun exists but is narrower than its canonical meaning), * = target (intended architecture, not yet a first-class runtime concept).
mindmap
root((git-warp))
Write
Patch
Worldline ~
Live strand ~
Braid *
Position
Coordinate ~
Frontier ~
Ceiling
Tick ~
Read
ProjectionHandle
Observer ~
Aperture ~
Optic ~
Optic basis
Support
Bounded support rule ~
Causal index ~
Support fragment ~
Materialization plan *
Prove
Witness *
TickReceipt
GraphDiff ~
Suffix admission shell ~
Persist
Snapshot
State cache
Checkpoint ~
| Concept | Status | One-line meaning |
|---|---|---|
| Patch | shipped | An appended claim about a bounded causal site; never rewritten. |
| Worldline | transition | The named causal history a writer commits to and readers observe. |
| Live strand | transition | A strand over a live parent basis plus its own owned overlay divergence. |
| Braid | target | A composition of lanes; common-basis braid validation is not yet shipped. |
| Coordinate | transition | A comparable read point: a causal basis plus a ceiling. |
| Frontier | transition | The causal basis — which history has been observed (writer tips / version vectors). |
| Ceiling | shipped | The upper replay boundary on a coordinate or lane. |
| Tick | transition | One atomic admitted history step on a lane. |
| ProjectionHandle | shipped | A pinned read handle returned by live() and seek(). |
| Observer | transition | A read surface that answers a question through an aperture. |
| Aperture | transition | The { match, expose, redact } policy bounding what an observer sees. |
| Optic | transition | A first-class runtime read-intent noun used by fluent optic reads; native Continuum transport remains future work. |
| Optic basis | shipped | Verified bounded evidence (prepareOpticBasis()) that an optic read is answerable without full materialization. |
| Bounded support rule | transition | The smallest causally sufficient support set to answer an optic honestly. |
| Causal index | transition | A rebuildable acceleration structure that finds support without whole-graph discovery. |
| Support fragment | transition | A cached partial materialization keyed by support and coordinate (cache storage pending). |
| Materialization plan | target | The plan deciding receipts vs. indexes vs. fragments vs. replay vs. full state. |
| Witness | target | Minimal information sufficient to justify a local change result. |
| TickReceipt | shipped | The operational envelope recording what happened for one admitted step. |
| GraphDiff | transition | A first-class "what changed between these coordinates?" result. |
| Witnessed suffix admission shell | transition | Observer-readable import/export envelope for a transported suffix; live Echo/git-warp network exchange remains Continuum stack work. |
| WarpStateSnapshot | shipped | A persisted materialized graph state at a coordinate. |
| WarpStateCache | shipped | The owning system for persisted and in-memory snapshot reuse. |
| Checkpoint | transition | A pinned snapshot protected from ordinary eviction. |
The topic pages own the current explanations for these nouns. Exact API, CLI, schema, and error inventories should be generated or coverage-checked rather than maintained as long-form prose; see the generated source-backed reference.
Opticis now a reified runtime noun for the public read path. The fluent API lowers into a frozenOpticvalue before execution; see Optic reads.
Writers can make independent changes without a central coordinator. When history converges, the same patches produce the same visible result.
For the Nerds™ — Convergence is a join-semilattice
Deterministic multi-writer merge is the statement that materialized state forms a join-semilattice
$(L, \sqcup)$ : a partial order with a least upper bound for any pair. Each writer's patches push state up the order, and merge is the join$\sqcup$ — idempotent, commutative, and associative:
$$x \sqcup x = x \qquad x \sqcup y = y \sqcup x \qquad (x \sqcup y) \sqcup z = x \sqcup (y \sqcup z)$$ Those three laws are exactly what "no central coordinator" buys you:
- commutativity ⇒ writers can apply each other's patches in any order,
- associativity ⇒ they can batch them however the network delivers them,
- idempotence ⇒ re-delivering the same patch is harmless.
So convergence isn't luck; it's the least upper bound
$\bigsqcup_i h_i$ of everyone's observed history$h_i$ . This is the CRDT (state-based / CvRDT) guarantee: monotone updates into a semilattice always reconcile to the same join, independent of message order or duplication.
History is never rewritten. New claims are appended to Git refs under refs/warp/....
Every visible value traces back to the patch that produced it.
The runtime is designed so reads stay scoped. It avoids the “just materialize the whole graph” footgun.
For the Nerds™ — A causal cone is a down-set
History is a poset
$(H, \preceq)$ under causal precedence (Git's parent edges give the Hasse diagram). A coordinate picks a consistent cut: a down-closed set, i.e. a down-set / order ideal
$$\downarrow! C ;=; {, x \in H \mid x \preceq c \text{ for some } c \in C ,}.$$ A frontier is that cut's boundary — an antichain of writer tips, the maximal elements of the ideal.
A read's causal cone
$D(v) = {\downarrow}{v}$ is the down-set generated by$v$ : everything that could have influenced it, and nothing that couldn't. Because the poset is well-founded,$D(v)$ is finite even when$H$ is unbounded — which is why a bounded read can exist at all. The bounded support rule is then just the claim "this optic's answer factors through$D(v)$ , so materializing the rest of$H \setminus D(v)$ is provably unnecessary."
History keeps per-entity provenance, so a single node's backward causal cone can be reconstructed and replayed on its own: provenance.materializeSlice(nodeId) loads only the cone's patches, never the whole graph. This slice path is currently classified as a diagnostic read, not a first-use application API.
The broader worldline-wide direction is still narrower than the doctrine: live strands and support fragments have runtime footholds, but support-fragment cache storage, plan-driven fragment execution, and full holographic worldline reads are not first-use shipped paths. See Runtime posture, Optic reads, and Strands.
The main application entry point is openWarpWorldline().
A worldline gives you a small, practical interface:
| Method | What it does |
|---|---|
commit() |
Admits a patch into the worldline |
live() |
Reads the latest visible state |
seek() |
Reads a historical coordinate |
observer() |
Creates a filtered read view |
prepareOpticBasis() |
Verifies bounded evidence for coordinate-based reads |
coordinate() |
Captures a stable causal position |
optic() |
Starts a one-off read that lowers through a reified Optic |
For coherent optic reads, call prepareOpticBasis() first, then read through a coordinate.
If no bounded basis exists yet, prepareOpticBasis() fails closed with E_OPTIC_NO_BOUNDED_BASIS rather than materializing the whole graph.
Advanced tooling can also use openWarpGraph() directly. That lower-level surface is intended for compatibility, diagnostics, substrate operations, and migration work. New application code should generally prefer worldlines and optics.
openWarpGraph() exposes the runtime through four moments:
| Moment | Capabilities | What it does |
|---|---|---|
| Commitment | patches, strands, comparison |
Admits claims into frontier-relative truth |
| Folding | checkpoint |
Re-expresses admitted history as operational artifacts |
| Revelation | query, subscriptions, provenance |
Exposes admitted truth under bounded rights |
| Governance | sync |
Transports and admits remote suffixes |
Public examples use the flat aliases like graph.query and graph.checkpoint. The moment-scoped names are the same runtime object with more explicit naming.
Git and WARP fit together because both are:
- append-only in spirit.
- content-addressed.
- distributed and multi-writer.
- history-preserving.
Each writer appends patch commits under refs/warp/<graph>/writers/<writerId>. The refs stay outside normal branch history, so graph history stays separate from your checked-out source tree. Patch commits may carry patch and content trees; the isolation comes from refs and Git plumbing, not from pretending every data commit is empty. Sync uses normal git push and git fetch over the WARP refs.
For the Nerds™ — Git as a Merkle DAG, patches as a free monoid
Git's object store is a Merkle DAG: every object is named by the hash of its content, so a commit's id transitively fixes its entire history. That gives structural sharing (equal subhistories are stored once — hash-consing) and tamper-evidence for free: change one byte upstream and every downstream id changes.
git-warpleans on two consequences. First, each writer's chain atrefs/warp/<graph>/writers/<writerId>is the free monoid$(W^{*},, \cdot,, \varepsilon)$ on that writer's claims$W$ — append-only concatenation$\cdot$ , empty history$\varepsilon$ as identity, no rewriting. Second, the commits live on WARP refs rather than source-tree refs, so graph history rides Git's transport and dedup without touching your working tree. Merge law lives one layer above this (see the semilattice note); Git supplies the verifiable spine.
git-warp is one runtime in the Continuum stack. Continuum is not a runtime, database, or storage engine — it is the shared boundary protocol that lets independent runtimes, apps, debuggers, and agents exchange witnessed history instead of copying one database or scraping UIs.
Continuum's model shift is the same one git-warp is built on:
The graph is a coordinate chart over witnessed causal history. History is the territory; state is a policy-relative materialized view; files are readings; writes are intents; admission is witnessed.
Its shared vocabulary is Intent → Admission → Witness → Reading:
- Intent — "I want to do this" (a submitted patch).
- Admission — the runtime decides whether it can happen.
- Witness — evidence for the decision (receipts, provenance).
- Reading — one lawful view of the resulting history (worldlines, optics, observers).
In the stack, git-warp and Echo own runtime truth, while Continuum owns the boundary language and proof posture that lets those runtimes cooperate across the network.
| Use case | Fit |
|---|---|
| Offline-first multi-writer convergence | Strong |
| Agent/tool substrate with causal history | Strong |
| Graph semantics without inventing merge law | Strong |
| Speculative lanes for what-if exploration | Strong |
| High-throughput real-time execution | Use Echo instead |
| General-purpose OLTP | Use Postgres |
| Full-text search / analytics | Use purpose-built engines |
| Time-travel debugging UI | Use warp-ttd on top of git-warp |
Current first-use docs teach openWarpWorldline(), worldline reads, coordinates, reified optics, and observer apertures as the application path. GitWarpWitnessedSuffixAdmissionShell is a transition runtime envelope, not proof of live network exchange. Native Continuum witnesshood, remote optic transport, common-basis braid validation, live Echo/git-warp suffix exchange, support-fragment cache storage, and plan-driven fragment execution remain outside the first-use shipped path unless their own docs say otherwise.
- Topics — task-oriented documentation map
- Getting started — first open, write, read, sync
- Optic reads, Observers, and Querying — the current public read model
- Strands, Sync, and CLI — common usage paths
- Git substrate, Content and CAS, and Continuum boundary — substrate and boundary explanations
- Operations and Troubleshooting — maintenance and recovery workflows
- Examples — runnable read-model snippets
- Architecture — hexagonal layers and admission kernel
A Git-native causal history runtime. It stores graph-shaped data as an append-only log of patches in Git refs, then provides safe, bounded reads over that history.
It is deliberately "weird": optimized for offline-first, multi-writer, provenance-first use cases rather than high-throughput OLTP.
It is a state-based CvRDT substrate with strong emphasis on bounded reads, perfect provenance, and Git as the transport layer.
This gives you deterministic convergence without a central server, but reads are intentionally scoped (via optics and coordinates) instead of materializing the entire graph.
Nodes, properties, and directed edges identified by stable string IDs. Changes are additive patches that are never rewritten. See Getting started.
Yes — independently, even fully offline. Histories converge deterministically via the join-semilattice model. No locking required.
npm install @git-stunts/git-warp @git-stunts/plumbingWorks alongside any existing Git repo. Full setup: Getting started.
Standard Git (push/fetch/pull). Patches live under refs/warp/....
Observers + Apertures with { match, expose, redact } policies for different views over the same history.
Check CHANGELOG.md, the topic docs, and the package registry for release and surface status. The README does not carry live release gates.
Strong for offline/moderate causal workloads thanks to bounded support and holographic slices. Not for high-frequency real-time (use Echo).
git-warp: Offline-first/Git-native ("the weird one").- Echo: Primary high-throughput runtime.
- Continuum: Boundary protocol for witnessed history exchange.
No. The fluent API is practical; theory is optional.
Migration tools and diagnostic surfaces exist. See Operations and Git substrate.
Yes. Graph history lives under WARP refs such as refs/warp/<graph>/writers/<writerId>, separate from branch refs and the checked-out worktree.
examples/, docs/topics/, Issues.
Apache-2.0 Copyright © 2026 James Ross • FlyingRobots
Built by FLYING ROBOTS