Design

Content in Chronicle is stored by its BLAKE3 hash. This provides:
  • Deduplication: Identical content is stored once, regardless of how many files reference it
  • Integrity: Content is verified on read (hash mismatch = corruption detected)
  • Efficient sync: Only transfer content that the other side doesn’t have

Storage Tiers

┌─────────────────────┐
│   Local CAS         │  Filesystem-backed, fastest
│   (~/.chronicle/cas) │
└──────────┬──────────┘
           │ miss

┌─────────────────────┐
│      S3 CAS         │  Cloud-backed, shared across agents
│   (s3://bucket/cas)  │
└─────────────────────┘

TieredCAS

The TieredCAS combines local and S3 storage:
  • Write: Store locally + async upload to S3
  • Read: Check local first → fetch from S3 on miss → promote to local cache
  • Pooled CAS: Optional shared local cache across agents (~/.chronicle/shared_cas/)

SocketCAS

For sandbox replication, content can be fetched over the replication socket:
  • Sandbox requests content by hash from the agent
  • Agent retrieves from its CAS and sends over the wire
  • Avoids sandbox needing direct S3 access

Chunking

Large files are split into chunks for efficient transfer:
struct ChunkManifest {
    total_size: u64,
    chunk_size: u64,
    chunks: Vec<ChunkInfo>,  // hash + offset + size per chunk
}
When a ContentFetchResponse includes a chunk_manifest:
  • The receiver fetches individual chunks in parallel by their hashes
  • Chunks are reassembled on the receiving side
  • Each chunk is independently content-addressed

Compression

All CAS content is compressed with Zstd before storage:
  • Typical compression ratio: 3-5x for source code
  • Transparent — compression/decompression happens at the CAS layer
  • Both local and S3 storage use compressed content

ContentStorage Trait

#[async_trait]
pub trait ContentStorage: Send + Sync {
    async fn get(&self, hash: &str) -> Result<Option<Vec<u8>>>;
    async fn put(&self, hash: &str, data: &[u8]) -> Result<()>;
    async fn exists(&self, hash: &str) -> Result<bool>;
    async fn delete(&self, hash: &str) -> Result<()>;
}
Implementations: LocalFileCAS, S3CAS, SocketCAS, TieredCAS