Skip to content

Architecture Guide

This guide answers one question: after an application commits a SQLite transaction, how does that change become Graft history that can be compared, merged, synchronized, and restored?

It follows one repository containing app.sqlite, settings.json, and a large attachments/report.pdf. These contents take different storage paths and meet in one repository commit.

This is the most important fact in the book.

Application history (repository history)
branch/ref -> repository commit -> tree -> path blob
|
+-- file bytes / external pointer
+-- SQLite snapshot descriptor
SQLite storage history
snapshot descriptor -> VolumeId + ordered log ranges
|
+-- (LogId, LSN) storage commits
|
+-- changed 4 KiB pages

A repository commit says which paths make up an application version. A storage commit says which 4 KiB pages changed from a prior SQLite state. They are not the same commit and are not one-to-one:

  • one repository commit can reference several databases and ordinary files;
  • graft add app.sqlite can create a storage commit before a repository commit exists;
  • a no-op add can reuse a snapshot without creating a storage commit;
  • a branch ref points to a repository commit, never directly to an LSN.

For an insert into a notes table:

1. worktree
ordinary SQLite changes app.sqlite and perhaps app.sqlite-wal
|
| graft add
v
2. consistent private image (temporary)
SQLite online backup captures committed transactions
|
| 4 KiB chunk comparison
v
3. storage snapshot
changed pages enter an immutable segment and storage commit
|
| snapshot descriptor
v
4. index
stage 0 for app.sqlite names that exact snapshot
|
| graft commit
v
5. repository history
write blob -> tree -> commit, then move refs/heads/main

The private image is only a capture boundary. The index is the authority for the next commit. commit does not reopen a database that may have changed since add.

  1. Which state does it read? Worktree, index, a commit, or a side of an active merge?
  2. Which state does it write? Storage, objects, index, ref, merge journal, remote, or worktree?
  3. What identifies the result? Byte hash, object ID, snapshot descriptor, or (LogId, LSN)?
  4. What remains authoritative after failure? A ref, index, merge journal, or rebuildable cache?

Read this section after completing a CLI or SDK quickstart. It explains the system boundaries needed to design a safe integration; task pages remain the source for command sequences, and the specifications define exact contracts.

  1. Repository And Objects
  2. SQLite Snapshots
  3. Stage And Commit
  4. Checkout And Restore
  5. Diff And Merge
  6. Remotes And Recovery
  7. Hands-On Lab

Path identity, object/ref/index semantics, snapshot content, merge results, and remote publication order are observable contracts. Fjall key encodings, cache names, Rust module boundaries, and temp file names are implementation details. They are useful for debugging but not product integration.

There is no supported repository-control compatibility layer based on SQLite PRAGMAs. Supported integration surfaces are the graft CLI and its JSON output, the Node.js SDK, and the HTTP remote packages.