NativeLink
Reference

Protocol and API surface

Every gRPC service NativeLink serves, which RPCs are implemented, and the values it advertises.

Who this is for: anyone writing or debugging a client, or checking whether a given REAPI feature is available. What you'll have at the end: the complete service list with implementation status. Time: use as a lookup.

NativeLink implements the Remote Execution API plus the adjacent protocols it depends on (ByteStream, long-running Operations, Remote Asset and the Build Event Protocol), and defines exactly one service of its own. Every vendored .proto under nativelink-proto/ is copied from upstream with only its licence header replaced; there are no NativeLink-specific fields or extensions on the standard messages.

Services

ServiceOriginStatus
ExecutionREAPIImplemented
ActionCacheREAPIImplemented
ContentAddressableStorageREAPIImplemented
CapabilitiesREAPIImplemented
google.bytestream.ByteStreamGoogle APIImplemented
google.longrunning.OperationsGoogle APIPartially implemented, see below
Remote Asset FetchRemote Asset v1Implemented
Remote Asset PushRemote Asset v1Implemented
PublishBuildEventBuild Event ProtocolImplemented, marked experimental
WorkerApiNativeLinkImplemented

Each is registered only if the configuration asks for it. Registration order at startup is fixed: action cache, CAS, execution, Operations, fetch, push, ByteStream, capabilities, worker API, BEP.

Two endpoints are not gRPC

The health endpoint (/status by default) and the admin endpoint (/admin by default; both paths are configurable) are plain HTTP handlers on the same listener. They will not appear in gRPC reflection, and a health check does not need a gRPC client.

WorkerApi: the only NativeLink-defined service

Defined in worker_api.proto. It has exactly one RPC:

rpc ConnectWorker(stream UpdateForScheduler) returns (stream UpdateForWorker);

One bidirectional stream carries a worker's entire relationship with its scheduler: registration, heartbeats, action assignment, progress and completion. No polling RPC and no second connection exist. See worker execution.

events.proto in the same tree declares message types only, no services.

Partially implemented RPCs

Three Operations RPCs are registered and return unimplemented:

RPCStatus
GetOperationImplemented
WaitOperationImplemented
ListOperationsunimplemented
DeleteOperationunimplemented
CancelOperationunimplemented

A client that relies on cancellation to release cluster resources will not get it here. Actions are instead reaped by timeout; see client_action_timeout_s, which kills an action nobody is listening to.

SplitBlob and SpliceBlob are upstream RPCs

Both appear in NativeLink's vendored CAS proto and are sometimes mistaken for NativeLink inventions. They are part of the upstream REAPI definition (content-defined chunking), vendored along with everything else. NativeLink serves them only for CAS instances that configure experimental_chunking (or proxy to a grpc store that does); elsewhere the capabilities response reports them unsupported and the RPCs return Unimplemented.

split_blob

What Capabilities advertises

FieldValue
Supported API versions2.0.0 to 2.3.0
Digest functionsSHA256, BLAKE3
max_batch_total_size_bytes65536 (64 KiB)
max_cas_blob_size_bytes0 (no limit advertised)
symlink_absolute_path_strategyDISALLOWED
update_enabled (action cache)true
supported_compressorsZSTD when the instance's capabilities entry sets remote_cache_compression: true; empty otherwise
split_blob_support, splice_blob_support, fast_cdc_2020_paramsset when the instance's cas entry configures experimental_chunking; otherwise false/unset
execution_capabilitiespresent only when the instance's capabilities entry has remote_execution; then exec_enabled is true and the priority range is 0 to i32::MAX
get_capabilities

Two of these need a caveat.

exec_enabled is hardcoded to true, with a TODO in the source acknowledging it. Whenever a capabilities entry names a remote_execution scheduler, execution is advertised as enabled; there is no way to advertise exec_enabled: false. A cache-only capabilities entry (no remote_execution) omits execution_capabilities altogether, which is the correct signal for a cache-only deployment.

The 64 KiB batch limit is advisory and small relative to what some clients assume. The CAS handlers do not enforce it themselves; the hard stop is the listener's max_decoding_message_size (4 MiB unless configured), and a batch request above that is rejected at the gRPC layer. Clients that honour the advertised limit send anything larger through ByteStream.

Wire-level details worth knowing

ByteStream resource names are parsed right to left. A resource name is {instance_name}/blobs/{hash}/{size}, and the instance name may itself contain slashes, so left-to-right parsing cannot find the boundary, while right-to-left can, because the trailing components are fixed. See ResourceInfo.

GetTree page tokens are "{hash}-{size}", constructed and parsed by splitting on -. They are neither opaque nor signed. The protocol asks clients to treat them as opaque, and clients that do will keep working if the format changes.

The Execute pre-flight input check is shallow and racy by design. It does not walk the full input tree, and a blob can be evicted between the check and the worker's fetch. It exists to turn the common "inputs were never uploaded" mistake into a fast error, not to provide a guarantee. See ExecutionServer.

ActionStage::CacheCheck is never emitted. The cache lookup happens in a decorator in front of the scheduler, so the state is skipped entirely. A client waiting to observe it will wait forever.

Final action failure arrives as success. An action that exhausts its retries returns ActionStage::Completed with ActionResult.error set: a successful RPC describing a failed action. This is what the REAPI specifies. Clients that only inspect the gRPC status will misread it.

server_logs is never populated. The field exists; the worker does not fill it.

On this page