Skip to content

remote-cache: add file:// backend for sharing compiled state between worktrees - #616

Merged
oyvindberg merged 1 commit into
masterfrom
remote-cache-local-dir
Jul 25, 2026
Merged

remote-cache: add file:// backend for sharing compiled state between worktrees#616
oyvindberg merged 1 commit into
masterfrom
remote-cache-local-dir

Conversation

@oyvindberg

Copy link
Copy Markdown
Owner

What

Adds a local-directory backend to the build cache: remote-cache: { uri: file:///path/to/cache } in bleep.yaml now stores entries as plain files instead of requiring an S3-compatible service and credentials.

Why

Sharing compiled state between git worktrees on one machine is the motivating case: cache keys are content digests and the shipped zinc analysis is path-portable, so a fresh worktree can bleep remote-cache pull and skip compiling everything a sibling checkout already built. Until now the cache could only talk to S3-compatible HTTP endpoints, with credentials required unconditionally.

How

  • Push/pull logic was already backend-agnostic; the backend surface is exactly three operations. Extracted as CacheStore (headObject/getObject/putObject), implemented by the existing S3Client and a new LocalDirStore.
  • LocalDirStore maps keys to files under a root directory. Puts are atomic (temp file in target dir + ATOMIC_MOVE), so concurrent pushes of the same digest from different worktrees are safe. Keys are validated against escaping the root.
  • Scheme dispatch in RemoteCache: file:// skips credential resolution entirely; every other scheme keeps the existing S3 path with its fail-hard credential requirement.
  • Docs: local-directory section in the build cache page with the worktree workflow.

Testing

New LocalDirCacheIT deliberately runs with the harness default config — no remoteCacheCredentials — proving the local backend never asks for them. Covers push layout (<project>/<digest>.tar.gz, no leftover temp files), noop-manifest exclusion from the archive, skip on second push, and pull restoring classes + analysis + regenerating the manifest. Existing RemoteCacheIT (S3 path) still passes.

🤖 Generated with Claude Code

…worktrees

The build cache only spoke the S3 wire protocol: s3:// went to AWS and any
other uri was treated as an S3-compatible HTTP endpoint, with credentials
required unconditionally. Pointing the cache at a local directory - the
natural setup for sharing compiled state between git worktrees on one
machine - was impossible.

Push/pull logic was already backend-agnostic (content-digest keys, portable
zinc analysis, noop-manifest regeneration on pull), so the backend surface
is three operations. Extract that as CacheStore (headObject/getObject/
putObject), implemented by the existing S3Client and a new LocalDirStore
that maps keys to files under a root directory. Writes are atomic
(temp file + ATOMIC_MOVE) so concurrent pushes of the same digest from
different worktrees are safe, and keys are checked against escaping the
root. file:// uris skip credential resolution entirely; everything else
keeps the existing fail-hard requirement.

The new integration test deliberately runs with the harness default config
- no remoteCacheCredentials - proving the local backend never asks for
them, and covers push layout, noop-manifest exclusion, skip-on-second-push,
and pull restoring classes + analysis + regenerated manifest.

Co-Authored-By: Claude Fable 5 <[email protected]>
@oyvindberg
oyvindberg merged commit 188821c into master Jul 25, 2026
10 checks passed
@oyvindberg
oyvindberg deleted the remote-cache-local-dir branch July 25, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant