// Author: Simon-Pierre Boucher — contact@spboucher.ai #pragma once #include "core/autograd.h" #include "core/tensor.h" #include #include #include #include #include // .forge — Forge's home-made, Apple-native, git-style weight format. // // A .forge is a DIRECTORY (a model repository): // // model.forge/ // manifest-latest.json <- HEAD: copy of the newest manifest // manifests/manifest-000042.json <- one "commit" per save(): step, tag, // parent, config, tensor index // objects/<16-hex>.fshard <- immutable content-addressed shards // // Three properties make it worth existing next to .pt/safetensors/gguf: // // 1. APPLE-NATIVE ZERO-COPY. Every tensor is aligned to the Apple Silicon // 16 KB page inside its shard, and shards are padded to page multiples, // so loading is mmap + newBuffer(bytesNoCopy): the file-cache pages ARE // the GPU memory (MTLStorageModeShared unified memory). No parse, no // memcpy — a multi-GB model "loads" in milliseconds. // // 2. GIT-STYLE DELTA SAVES. Tensors are content-addressed (FNV-1a 64). // save() rewrites only tensors whose bytes changed since the parent // manifest; unchanged ones are referenced in place. Manifests are tiny // JSON commits with a parent link, so a repo carries its whole history. // // 3. GITHUB-FRIENDLY SHARDING. New tensors are packed into shard files // capped at shard_mb (default 95 MB — under GitHub's 100 MB limit), so // a repo can be pushed as-is. // // dtypes: f32 (zero-copy alias at load) · f16 / bf16 (half size on disk, // converted to f32 at load until the mixed-precision kernels land). namespace forge::fmodel { struct SaveOptions { DType dtype = DType::F32; // f32 | f16 | bf16 storage int64_t shard_mb = 95; // shard cap; a bigger single tensor gets its own std::string tag; // optional human label for the manifest int64_t step = -1; // training step recorded in the manifest }; // Snapshot the (deduped) parameters into repo_dir, creating it if needed. // Returns the manifest path. Repeated saves write only changed tensors. std::string save(const std::string& repo_dir, const std::string& config_json, const std::vector>& named_params, const SaveOptions& opts); // Zero-copy reader for one manifest. class Snapshot { public: // path: a .forge directory (opens manifest-latest.json) or an explicit // manifest .json inside one. Dies with a message on malformed repos. static Snapshot open(const std::string& path); const std::string& config_json() const; int64_t step() const; std::vector names() const; bool has(const std::string& name) const; const std::vector& shape(const std::string& name) const; // f32 tensors alias the mmapped shard (READ-ONLY by contract: they feed // forward passes, never optimizer updates). Other dtypes convert into a // fresh f32 tensor. Tensor tensor_f32(const std::string& name) const; private: struct Impl; std::shared_ptr impl_; }; } // namespace forge::fmodel