Fork channel

Create a new channel as a copy of main.

Rename channel

Rename main to:

Delete channel

Delete main? This cannot be undone.

mode name
drwxr-xr-x proto/
drwxr-xr-x test/
-rw-r--r-- .googleapis-sha
-rw-r--r-- .remote-apis-sha
-rw-r--r-- ARCHITECTURE.md
-rw-r--r-- HANDOFF.md
-rw-r--r-- README.md
README

Elpe ↔ Bazel Remote Execution API (REAPI)

Elpe exposes its content-addressed store to Bazel/Buck2 via the standard Remote Execution API. This lets any REAPI client use Elpe as a --remote_cache (and, later, --remote_executor), which is how we get a fine-grained “one action = one derivation” build graph for free — without writing a per-build-system extractor.

Elpe’s own OCaml frontend keeps talking to the elpe.Elpe gRPC service; Bazel talks to the REAPI services. Two frontends, one backend.

Digest function: BLAKE3

Elpe’s store is BLAKE3-addressed, so the REAPI digest of a blob is simply blake3(content). GetCapabilities advertises only BLAKE3 (DigestFunction.Value.BLAKE3 = 9). Clients must be told to match: bazel build --digest_function=BLAKE3. This is the single most important interop point — a mismatch makes every digest wrong.

Vendored protos

The canonical .proto files live under proto/, fetched at pinned commits for reproducibility:

  • remote-apis.remote-apis-sha
  • googleapis.googleapis-sha

build.rs compiles remote_execution.proto + bytestream.proto; protoc pulls in the transitive imports from the same include root.

Status

Milestone 1 — remote cache: DONE, validated end-to-end against real Bazel 7.6.0 (2026-08-03). A bazel build --remote_cache=grpc://… --digest_function=blake3 uploads on the cold run, and a run with a fresh local output base reports 1 remote cache hit — Bazel fetched the action result + output blob from Elpe over gRPC in BLAKE3. Reproduce with reapi/test/run.sh.

ServiceMethodsState
CapabilitiesGetCapabilities✅ advertises BLAKE3
ContentAddressableStorageFindMissingBlobs, BatchUpdate/ReadBlobs
ContentAddressableStorageGetTree, Split/SpliceBlob⛔ unimplemented (not needed for caching)
ByteStreamRead, Write, QueryWriteStatus
ActionCacheGet/UpdateActionResult

CAS blobs live at {store}/reapi/cas/{hex-blake3}; cached action results at {store}/reapi/ac/{action-hash}_{size}. The CAS verifies every uploaded blob against its claimed digest — it never trusts the client.

Milestone 2 — remote executor (not started): the Execution service, which stages an Action’s input-root Merkle tree from CAS into Elpe’s existing clone3/chroot sandbox (src/container.rs) and captures outputs as an ActionResult.

Running

Unit tests (no network, real in-process gRPC, proves the BLAKE3 round-trip):

cargo test --lib reapi::

Standalone unprivileged cache server (no root, no PGP, no Ubuntu index):

cargo run --bin elpe-reapi -- --store /path/to/store --addr 127.0.0.1:50051

Full end-to-end against a real Bazel client (installs nothing; needs bazel/bazelisk on PATH):

reapi/test/run.sh