Browse by type

This is a beta release of ArtifactFS. Your mileage may vary.
ArtifactFS is a Git-backed filesystem daemon (FUSE driver) in Go that mounts repositories as normal working trees while avoiding eager blob downloads.
It exposes the tree quickly, then hydrates file contents on demand. That makes it useful for sandboxes, agents, and other short-lived environments where waiting for a full clone is too expensive.
In practice:
Cloudflare Artifacts is a versioned filesystem that speaks git. It is built for agent toolchains, sandboxes, and CI/CD systems that need fast access to code repositories.
ArtifactFS is the optional FUSE driver -- it lets you mount an Artifact (or any git repo) as a local filesystem without waiting for a full clone.
Requires Go 1.26+ and a FUSE implementation:
fuse3 (apt install fuse3 on Debian/Ubuntu, dnf install fuse3 on Fedora)Install the CLI from the module:
go install github.com/cloudflare/artifact-fs/cmd/artifact-fs@latest
Or build it directly from the module path:
go build -o artifact-fs github.com/cloudflare/artifact-fs/cmd/artifact-fs
Quick start against a public repo:
export ARTIFACT_FS_ROOT=/tmp/artifact-fs-test
# Register, clone, and build the initial snapshot
./artifact-fs add-repo \
--name workers-sdk \
--remote https://github.com/cloudflare/workers-sdk.git \
--ref refs/heads/main \
--mount-root /tmp
# Start the daemon (mounts via FUSE, blocks until killed)
./artifact-fs daemon --root /tmp &
DAEMON_PID=$!
# Use the repo
ls /tmp/workers-sdk/
cat /tmp/workers-sdk/README.md
git -C /tmp/workers-sdk log --oneline -5
# Cleanup
kill $DAEMON_PID
Check the state of a mounted repo with status:
./artifact-fs status --name workers-sdk
# repo=workers-sdk state=mounted head=d4c61587... ref=main source_ref=refs/heads/main required_commit=none acquisition=not_required base_commit=d4c61587... remote_refresh=enabled ahead=0 behind=0 diverged=false last_fetch=2026-03-27T12:00:00Z result=ok prepare_error=none hydrated_blobs=42 hydrated_bytes=131072 overlay_dirty=false
| Field | Meaning |
|---|---|
state |
mounted, unmounted, preparing, or failed |
head / ref |
Backward-compatible aliases for the current base commit and Git HEAD ref |
source_ref |
Canonical remote ref selected during acquisition |
required_commit |
Required source commit, or none |
acquisition |
Historical acquisition evidence: not_required, pending, or verified |
base_commit |
Commit backing the currently published filesystem generation |
remote_refresh |
Whether daemon and manual remote refreshes are enabled |
ahead / behind / diverged |
Currently zero/false in one-shot CLI status output |
prepare_error |
Last redacted preparation error, if any |
hydrated_blobs / hydrated_bytes |
Blob count and bytes present in the local hydration cache |
overlay_dirty |
true if the overlay contains created or modified files; delete-only overlays are not counted |
last_fetch / result |
FETCH_HEAD modification time and ok when present; otherwise never |
Hydration (blob downloading) is transparent: the file tree is visible immediately after mount, and reads block only until the requested blob is fetched. The daemon prioritizes code and manifests (package.json, go.mod, README.md) over binary files.
Use --hydration-concurrency to control the number of parallel blob-fetch workers (default 4). Each worker maintains a persistent git cat-file --batch process, so higher values trade memory for faster bulk hydration:
./artifact-fs daemon --root /tmp --hydration-concurrency 8
ArtifactFS emits newline-delimited JSON to stderr. Preparation logs include the mode, source, attempt, phase, state, duration, and deadline. Clone and fetch operations retry known transient transport failures up to three total attempts. Preparation has a 30-minute timeout. Caller cancellation stops the active Git command and retry backoff; synchronous preparation records a redacted prepare canceled status, while daemon shutdown leaves async preparation queued for restart.
Async existing-clone preparation reports remote configuration, fetch, and branch update as separate configure_remote, fetch, and update_branch phases.
Successful add-repo:
{"time":"2026-07-16T12:00:00Z","level":"INFO","msg":"repo preparation started","repo":"workers-sdk","mode":"sync","source":"fresh_clone","attempt":1,"phase":"validate","state":"started","duration_ms":0,"branch":"refs/heads/main","fetch_ref":"main","deadline_set":true,"timeout_ms":1799999}
{"time":"2026-07-16T12:00:04Z","level":"INFO","msg":"repo preparation completed","repo":"workers-sdk","mode":"sync","source":"fresh_clone","attempt":1,"phase":"complete","state":"completed","duration_ms":4217,"deadline_set":true,"timeout_ms":1799999,"head_oid":"d4c61587...","head_ref":"main","snapshot_generation":1}
Transient network failure followed by recovery:
{"time":"2026-07-16T12:01:00Z","level":"WARN","msg":"git operation attempt failed","operation":"clone","repo":"workers-sdk","attempt":1,"max_attempts":3,"retryable":true,"duration_ms":842,"timed_out":false,"canceled":false,"error":"HTTP 503: unexpected disconnect"}
{"time":"2026-07-16T12:01:00Z","level":"INFO","msg":"retrying transient git operation failure","operation":"clone","repo":"workers-sdk","attempt":1,"next_attempt":2,"backoff_ms":214}
{"time":"2026-07-16T12:01:02Z","level":"INFO","msg":"git operation recovered","operation":"clone","repo":"workers-sdk","attempts":2,"duration_ms":2087}
Preparation timeout:
{"time":"2026-07-16T12:30:00Z","level":"ERROR","msg":"repo preparation failed","repo":"workers-sdk","mode":"sync","source":"fresh_clone","attempt":1,"phase":"clone","state":"failed","duration_ms":1800000,"deadline_set":true,"timeout_ms":1799999,"timed_out":true,"canceled":false,"error":"git clone failed after 1 attempt; caller context: context deadline exceeded"}
Diagnostics are bounded and redact credentials and complete remote references. To follow preparation and network activity:
./artifact-fs daemon --root /tmp 2>/tmp/daemon.log &
tail -f /tmp/daemon.log | grep -Ei 'prepar|git operation'
By default, add-repo waits for the blobless clone and initial snapshot before returning. Use --async when the daemon should prepare the repo in the background:
./artifact-fs add-repo \
--name workers-sdk \
--remote https://github.com/cloudflare/workers-sdk.git \
--ref refs/heads/main \
--mount-root /tmp \
--async
The daemon mounts a placeholder immediately. Operations inside that repo mount, such as ls, less, or git -C /tmp/workers-sdk status, wait until the clone/fetch and snapshot publish have completed. If preparation fails, those operations return an I/O error until preparation is retried:
./artifact-fs status --name workers-sdk
./artifact-fs prepare --name workers-sdk
Async HTTPS remotes must use ambient credentials, such as a configured Git credential helper or repo-local Git config. Inline credentials in the remote URL are rejected for async repositories.
For workflows that create the gitdir separately, --prepared-gitdir makes the async step fetch and prepare an existing gitdir instead of running git clone:
git init --separate-git-dir /tmp/workers-sdk.git --initial-branch main /tmp/workers-sdk
git -C /tmp/workers-sdk remote add origin https://github.com/cloudflare/workers-sdk.git
./artifact-fs add-repo \
--name workers-sdk \
--ref refs/heads/main \
--mount-root /tmp \
--async \
--prepared-gitdir \
--git-dir /tmp/workers-sdk.git \
--fetch-ref main
Use a verified source when a job must inspect the exact revision selected for a deployment:
artifact-fs add-repo \
--name workers-sdk-check \
--remote https://github.com/cloudflare/workers-sdk.git \
--ref refs/heads/main \
--require-commit "$DEPLOY_SHA" \
--depth 1 \
--refresh never \
--mount-root /tmp
These options express three independent policies: --require-commit asserts what the canonical source ref must resolve to, --depth bounds transferred history, and --refresh never disables daemon and manual remote refreshes. The required commit must be a full 40- or 64-character object ID. If the fetched ref resolves to a different commit, preparation fails before any filesystem generation is published.
ArtifactFS fetches the canonical ref into a private candidate ref, verifies its peeled commit, and publishes directly from that commit rather than ambient HEAD. A successful acquisition receipt is persisted and reported as acquisition=verified. Verified acquisition is historical evidence, not a continuously re-evaluated boolean.
A required source commit fixes the published base generation: ArtifactFS does not start its HEAD watcher for that repository, so later local Git ref changes are not adopted by the mount. The mounted filesystem remains writable through the overlay, and blob hydration may still contact the promisor remote. This is therefore a verified source, not an immutable filesystem.
The remote must advertise Git partial-clone filtering for file contents to hydrate over the network on demand. If it does not, Git downloads the selected revision's blobs eagerly, but depth 1 still prevents historical commits and obsolete blob versions from being transferred.
--prepared-gitdir is not supported with --require-commit because verified acquisition atomically installs a private Git directory.
See the generic container example for Docker-compatible runtimes or the Cloudflare Sandbox SDK example for Workers and Containers.
ArtifactFS has two distinct phases: a one-shot setup (add-repo) that registers and usually prepares a fast blobless clone, and a long-running daemon that mounts it via FUSE and serves file operations. With add-repo --async, setup only registers the repo; the daemon performs clone/fetch and snapshot publishing while FUSE operations wait behind a readiness gate.
``` ┌─────────────────────────────────────────────────┐ │ Daemon │ │ │ ┌──────────┐ clone │ ┌──────────┐ ls-tree ┌──────────────┐ │ │ Remote │◄──────────┼──│ GitStore │────────────────►│ Snapshot │ │ │ repo │ fetch │ │ │ cat-file │ (SQLite) │ │ └──────────┘ │ │ batch │ --batch-check │ │ │ │ │ pool │ │ base_nodes │ │ │ └────┬─────┘ │ per gen │ │ │ │ cat-file └──────┬───────┘ │ │ │ --batch │ │ │ ▼ ▼ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ Blob │ │ Resolver │ │ │ │ Cache │ │ │ │ │ │ (disk) │◄────hydrate─────│ snap + ovl │ │ │ └──────────┘ │ merged view │ │ │ ▲ └──────┬───────┘ │ │ │ │ │ │ ┌────┴─────┐ prefetch ┌─────┴────────┐ │ │ │ Hydrator │◄─────────────────│ Engine │ │ │ │ │ │ │ │ │ │ priority │ ensureOverlay │ read / write │ │ │ │ queue │ copy-on-write │ create / rm │ │ │ └──────────┘ └─────┬────────┘ │ │ │ │ │ ┌──────────┐ ┌──────┴───────┐ │ │ │ Overlay │◄────────────────│ FUSE Layer │ │ │ │ (SQLite │ write ops │ (macFUSE / │ │ │ │ + upper │ │ /dev/fuse) │ │ │ │ dir) │ └──────┬───────┘ │ │ └──────────┘ │ │ │ │ │ │ ┌──────────┐ HEAD poll ┌─────┴─────
browse all types & interfaces →
$ claude mcp add artifact-fs \
-- python -m otcore.mcp_server <graph>