TensorOrigin documentation.
TensorOrigin is an internal TensorPlane Git storage engine: a single daemon that serves Git protocol v2 smart-HTTP over TLS behind capability tokens, with object storage as the authoritative store and local Git directories as disposable caches. It is in Closed beta, it is not a product SKU, it is not billed, it is not a public Git host, and it is not a GitHub replacement.
What TensorOrigin is today.
TensorOrigin is an internal Git storage engine, intended for dogfood use so TensorPlane can exercise the platform end to end. It is literally not a product SKU, not a billed surface, and not a public Git host. It is not a GitHub replacement for the money-path review and publication authority, and it is not tenant identity, authorization, entitlements, audit, billing, or a console — those stay in the Go control plane.
The dogfood serve path is implemented. tensororigin serve exposes the Git v2 smart-HTTP endpoints over TLS behind capability-token auth, backed by the durable-ack engine (ADR 0002 §4) and disposable local caches that rebuild from the object store (ADR 0002 §7). In this build git_protocol_enabled() is true and control_plane_integration_enabled() stays false — the daemon verifies capability tokens and never calls the control plane. This page documents the pinned commit f71931d9; interfaces can still change.
The model to hold in your head.
- org_id and repo_id — a repository is addressed by two opaque UUIDs. The clone path is
/git/<org_id>/<repo_id>.git; both ids are allocated by the admin endpoint and carry no tenant meaning here. - Object storage is authoritative; local caches are disposable. A write is durable only once the required objects and the conditional index publication have committed. The local Git directories under
--cache-dirare caches — complete cache loss still recovers every acknowledged write from the store. - Durable ack (ADR 0002 §4) — a push is acknowledged to the Git client only when all four hold: every named pack has a successful
PutIfNoneMatch(or aHeadproving the same digest exists); the generation documentPutIfNoneMatchsucceeded; the live-index CAS returned 2xx; and a confirmingGetshows the new generation with a matching digest. Local ref updates happen after ack and are not part of it. - Capability tokens — every Git RPC requires a token in the wire form
TO1.<org>.<repo>.<actions>.<expiry>.<hmac_hex>, bound to(org_id, repo_id, actions, expiry). Actions arer,w,c,a(read, write, create, admin). This is distinct from the daemon secret (--token), which signs tokens and gates the admin endpoint.
What you need to build and run.
- Rust 1.98.1, pinned in
rust-toolchain.toml. - Stock git 2.39+ as the client (no libgit2 / JGit / go-git).
- openssl and curl for the dogfood recipe.
- An S3-compatible object store: MinIO for test and CI; an S3-compatible store in production.
- Do not put
CARGO_TARGET_DIRon/tmp(tmpfs OOM); use the repo-localtarget/.
Build and test the binary.
The qualification tests download a static MinIO binary into target/githost-tools (or $CARGO_TARGET_DIR/githost-tools); override the path with GITHOST_MINIO_BIN. Docker is not required. Passing against MinIO does not certify any particular production object store.
tensororigin serve.
The only subcommand is serve. A missing or unknown subcommand prints the usage line and exits 2; a runtime error prints tensororigin: <err> and exits 1. On startup the daemon logs one readiness line to stdout beginning tensororigin: listening on https:// with the bound address. The object store is configured for region us-east-1 with a 60-second request timeout.
| Flag | Required | Default / env | Meaning |
|---|---|---|---|
--listen ADDR | Optional | 127.0.0.1:0 | Address to bind. The default picks an ephemeral loopback port; the chosen port is printed on the readiness line. |
--cert P | Required | — | PEM certificate. TLS is mandatory; there is no plaintext HTTP listener. |
--key P | Required | — | PEM private key for the certificate. |
--token S | Required | — | Daemon HMAC / admin secret. It signs capability tokens and is the credential the admin endpoint checks. |
--cache-dir D | Required | — | Directory for the disposable local Git caches. Safe to wipe: caches rebuild from object storage. |
--s3-endpoint U | Required (or env) | TENSORORIGIN_S3_ENDPOINT | Object-store endpoint URL. Falls back to the env var of the same name. |
--s3-bucket B | Required (or env) | TENSORORIGIN_S3_BUCKET | Bucket that holds the authoritative packs and index. Env fallback of the same name. |
--s3-access-key K | Required (or env) | TENSORORIGIN_S3_ACCESS_KEY | Object-store access key. Env fallback of the same name. |
--s3-secret-key S | Required (or env) | TENSORORIGIN_S3_SECRET_KEY | Object-store secret key. Env fallback of the same name. |
--threads N | Optional | 8 | Worker thread count for the server. |
--token-ttl-secs N | Optional | 3600 | Lifetime, in seconds, of the capability tokens the admin endpoint mints. |
The four object-store values may come from the flags or from their environment variables — TENSORORIGIN_S3_ENDPOINT, TENSORORIGIN_S3_BUCKET, TENSORORIGIN_S3_ACCESS_KEY, and TENSORORIGIN_S3_SECRET_KEY — but one of the two must be present or startup fails. Run the built binary directly:
The dogfood script, end to end.
scripts/dogfood.sh runs the whole loop. It needs openssl, curl, git 2.39+, and either a running S3-compatible store (set TENSORORIGIN_S3_*) or a minio binary on PATH or at $MINIO_BIN.
It generates a self-signed cert, launches the daemon, creates one repository through the admin endpoint, and prints a ready-to-run git clone command. You then commit and push main, clone again into a new directory to see the commit, and wipe the cache to prove the next clone rebuilds from the store. When no TENSORORIGIN_S3_* is set it starts MinIO at http://127.0.0.1:9000 with bucket and access key tensororigin. Everything lands under a /tmp/tensororigin-dogfood.XXXXXX directory that is not cleaned up, so you can inspect it.
POST /admin/repos.
The admin endpoint allocates a repository and mints a read+write token. The presented credential must equal the daemon secret (--token), as a Bearer token or a Basic password; otherwise it returns 401 admin authentication required.
The JSON response carries org_id, repo_id, clone_path (/git/<org_id>/<repo_id>.git), and token — capture the token, it is the capability token for that repository.
Clone, commit, push main.
Clone over HTTPS, passing the capability token as an extra header. The generated cert is self-signed: trust it with http.sslCAInfo, or, for a throwaway local run only, disable verification with http.sslVerify=false — never against a real backend. ABasic credential works too, with the token as the password.
The caches are disposable.
The local Git directories under --cache-dir are disposable. Wipe the cache directory contents and clone again: the daemon reconstructs the repository from object storage (TENSORORIGIN_S3_ENDPOINT and the rest of the TENSORORIGIN_S3_* values). Every acknowledged write survives a complete cache loss.
At the pinned commit f71931d9 there is no fence and no pinned-generation read lifetime. Each smart-HTTP request re-reads the committed generation from the object store (read_committed) and rebuilds the cache directory from that generation’s named packs (ensure_generation) before serving; the cache is never treated as truth. If the object-store read fails, the request surfaces as HTTP 500 git error: … (see the status table) and the client should retry.
ADR 0002 §7 specifies the future design contract: reads that pin a generation, so a read starting after a durable ack of generation G observes at least G — catching lagging replicas up from the store before serving — with a bounded pin lifetime and a retryable service-unavailable response (HTTP 503) when the freshness read fails. That contract is not yet implemented at f71931d9.
Endpoints and status codes.
| Method | Path | Auth | Notes |
|---|---|---|---|
| POST | /admin/repos | Daemon secret | Allocate a repository (new org and repo UUIDs) and mint a read+write token. Localhost dogfood convenience. |
| GET | /git/<org>/<repo>.git/info/refs?service= | Capability token | Ref advertisement. service must be git-upload-pack or git-receive-pack; anything else (including dumb HTTP) is refused. |
| POST | /git/<org>/<repo>.git/git-upload-pack | Read token | Fetch / clone. Requires a token granting Read. |
| POST | /git/<org>/<repo>.git/git-receive-pack | Write token | Push. Requires a token granting Write, and passes the receive-pack admission gate first. |
| Code | When |
|---|---|
400 | bad request body; or git protocol v1 is not supported; use v2 (an explicit Git-Protocol version=0/version=1); or a rejected ref name or pack (Rejected -> 400). |
401 | authentication required on a Git RPC with no or an invalid token; admin authentication required on /admin/repos without the daemon secret. |
403 | smart HTTP git protocol v2 required — info/refs without a known service= (dumb HTTP is refused). |
404 | not found — a path outside /git/, a git-receive-pack (push) to a repository that does not exist (RepoNotFound), or /info/lfs (LFS is not served). |
500 | git error: … — any other engine or object-store failure. A clone / fetch / info-refs of a missing or unreadable repository takes the read path and surfaces here as 500, not 404; create failed: … is returned when /admin/repos cannot allocate a repository. |
503 | receive-pack admission queue full; retry with Retry-After: 1 — the per-repo depth (8) or per-replica ceiling (32) is saturated. Retry; no refs were touched. |
A single pack is capped at 512 MiB (pack exceeds 512 MiB). The receive body ceiling is that plus 16 MiB, but a body over the ceiling is refused up front by the body reader with 400 bad request body — the internal receive body exceeds limit message is not what the client sees. Either overflow is a deterministic rejection, not a partial write.
What the protocol supports and rejects.
The baseline client is stock Git 2.39+ speaking protocol v2 over HTTPS. The matrix below is the ADR 0003 §1 target matrix: the ADR 0003 §1 target column is the planned disposition, and the At f71931d9 column is what the pinned build actually enforces. Only the refusals enforced in code fail deterministically before any effect — protocol v1 (400), dumb HTTP (403), a missing or invalid capability token (401), the partial-clone filter (uploadpack.allowFilter=false), and the absent SSH listener. Rows marked not implemented or not advertised are ADR targets, not behaviour you can rely on at this commit.
| Feature | ADR 0003 §1 target | At f71931d9 |
|---|---|---|
| HTTPS smart HTTP + TLS, Git protocol v2 | Support | Enforced — v2 required; a v1 request is refused 400 |
| SHA-1 clone / fetch / push | Support | Enforced over HTTPS + v2 |
| Atomic multi-ref push, report-status / report-status-v2 | Support | Enforced — all-or-nothing receive |
| ofs-delta / thin-pack on receive | Support (with fsck) | Enforced — receive.fsckObjects / transfer.fsckObjects = true |
| Partial clone / filter | Reject | Refused — uploadpack.allowFilter = false (sealed) |
| Git protocol v1, git:// and dumb HTTP | Reject | Refused — 400 (v1) / 403 (dumb HTTP) |
| SSH transport | Reject | No SSH listener; the daemon binds HTTPS only |
| Anonymous access | Reject | Refused — every RPC requires a capability token |
| Git LFS (/info/lfs) | Reject | /info/lfs returns 404 |
| Server-side hooks | Reject (never execute) | Sealed config; hooks stored as blobs only, never run |
| SHA-256 object format | Reject | Not implemented / not advertised (ADR 0003 target: reject) |
| Shallow push | Reject | Not implemented / not advertised (ADR 0003 target: reject) |
| bundle-URI | Reject | Not advertised (ADR 0003 target: reject) |
| Export (git bundle / archive via authorized API) | Support (future, tensororigin#4) | No export route — not available |
| Host import / mirror from another Git host | Reject | Not implemented (no import path) |
Ref names are constrained (ADR 0003 §4). Allowed by default: refs/heads/*, refs/tags/*, and symbolic HEAD. Rejected: refs/replace/*, refs/pull/*, names containing .., control characters, a leading or trailing /, a .lock suffix, the sequence @{, or a path component .git; the maximum ref name is 255 bytes of UTF-8.
Common errors.
- TLS / self-signed cert errors on clone — trust the cert with
-c http.sslCAInfo=<cert.pem>, or for a throwaway local run only,-c http.sslVerify=false. Never disable verification against a real backend. 401 authentication required— the Git RPC had no token or an invalid one;401 admin authentication required— the daemon secret did not match on/admin/repos.403 smart HTTP git protocol v2 required— the request hitinfo/refswithout a knownservice=(dumb HTTP is not served).400 git protocol v1 is not supported; use v2— a client asked forGit-Protocol: version=0orversion=1. Use a stock Git 2.39+ client.503 receive-pack admission queue full; retry— honorRetry-After: 1and retry; the per-repo depth (8) or per-replica ceiling (32) was saturated. No refs were touched.- A
ghp_/ghs_or other GitHub-shaped credential is rejected before any HMAC work — mint aTO1.token from the admin endpoint instead. - Wrong-repo or expired token — the token is bound to
(org_id, repo_id, actions, expiry); a token for another repository, or one past its TTL, is rejected. - Pack too large — a single pack over 512 MiB is rejected; split the push.
- Cache directory wiped — expected and safe; the next clone rebuilds from object storage.
What this build does not do.
This dogfood scope is HTTPS + v2 only. The following are not implemented here:
- SSH transport — SSH is not served; no sshd listens.
- Git protocol v1,
git://, and dumb HTTP. - Git LFS (
/info/lfsreturns 404), partial clone / filter, and the SHA-256 object format. - Replicas, compaction, garbage collection, and restore.
- Export API — there is no
git bundle/ archive endpoint; export is an ADR 0003 target (tensororigin#4), not a route here. - Repository import or migration from another Git host.
- Control-plane APIs — identity, entitlements, audit, and billing stay in the control plane.
- Non-stock clients (libgit2, JGit, go-git) until they pass the HTTPS + v2 fixtures.
How to get into the Closed beta.
TensorOrigin is invite-only in the Closed beta. Request early access, or contact us; the TensorPlane team provides build instructions and a pinned commit reference to Closed beta participants.
How TensorOrigin is priced.
TensorOrigin is not a product SKU and is not billed. The Git storage engine and its capability tokens carry no price. For the products that are billed, see billing.
Get early access to the platform.
Every product is included in one platform subscription. Request early access and we'll onboard your team hands-on — free while we build toward launch.