Overview

About Arc

Why another version control system, what problems it solves, and the ideas behind its design.

Background

Version control has evolved from per-file delta chains (RCS, SCCS) to centralised repositories (CVS, Subversion) to distributed snapshot DAGs (Git). Git’s model is powerful, but its interface reflects its origins in Linux kernel development — staging areas, reflogs, rebase strategies, and a large command surface. Alternatives like Mercurial, Fossil, Pijul, and Darcs each explored different trade-offs, but all are standalone applications tied to their own storage format and CLI.

Meanwhile, software projects are trending toward many small, composable files — driven by modern frameworks, AI-assisted development, and tooling that works best with granular file trees. Arc is built for this environment.

Why Arc exists

Arc is a modern, general-purpose version control system built as a library. It provides the full feature set — checkpoints, branches, merges, tags, stash, cherry-pick, undo — for individuals, teams, and AI-assisted workflows. Because it is a library, the same VCS can also be embedded directly into any application that needs versioning.

The core is a set of pure functions. Each takes a storage backend as its first argument, so the same logic runs against any store — a local filesystem, a PostgreSQL database, or a browser’s IndexedDB.

Design

Flat manifests

Every checkpoint records a flat map of file paths to content hashes. Restoring any checkpoint is a single read — no tree traversal, no graph walking. Git stores snapshots too, but encodes them as nested tree objects that reference other tree objects that reference blobs. Reconstructing a file list means walking that entire hierarchy. Arc’s manifests are what you read: a direct picture of your project with nothing to resolve.

Self-contained checkpoints

Each checkpoint includes a complete manifest. This makes every checkpoint independently transferable, which is what enables shallow clones, partial fetching, and straightforward pruning. There are no loose-object-to-pack transitions, no repacking, and no compaction cycles. The manifest compresses well with gzip because paths and hashes are repetitive across checkpoints.

Content-addressed storage

File content is stored by its SHA-256 hash. Identical files across branches and checkpoints share a single blob, giving you deduplication, integrity verification, and straightforward garbage collection. Blobs are delta-compressed automatically — text files over 4 KB are stored as line-level diffs against their previous version, with automatic hydration when chains get deep. The hash is always of the full content, so manifests, deduplication, and transfers work the same regardless of how a blob is stored internally.

How it fits together

checkpoint cp-a7f3
manifest
src/app.js→ 9f8e
lib/util.js→ c4d5
README.md→ 7b6a
checkpoint cp-b8e2
manifest
src/app.js→ 3a2b
lib/util.js→ c4d5
README.md→ 7b6a
blob store (SQLite)
9f8efullsrc/app.js (checkpoint A)
c4d5fulllib/util.js (shared by both)
7b6afullREADME.md (shared by both)
3a2bdelta → 9f8esrc/app.js (checkpoint B)
Hash is always SHA-256 of full content — never of the delta
readBlob(3a2b) resolves the delta chain transparently

Each checkpoint stores a complete manifest. Unchanged files share the same blob via content-addressing. Changed files are stored as deltas when beneficial. Reads resolve chains automatically — callers always get full content.

Monotonic trunk sequence

Checkpoint IDs are content hashes — stable and globally unique, but unordered. When a checkpoint lands on the trunk (main), Arc also assigns it a monotonic, increasing sequence number. The hash stays the canonical identity; the sequence gives trunk history a human-readable total order, so a host can say “main is at #1248” or “your branch is 37 behind” without walking the graph.

Zero dependencies

No native modules, no C bindings, no build step. Arc runs anywhere JavaScript runs — Node.js, Deno, Bun, or the browser.

Familiar operations, simpler model

Arc covers the same workflow — branching, merging, cherry-picking, stashing, blame, undo — but without the concepts that exist only to manage internals. There is no staging area and no reflog. Fewer moving parts means fewer things to learn and fewer failure modes.

What this enables

Storage is just an interface

You provide a FileAdapter for project files and an ArcStorage for internal data. SQLite and PostgreSQL are included; implement the same interface to run against IndexedDB, S3, MySQL, or anything else. Because storage is an interface rather than a filesystem assumption, Arc doesn’t need files on disk at all — you can create checkpoints, switch branches, and merge entirely against a database, which makes it practical in serverless functions, containers, and browser-based editors.

This also means multiple users can share the same backend. A team on Postgres gets the same branching and merging as a solo developer on SQLite. And if your project already lives in a database — a CMS, a design tool, a document editor — Arc talks to it directly, with no round-trip through the filesystem.

A living monorepo

Because content is addressed by hash and a checkpoint is a flat manifest, materialising any branch’s full tree from its tip is cheap — no copy, just references into the shared blob store. A host can give every user their own branch view of one shared workspace: two people can sit on two different branches at the same time, each seeing that branch’s tree and content, while live edits sync only among users on the same branch. Switching branches is a non-destructive view-swap — instant, and each branch keeps its own uncommitted work. The unit of isolation is the branch, so anyone who wants private, experimental state branches off — a one-click operation since no files are copied.

Embeddable by default

Git is a standalone binary. To version-control something from an application, you spawn a subprocess, pass arguments, and parse stdout. Arc is a library — you import functions and call them. This means any application can embed version control as a feature: undo history in an editor, branching in a project management tool, audit trails in a CMS. No installation step, no PATH configuration, no binary compatibility concerns.

Source code stays on your infrastructure

For teams and companies that need to control where source code lives, Git’s model is a problem — every developer clones the full repository to their machine, and once it’s on a personal device, it’s outside your control. Large companies have built entire virtual filesystem layers (Google’s CitC, Meta’s EdenFS, Microsoft’s VFS for Git) just to work around this. With Arc, organisations can keep the entire codebase in a central database and give developers access through a controlled environment — a browser-based IDE, a locked-down desktop app, or any application that embeds Arc. Developers branch, merge, diff, and review without ever downloading the repository. Permissions can be enforced per-file or per-branch at the backend level, and every operation goes through your database, giving you a complete audit trail by default.

How it compares

GitFossilArc
ModelSnapshot DAGSnapshot DAGSnapshot DAG
StoragePack files on filesystemSingle SQLite filePluggable (SQLite, Postgres, custom)
EmbeddableNo (shell out to binary)No (standalone binary)Yes (JS library, pure functions)
DependenciesC toolchain, zlib, opensslC toolchain, SQLite (bundled)None
CompressionPack files (binary delta)zlib per-artifactDelta-compressed blobs (gzip) + full manifests (gzip)
Staging areaYes (index)NoNo