Git LFS (standard)
CAVS Node implements the Git LFS batch API with the standard basic transfer
adapter. Point lfs.url at a repository and stock git-lfs works — no CAVS
binaries, no plugins, nothing to install beyond what you already have.
-
Get the LFS URL. From the repository’s Connect tab, or:
Terminal window curl -sS "https://cavsnode.com/api/v1/repositories/$REPO/connect" \-H "Authorization: Bearer $CAVS_TOKEN" | jq -r .lfs_urlIt looks like
https://cavsnode.com/api/v1/repositories/<uuid>/lfs. -
Configure the repository.
Terminal window git lfs install --localgit config lfs.url "https://cavsnode.com/api/v1/repositories/$REPO/lfs" -
Provide a credential.
Terminal window git config credential.helper store# On the first transfer: any username, your CAVS token as the password.Terminal window git config --add http.https://cavsnode.com/.extraHeader \"Authorization: Bearer $CAVS_TOKEN"Scoping it to the CAVS origin matters — an unscoped
http.extraHeaderwould send your CAVS token to your Git host too. -
Track and push.
Terminal window git lfs track "*.safetensors"git add .gitattributes model.safetensorsgit commit -m "Add model"git push
What happens on the wire
Section titled “What happens on the wire”Git LFS asks CAVS to authorize a batch, then transfers directly to object storage.
POST /api/v1/repositories/{repoID}/lfs/objects/batchAuthorization: Bearer cavs_pat_…Accept: application/vnd.git-lfs+jsonContent-Type: application/json
{ "operation": "upload", "transfers": ["basic"], "objects": [{ "oid": "9f2c8b0e…", "size": 104857600 }]}{ "transfer": "basic", "objects": [ { "oid": "9f2c8b0e…", "size": 104857600, "actions": { "upload": { "href": "https://<object-storage>/…?X-Amz-Signature=…", "expires_at": "2026-07-28T12:15:00Z" }, "verify": { "href": "https://cavsnode.com/api/v1/repositories/{repoID}/lfs/verify" } } } ]}Then git-lfs PUTs the bytes to href — the API never sees them.
Downloads are the same call with "operation": "download", returning a presigned
download action per object, and {"error": {"code": 404}} for objects the
repository doesn’t have.
Cloning
Section titled “Cloning”git clone <your-git-url>cd <repo>git lfs install --localgit config lfs.url "https://cavsnode.com/api/v1/repositories/$REPO/lfs"git lfs pullIf the clone tried and failed to fetch LFS objects before CAVS was configured, skip the smudge filter and fetch afterwards:
GIT_LFS_SKIP_SMUDGE=1 git clone <your-git-url>Fetch only what you need
Section titled “Fetch only what you need”git lfs pull --include="checkpoints/current/**"git lfs pull --include="*.safetensors" --exclude="archive/**"
# Or persist itgit config lfs.fetchinclude "checkpoints/current/**"git config lfs.fetchexclude "archive/**"What you get, and what you don’t
Section titled “What you get, and what you don’t”Standard git-lfs |
With the CAVS agent | |
|---|---|---|
| Works with no extra software | ✓ | |
| Presigned direct-to-storage transfer | ✓ | ✓ |
| Identical files stored once | ✓ | ✓ |
| Chunk-level dedup across versions | ✓ | |
| Range-resumed partial fetches | ✓ | |
| Per-object physical size + chunk counts | ✓ | |
| Measured transfer benchmarks | ✓ | |
| Local chunk cache reused across pulls | ✓ |
Concretely: with standard LFS, changing 3 MiB inside a 22 MiB file stores and transfers 22 MiB again. The dashboard will show a dedup ratio near zero and an empty Benchmarks tab — that’s expected on this path, not a fault.
- uses: actions/checkout@v4 with: lfs: false # fetch LFS after CAVS is configured
- name: Configure CAVS as the LFS backend run: | git lfs install --local git config lfs.url "https://cavsnode.com/api/v1/repositories/${{ vars.CAVS_REPO_ID }}/lfs" git config --add http.https://cavsnode.com/.extraHeader \ "Authorization: Bearer ${{ secrets.CAVS_TOKEN }}"
- name: Fetch large files run: git lfs pull --include="models/**"More platforms in CI/CD recipes.
Migrating existing history
Section titled “Migrating existing history”git lfs track only affects future commits. To move files already in history:
git lfs migrate import --include="*.safetensors" --everythinggit push --force-with-leaseMoving to the CAVS agent
Section titled “Moving to the CAVS agent”No migration, no re-push of existing objects:
# Install the agent (comes with the CLI installer)curl -fsSL https://raw.githubusercontent.com/orelvis15/cavs-hub-cli/main/install.sh | sh
# Wire it into this repositorycav install-lfsFrom then on, new pushes are chunked and deduplicated. Objects already stored the old way stay readable — they’re addressed by the same oid. See CAVS LFS agent.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause |
|---|---|
401 on transfer |
No credential for lfs.url. Set the helper or extraHeader. |
403 on push |
The token lacks repo:write, or your role lacks push. |
404 on an object |
It isn’t in this repository. Check you’re pointing at the right lfs.url. |
| Expired URL mid-transfer | Presigned URLs last 15 minutes. git-lfs re-requests; if a single object can’t finish in 15 minutes, use the CAVS agent, which fetches in ranges. |
smudge filter lfs failed on clone |
LFS ran before CAVS was configured. Re-clone with GIT_LFS_SKIP_SMUDGE=1. |
| Dedup ratio is ~0 | Expected on this path. Use the agent. |
More in Troubleshooting.
- CAVS LFS agent — the same repository, with chunk dedup.
- Git LFS endpoints — the API reference.
- Connect a Git repository — the guided path.

