hammerkit
Architecture decisions

Local cache with an explicit remote bridge (no read-through tier)

A hammerkit cache has a single backend, and a build only ever reads/writes the local cache. To split network from compute for distributed/CI caching, we do not introduce a read-through two-tier cache. Instead, tasks keep caching against a local backend, and two new commands — hammerkit cache pull --remote <name> and hammerkit cache push --remote <name> — are the only operations that touch a remote backend (S3, registry). Pull syncs remote→local for the in-scope tasks' current state keys; push syncs local→remote. The build itself never performs remote I/O, so a CI pipeline can run a network-bound cache pull job and a compute-bound build job separately.

The remote is declared as a normal entry in the caches: block and selected by the --remote flag, rather than referenced by tasks or expressed as a remote: field on a cache.

Considered options

  • Read-through two-tier cache (local mirror in front of a remote origin, reads fall through) — rejected as a speculative new abstraction; violates "add nothing speculative" and "simplicity & composability".
  • Pre-restore only (run the existing restore phase early against the configured backend) — rejected because if that backend is remote, the build still performs has() network checks, so it does not actually move network off the build's critical path.

Consequences

  • A build file now distinguishes a local working cache from a remote backend; both are entries in caches:.
  • service-state-snapshot's "machine A seeds, machine B restores" story is just another entry the bridge moves — no extra machinery.

On this page