CASK is a Git-like, content-addressable store for Go: bytes are keyed by their content digest, objects stay immutable, and typed application models sit on top of the generic core.
cas core stays generic; each app defines its own Object[T] and Store[T] model.Backend and Codec[T] contracts; the client supplies the hash algorithm (sha256 is the default).cas/bloom adds hot-path absence checks; the stdlib-style gzip, zlib, and flate codec wrappers compress payloads when the workload benefits.SHA-256 + flate for durable data, with SHA-512/256 as a fast secure alternative; JSON and compact binary remain valid application-level choices.cas/pack provides chunking and sidecar metadata workflows without changing the identity model.cas/backend/fs is the raw backend, cas/backend/packfs is the storage backend with a private pack index format, and cas/pack is the optional helper used by apps and examples, not by backend internals.cas.Verify and cas.NewVerifier separate object identity from validation, re-reading the bytes with the caller-supplied Hasher while the backend itself stays a storage-only Digest -> bytes layer.gob remains Go-only, while MD5 and SHA-1 are migration-only choices rather than defaults.A single-host content-addressable store. Each named spec is the normative contract:
cas + CLI + embedded viewer; no CAS JSON API, SDK, or server binary. HTTP exposure is an app pattern (examples/) — backend-architecture §1.gitlike library.cas.Hasher; cas/hash/sha256 is go-cask’s default), reference fs+mem backends and a JSON codec; only the cas-core §7.1 surface is stable.gc/prune/clean) hold an exclusive lock and reclaim only objects older than --min-age, so fresh writes survive (cas-core §6).gitlike package is the shared reference — the runnable examples teach seams (artifacts = compression codec, api = HTTP exposure); gitlike is a reference/copy-source object model apps import or copy.cas): generic, app-agnostic, stable surface.gitlike): a copyable template for typed object graphs.cask store operations and the embedded viewer (cask web).cas layers a non-generic byte layer (Digest, Backend + backends) under a generic typed layer (Object[T], Codec[T], Store[T], Walker[T]), with caching wrappers on top. A store also carries the client’s Hasher — the algorithm seam. Apps build their own Object[T] models on Store[T].
classDiagram
direction TB
class Digest {
+String() string
+Equal(other Digest) bool
}
class Hasher {
<<interface>>
+Digest(r io.Reader) (Digest, error)
+Validate(d Digest) error
}
class Backend {
<<interface>>
+Put(ctx, d, r) error
+Get(ctx, d) io.ReadCloser
+Exists(ctx, d) (bool, error)
+Delete(ctx, d) error
+List(ctx) ([]Digest, error)
+Stats(ctx) (*Stats, error)
}
class Object~T~ {
<<interface>>
+Type() string
+References() []Digest
}
class Codec~T~ {
<<interface>>
+Encode(v T) ([]byte, error)
+Decode(data []byte) (T, error)
}
class Store~T~ {
+Put(ctx, obj T) (Digest, error)
+Get(ctx, d) (T, error)
+Delete(ctx, d) error
}
class Walker~T~ {
+Walk(ctx, d) error
}
Store~T~ o-- Backend : raw
Store~T~ o-- Codec~T~ : codec
Store~T~ o-- Hasher : hasher
Store~T~ ..> Object~T~ : stores
Walker~T~ ..> Store~T~ : reads via Get
cas stays hash- and codec-agnostic by design, but the repo recommends a practical default policy for new durable data:
SHA-256 (cas/hash/sha256)flate (cas/codec/flate) for compressed object payloadscas/codec/json) for readability and portability, layered behind the default flate compression when size reduction mattersSHA-512/256 (cas/hash/sha512_256)gzip and zlib (cas/codec/gzip, cas/codec/zlib) for workloads that prefer a different compression profilecas/pack for fixed-size chunking and sidecar metadata workflows in app-level storage patternscas/codec/binary when a stable per-type binary layout is requiredgob (cas/codec/gob) for Go-only compatibility, not for durable long-term storageLegacy or compatibility-only hashes should not be used for new content-addressed data: MD5 and SHA-1 are migration-only or compatibility choices, not the default for a CAS.
Use cryptographic hashes for object identity and integrity. For new data, prefer SHA-256 or SHA-512/256. Do not use MD5 or SHA-1 for new content-addressed data, even when a legacy system still emits them; they are not recommended for new objects or new interoperability contracts.
Current patch release: v1.4.2. This maintenance release documents the default policy as SHA-256 + flate compression for durable payloads, refreshes the benchmark guidance to keep benchmark winners distinct from the project default, and keeps the canonical benchmark matrix in JSON for review and future analysis.
v1.3.0 is a breaking MINOR: the core is hash-agnostic (cas.Hash → cas.Digest + a client-injected cas.Hasher), gitlike.NewRepository takes a gitlike.Codecs set, object invariants moved to cas.Validator, and the filesystem layout lost its algorithm directory. Read the [v1.3.0] section of CHANGELOG.md and docs/specs/operations.md §5 before pointing this build at an existing store — objects written by v1.2.0 are not migrated.
import (
fs "github.com/dmundt/go-cask/cas/backend/fs" // or use the mem backend
"github.com/dmundt/go-cask/cas"
jsoncodec "github.com/dmundt/go-cask/cas/codec/json"
sha256 "github.com/dmundt/go-cask/cas/hash/sha256"
"github.com/dmundt/go-cask/gitlike"
)
raw, _ := fs.New("./objects") // backend
// typed layer: the client supplies both the hasher and the codecs, so the
// repository names neither the algorithm nor the wire format.
repo := gitlike.NewRepository(raw, sha256.New(), gitlike.Codecs{
Blob: jsoncodec.New[*gitlike.Blob](),
Tree: jsoncodec.New[*gitlike.Tree](),
Commit: jsoncodec.New[*gitlike.Commit](),
Tag: jsoncodec.New[*gitlike.Tag](),
})
d, _ := repo.Blobs.Put(ctx, andgitlike.Blob{Data: []byte("hello")})
blob, _ := repo.Blobs.Get(ctx, d) // *gitlike.Blob
For tests/ephemeral use, swap the backend:
mem "github.com/dmundt/go-cask/cas/backend/mem" // declares package memory
raw := mem.New() // fast, deterministic, not persistent
docs/specs/ is the complete design contract: core architecture, coding guidelines, library design, performance, testing, consistency (GC/pruning), viewer HTTP surface, viewer design and security, versioning, defaults, examples, and extensions.
Note: the documentation tree under docs/ follows the OKF frontmatter layout (type, title, description, version for each document, with docs/index.md as the top-level rule index).
Key references:
Use docs/index.md to find the matching spec for a change area.
go build ./...
go vet ./...
go test -race ./...
gofmt -l .
Requires Go 1.27 (toolchain self-managing; library baseline Go 1.24+, needed for the omitzero JSON tags used by cas.Digest reference fields). See CONTRIBUTING.md for the workflow, and benchmarks/README.md for running/reading the benchmarks.
MIT — see LICENSE. Copyright (c) 2026 Daniel Mundt.