Modern open-source systems still rely on centralized infrastructure to distribute binary artifacts, even when their source code is fully decentralized. This creates a fragile dependency: if hosting endpoints are blocked, degraded, or removed, critical artifacts become unavailable or unverifiable.
git-casaddresses this by making artifact distribution inherit Git’s existing replication model, allowing binaries to be stored, verified, and transported anywhere Git can operate, including mirrored networks, constrained environments, or fully offline contexts.
Hold on. He’s turning Git into a blob store. Let him cook.
Most potent clone available on GitHub (legally).
git-cas uses Git's object database as a storage layer for large, awkward, or
security-sensitive files.
It stores content as chunk blobs, records how to rebuild that content in a manifest, can emit a real Git tree for reachability, and can keep named assets reachable through a GC-safe vault ref.
This repo ships three surfaces over the same core:
- a JavaScript library for Node-first applications
- a human CLI/TUI (
git-cas, andgit caswhen installed as a Git subcommand) - a machine-facing agent CLI for structured automation flows
Primary runtime support is Node.js 22+. The project also maintains a Bun and Deno test matrix.
- storing binary assets, artifacts, bundles, and other files directly in Git
- chunk-level deduplication using fixed-size or content-defined chunking (CDC)
- optional gzip compression before storage
- optional AES-256-GCM encryption
- passphrase-derived keys via PBKDF2 or scrypt
- multi-recipient envelope encryption and recipient mutation
- key rotation without re-encrypting underlying data blobs
- manifest serialization in JSON or CBOR
- large-asset support through Merkle-style sub-manifests
- a GC-safe vault index under
refs/cas/vault - integrity verification, vault diagnostics, and an interactive inspector
git-cas is not:
- a hosted blob service
- a secret-management platform
- an access-control system
- metadata-oblivious storage
- secure deletion
Even when encryption is enabled, repository readers can still see metadata such as slugs, filenames, chunk counts, object relationships, recipient labels, and vault metadata. See SECURITY.md and docs/THREAT_MODEL.md for the exact boundary.
- Plaintext, uncompressed restore can stream chunk-by-chunk.
- Encrypted or compressed restore currently uses a buffered path guarded by
maxRestoreBufferSize(default512 MiB). - Encryption removes most of the dedupe advantage of CDC because ciphertext is pseudorandom.
- Git will happily retain a large number of blobs for you, but that does not mean storage management disappears. You still need to think about repository size, reachability, and maintenance.
- The manifest is the authoritative description of asset order and repeated chunks. The emitted tree is a reachability artifact, not the reconstruction source of truth.
For the library:
npm install @git-stunts/git-cas @git-stunts/plumbingFor the CLI:
npm install -g @git-stunts/git-casThis is the shortest practical path from an empty repo to a stored and restored asset.
mkdir demo-cas
cd demo-cas
git init
git-cas vault init
printf 'hello from git-cas\n' > hello.txt
git-cas store hello.txt --slug demo/hello --tree
git-cas inspect --slug demo/hello
git-cas verify --slug demo/hello
git-cas restore --slug demo/hello --out hello.restored.txtIf git-cas is installed on your PATH, Git can also invoke it as git cas.
Useful first commands:
git-cas store <file> --slug <slug> --treegit-cas restore --slug <slug> --out <path>git-cas inspect --slug <slug>git-cas verify --slug <slug>git-cas vault listgit-cas vault statsgit-cas doctor
import GitPlumbing from '@git-stunts/plumbing';
import ContentAddressableStore from '@git-stunts/git-cas';
const plumbing = new GitPlumbing({ cwd: './demo-cas' });
const cas = ContentAddressableStore.createJson({ plumbing });
const manifest = await cas.storeFile({
filePath: './hello.txt',
slug: 'demo/hello',
});
const treeOid = await cas.createTree({ manifest });
const reread = await cas.readManifest({ treeOid });
await cas.restoreFile({
manifest: reread,
outputPath: './hello.restored.txt',
});
const ok = await cas.verifyIntegrity(reread);
console.log({ treeOid, ok });Common library entry points:
storeFile()createTree()readManifest()restoreFile()verifyIntegrity()inspectAsset()collectReferencedChunks()initVault(),addToVault(),listVault(),resolveVaultEntry()addRecipient(),removeRecipient(),listRecipients(),rotateKey()rotateVaultPassphrase()
git-cas supports both fixed-size chunking and content-defined chunking.
Fixed-size chunking is simpler and predictable. CDC is more resilient to
insertions and shifting edits. See
docs/BENCHMARKS.md
for current published baselines.
Stored chunks live as ordinary Git blobs. createTree() writes a manifest blob
plus the referenced chunk blobs into a Git tree so the asset becomes reachable
like any other Git object.
The vault is a commit-backed slug index rooted at refs/cas/vault. It exists
to keep named assets reachable across normal Git garbage collection and to make
slug-based workflows practical.
The project supports:
- raw 32-byte encryption keys
- passphrase-derived keys
- recipient-based envelope encryption
- recipient mutation and key rotation
- vault passphrase rotation for envelope-encrypted vault entries
The cryptography is useful, but it is not invisible. Metadata remains visible. Read SECURITY.md and docs/THREAT_MODEL.md before treating this as a secrets solution.
The core domain is wired through an observability port rather than Node's event system directly. The repo ships:
SilentObserverEventEmitterObserverStatsCollector
If you want depth instead of a front page:
- docs/GUIDE.md
- long-form walkthrough
- docs/API.md
- command and API reference
- ARCHITECTURE.md
- high-level system map
- SECURITY.md
- crypto and security-relevant implementation notes
- docs/THREAT_MODEL.md
- attacker model, trust boundaries, exposed metadata, non-goals
- docs/BENCHMARKS.md
- published chunking baselines
- examples/README.md
- runnable examples
- CHANGELOG.md
- release history
Use git-cas when you want:
- artifacts to stay inside Git instead of moving to a separate blob service
- explicit chunk-level storage and verification
- Git-native reachability via trees and refs
- encryption on top of Git's object database without inventing a second storage system
Do not use git-cas when you actually need:
- per-user authorization
- opaque metadata
- remote multi-tenant storage management
- secret recovery or escrow
- transparent large-file ergonomics with no Git tradeoffs
Runnable examples live in examples/:
This is an active project with a real multi-runtime test matrix and an evolving docs/planning surface. The public front door should be treated as:
- README for orientation
- API/guide docs for detail
- changelog for release-by-release history
If you are evaluating the system seriously, read the security and threat-model docs before designing around encrypted storage behavior.