TL;DR: besides the JSON API on api.{org}.code.storage, the backend must serve
standard git smart HTTP on the storage host {org}.code.storage, so plain
git clone/push/fetch/pull work.
https://t:<jwt>@{org}.code.storage/{repo_id}.git # persistent namespace
https://t:<jwt>@{org}.code.storage/{repo_id}+ephemeral.git # ephemeral namespace
https://t:<jwt>@{org}.code.storage/{repo_id}+import.git # import namespace
- Basic auth: the username is the fixed literal
t; the password is the JWT. - JWT requirements match the HTTP API: the
repoclaim must match the repo;git:readfor fetch/clone,git:writefor push;refs/opspolicies enforced per ref during receive-pack.
GET /{repo}.git/info/refs?service=git-upload-pack # advertise refs (fetch/clone)
POST /{repo}.git/git-upload-pack # pack negotiation + packfile
GET /{repo}.git/info/refs?service=git-receive-pack # advertise refs (push)
POST /{repo}.git/git-receive-pack # receive pack, update refs
These are standard git paths; the SDKs only build the base remote URL and hand it to
git. Serving via git http-backend or a git library (go-git, libgit2,
gitoxide, JGit) against the repo storage is sufficient. The dumb protocol is not
required.
The receive path must:
- Enforce JWT ref policies per ref update (
no-push,no-force-push,verify-sig), first match wins, reporting per-refngresults with a policy message. - Map namespaces:
+ephemeralremotes see and update only the ephemeral ref space; persistent remotes must not see ephemeral refs (git namespaces or separate ref stores). - On pushes to persistent refs, emit
pushwebhooks (before/after SHAs per ref) and schedule upstream sync for synced repos. - Accept large histories on
+importpushes. Official docs describe immediate cold archival; for an OSS backend, "accept the objects, keep refs" is a functional equivalent (tiering optional).
The storage host must also expose the LFS Batch API at the standard discovery path:
POST https://{org}.code.storage/{repo_id}.git/info/lfs/objects/batch
Same JWT basic-auth remote; no separate LFS server or config. Implementing the batch API plus object upload/download (e.g. via S3-presigned or local storage) covers the documented behavior ("no separate LFS server, no extra configuration").
Objects and refs written through the HTTP API (commit-pack, merge, tags, notes) and
through git push must land in the same object database and ref store. The consumer
freely mixes git clone with API-created commits, and integration tests poll
GET /repos/branches right after pushes.
- Notes refs (
refs/notes/*) and tags are fetchable and pushable via standard git refspecs (e.g.git fetch origin 'refs/notes/*:refs/notes/*'), so the smart-HTTP layer must not filter them. - The API's branch listing shows
created_atper branch, so the backend needs per-ref creation metadata beyond what bare git stores (reflog or DB column).