You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by gi...@apache.org on 2020/12/29 13:05:18 UTC

[buildstream] 01/26: remote_execution: Update proto

This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch traveltissues/mr4
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 80df8e27e7f5b0ec82baa44de33d770f3830eea1
Author: Darius Makovsky <tr...@protonmail.com>
AuthorDate: Wed Dec 11 14:27:52 2019 +0000

    remote_execution: Update proto
---
 src/buildstream/_cas/casserver.py                  |   4 +-
 .../remote/execution/v2/remote_execution.proto     | 463 ++++++++++++----
 .../remote/execution/v2/remote_execution_pb2.py    | 613 ++++++++++++++++-----
 .../execution/v2/remote_execution_pb2_grpc.py      |  60 +-
 4 files changed, 873 insertions(+), 267 deletions(-)

diff --git a/src/buildstream/_cas/casserver.py b/src/buildstream/_cas/casserver.py
index 882e7e6..dd822d5 100644
--- a/src/buildstream/_cas/casserver.py
+++ b/src/buildstream/_cas/casserver.py
@@ -268,10 +268,10 @@ class _CapabilitiesServicer(remote_execution_pb2_grpc.CapabilitiesServicer):
         response = remote_execution_pb2.ServerCapabilities()
 
         cache_capabilities = response.cache_capabilities
-        cache_capabilities.digest_function.append(remote_execution_pb2.SHA256)
+        cache_capabilities.digest_function.append(remote_execution_pb2.DigestFunction.SHA256)
         cache_capabilities.action_cache_update_capabilities.update_enabled = False
         cache_capabilities.max_batch_total_size_bytes = _MAX_PAYLOAD_BYTES
-        cache_capabilities.symlink_absolute_path_strategy = remote_execution_pb2.CacheCapabilities.ALLOWED
+        cache_capabilities.symlink_absolute_path_strategy = remote_execution_pb2.SymlinkAbsolutePathStrategy.ALLOWED
 
         response.deprecated_api_version.major = 2
         response.low_api_version.major = 2
diff --git a/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution.proto b/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution.proto
index 7edbce3..efbf513 100644
--- a/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution.proto
+++ b/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution.proto
@@ -81,6 +81,7 @@ service Execution {
   // action will be reported in the `status` field of the `ExecuteResponse`. The
   // server MUST NOT set the `error` field of the `Operation` proto.
   // The possible errors include:
+  //
   // * `INVALID_ARGUMENT`: One or more arguments are invalid.
   // * `FAILED_PRECONDITION`: One or more errors occurred in setting up the
   //   action requested, such as a missing input or command or no worker being
@@ -93,6 +94,9 @@ service Execution {
   // * `INTERNAL`: An internal error occurred in the execution engine or the
   //   worker.
   // * `DEADLINE_EXCEEDED`: The execution timed out.
+  // * `CANCELLED`: The operation was cancelled by the client. This status is
+  //   only possible if the server implements the Operations API CancelOperation
+  //   method, and it was called for the current execution.
   //
   // In the case of a missing input or command, the server SHOULD additionally
   // send a [PreconditionFailure][google.rpc.PreconditionFailure] error detail
@@ -124,10 +128,7 @@ service Execution {
 //
 // The lifetime of entries in the action cache is implementation-specific, but
 // the server SHOULD assume that more recently used entries are more likely to
-// be used again. Additionally, action cache implementations SHOULD ensure that
-// any blobs referenced in the
-// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]
-// are still valid when returning a result.
+// be used again.
 //
 // As with other services in the Remote Execution API, any call may return an
 // error with a [RetryInfo][google.rpc.RetryInfo] error detail providing
@@ -136,7 +137,15 @@ service Execution {
 service ActionCache {
   // Retrieve a cached execution result.
   //
+  // Implementations SHOULD ensure that any blobs referenced from the
+  // [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]
+  // are available at the time of returning the
+  // [ActionResult][build.bazel.remote.execution.v2.ActionResult] and will be
+  // for some period of time afterwards. The TTLs of the referenced blobs SHOULD be increased
+  // if necessary and applicable.
+  //
   // Errors:
+  //
   // * `NOT_FOUND`: The requested `ActionResult` is not in the cache.
   rpc GetActionResult(GetActionResultRequest) returns (ActionResult) {
     option (google.api.http) = { get: "/v2/{instance_name=**}/actionResults/{action_digest.hash}/{action_digest.size_bytes}" };
@@ -144,11 +153,6 @@ service ActionCache {
 
   // Upload a new execution result.
   //
-  // This method is intended for servers which implement the distributed cache
-  // independently of the
-  // [Execution][build.bazel.remote.execution.v2.Execution] API. As a
-  // result, it is OPTIONAL for servers to implement.
-  //
   // In order to allow the server to perform access control based on the type of
   // action, and to assist with client debugging, the client MUST first upload
   // the [Action][build.bazel.remote.execution.v2.Execution] that produced the
@@ -157,7 +161,10 @@ service ActionCache {
   // `ContentAddressableStorage`.
   //
   // Errors:
-  // * `NOT_IMPLEMENTED`: This method is not supported by the server.
+  //
+  // * `INVALID_ARGUMENT`: One or more arguments are invalid.
+  // * `FAILED_PRECONDITION`: One or more errors occurred in updating the
+  //   action result, such as a missing command or action.
   // * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the
   //   entry to the cache.
   rpc UpdateActionResult(UpdateActionResultRequest) returns (ActionResult) {
@@ -181,8 +188,8 @@ service ActionCache {
 // hierarchy, which must also each be uploaded on their own.
 //
 // For small file uploads the client should group them together and call
-// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]
-// on chunks of no more than 10 MiB. For large uploads, the client must use the
+// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs].
+// For large uploads, the client must use the
 // [Write method][google.bytestream.ByteStream.Write] of the ByteStream API. The
 // `resource_name` is `{instance_name}/uploads/{uuid}/blobs/{hash}/{size}`,
 // where `instance_name` is as described in the next paragraph, `uuid` is a
@@ -204,6 +211,9 @@ service ActionCache {
 // by the server. For servers which do not support multiple instances, then the
 // `instance_name` is the empty path and the leading slash is omitted, so that
 // the `resource_name` becomes `uploads/{uuid}/blobs/{hash}/{size}`.
+// To simplify parsing, a path segment cannot equal any of the following
+// keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations` and
+// `capabilities`.
 //
 // When attempting an upload, if another client has already completed the upload
 // (which may occur in the middle of a single upload if another client uploads
@@ -255,10 +265,12 @@ service ContentAddressableStorage {
   // independently.
   //
   // Errors:
+  //
   // * `INVALID_ARGUMENT`: The client attempted to upload more than the
   //   server supported limit.
   //
   // Individual requests may return the following errors, additionally:
+  //
   // * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob.
   // * `INVALID_ARGUMENT`: The
   // [Digest][build.bazel.remote.execution.v2.Digest] does not match the
@@ -281,6 +293,7 @@ service ContentAddressableStorage {
   // independently.
   //
   // Errors:
+  //
   // * `INVALID_ARGUMENT`: The client attempted to read more than the
   //   server supported limit.
   //
@@ -310,6 +323,8 @@ service ContentAddressableStorage {
   // If part of the tree is missing from the CAS, the server will return the
   // portion present and omit the rest.
   //
+  // Errors:
+  //
   // * `NOT_FOUND`: The requested tree root is not present in the CAS.
   rpc GetTree(GetTreeRequest) returns (stream GetTreeResponse) {
     option (google.api.http) = { get: "/v2/{instance_name=**}/blobs/{root_digest.hash}/{root_digest.size_bytes}:getTree" };
@@ -323,7 +338,14 @@ service ContentAddressableStorage {
 // The query may include a particular `instance_name`, in which case the values
 // returned will pertain to that instance.
 service Capabilities {
-  // GetCapabilities returns the server capabilities configuration.
+  // GetCapabilities returns the server capabilities configuration of the
+  // remote endpoint.
+  // Only the capabilities of the services supported by the endpoint will
+  // be returned:
+  // * Execution + CAS + Action Cache endpoints should return both
+  //   CacheCapabilities and ExecutionCapabilities.
+  // * Execution only endpoints should return ExecutionCapabilities.
+  // * CAS + Action Cache only endpoints should return CacheCapabilities.
   rpc GetCapabilities(GetCapabilitiesRequest) returns (ServerCapabilities) {
     option (google.api.http) = {
       get: "/v2/{instance_name=**}/capabilities"
@@ -387,8 +409,19 @@ message Action {
   // immediately, rather than whenever the cache entry gets evicted.
   google.protobuf.Duration timeout = 6;
 
-  // If true, then the `Action`'s result cannot be cached.
+  // If true, then the `Action`'s result cannot be cached, and in-flight
+  // requests for the same `Action` may not be merged.
   bool do_not_cache = 7;
+
+  // List of required supported [NodeProperty][build.bazel.remote.execution.v2.NodeProperty]
+  // keys. In order to ensure that equivalent `Action`s always hash to the same
+  // value, the supported node properties MUST be lexicographically sorted by name.
+  // Sorting of strings is done by code point, equivalently, by the UTF-8 bytes.
+  //
+  // The interpretation of these properties is server-dependent. If a property is
+  // not recognized by the server, the server will return an `INVALID_ARGUMENT`
+  // error.
+  repeated string output_node_properties = 8;
 }
 
 // A `Command` is the actual command executed by a worker running an
@@ -418,7 +451,8 @@ message Command {
   // provide its own default environment variables; these defaults can be
   // overridden using this field. Additional variables can also be specified.
   //
-  // In order to ensure that equivalent `Command`s always hash to the same
+  // In order to ensure that equivalent
+  // [Command][build.bazel.remote.execution.v2.Command]s always hash to the same
   // value, the environment variables MUST be lexicographically sorted by name.
   // Sorting of strings is done by code point, equivalently, by the UTF-8 bytes.
   repeated EnvironmentVariable environment_variables = 2;
@@ -426,7 +460,8 @@ message Command {
   // A list of the output files that the client expects to retrieve from the
   // action. Only the listed files, as well as directories listed in
   // `output_directories`, will be returned to the client as output.
-  // Other files that may be created during command execution are discarded.
+  // Other files or directories that may be created during command execution
+  // are discarded.
   //
   // The paths are relative to the working directory of the action execution.
   // The paths are specified using a single forward slash (`/`) as a path
@@ -438,16 +473,22 @@ message Command {
   // MUST be sorted lexicographically by code point (or, equivalently, by UTF-8
   // bytes).
   //
-  // An output file cannot be duplicated, be a parent of another output file, be
-  // a child of a listed output directory, or have the same path as any of the
-  // listed output directories.
+  // An output file cannot be duplicated, be a parent of another output file, or
+  // have the same path as any of the listed output directories.
+  //
+  // Directories leading up to the output files are created by the worker prior
+  // to execution, even if they are not explicitly part of the input root.
+  //
+  // DEPRECATED since v2.1: Use `output_paths` instead.
   repeated string output_files = 3;
 
   // A list of the output directories that the client expects to retrieve from
-  // the action. Only the contents of the indicated directories (recursively
-  // including the contents of their subdirectories) will be
-  // returned, as well as files listed in `output_files`. Other files that may
-  // be created during command execution are discarded.
+  // the action. Only the listed directories will be returned (an entire
+  // directory structure will be returned as a
+  // [Tree][build.bazel.remote.execution.v2.Tree] message digest, see
+  // [OutputDirectory][build.bazel.remote.execution.v2.OutputDirectory]), as
+  // well as files listed in `output_files`. Other files or directories that
+  // may be created during command execution are discarded.
   //
   // The paths are relative to the working directory of the action execution.
   // The paths are specified using a single forward slash (`/`) as a path
@@ -461,15 +502,52 @@ message Command {
   // MUST be sorted lexicographically by code point (or, equivalently, by UTF-8
   // bytes).
   //
-  // An output directory cannot be duplicated, be a parent of another output
-  // directory, be a parent of a listed output file, or have the same path as
-  // any of the listed output files.
+  // An output directory cannot be duplicated or have the same path as any of
+  // the listed output files. An output directory is allowed to be a parent of
+  // another output directory.
+  //
+  // Directories leading up to the output directories (but not the output
+  // directories themselves) are created by the worker prior to execution, even
+  // if they are not explicitly part of the input root.
+  //
+  // DEPRECATED since 2.1: Use `output_paths` instead.
   repeated string output_directories = 4;
 
+  // A list of the output paths that the client expects to retrieve from the
+  // action. Only the listed paths will be returned to the client as output.
+  // The type of the output (file or directory) is not specified, and will be
+  // determined by the server after action execution. If the resulting path is
+  // a file, it will be returned in an
+  // [OutputFile][build.bazel.remote.execution.v2.OutputFile]) typed field.
+  // If the path is a directory, the entire directory structure will be returned
+  // as a [Tree][build.bazel.remote.execution.v2.Tree] message digest, see
+  // [OutputDirectory][build.bazel.remote.execution.v2.OutputDirectory])
+  // Other files or directories that may be created during command execution
+  // are discarded.
+  //
+  // The paths are relative to the working directory of the action execution.
+  // The paths are specified using a single forward slash (`/`) as a path
+  // separator, even if the execution platform natively uses a different
+  // separator. The path MUST NOT include a trailing slash, nor a leading slash,
+  // being a relative path.
+  //
+  // In order to ensure consistent hashing of the same Action, the output paths
+  // MUST be deduplicated and sorted lexicographically by code point (or,
+  // equivalently, by UTF-8 bytes).
+  //
+  // Directories leading up to the output paths are created by the worker prior
+  // to execution, even if they are not explicitly part of the input root.
+  //
+  // New in v2.1: this field supersedes the DEPRECATED `output_files` and
+  // `output_directories` fields. If `output_paths` is used, `output_files` and
+  // `output_directories` will be ignored!
+  repeated string output_paths = 7;
+
   // The platform requirements for the execution environment. The server MAY
   // choose to execute the action on any worker satisfying the requirements, so
   // the client SHOULD ensure that running the action on any such worker will
   // have the same result.
+  // A detailed lexicon for this can be found in the accompanying platform.md.
   Platform platform = 5;
 
   // The working directory, relative to the input root, for the command to run
@@ -527,12 +605,21 @@ message Platform {
 // In order to ensure that two equivalent directory trees hash to the same
 // value, the following restrictions MUST be obeyed when constructing a
 // a `Directory`:
-//   - Every child in the directory must have a path of exactly one segment.
-//     Multiple levels of directory hierarchy may not be collapsed.
-//   - Each child in the directory must have a unique path segment (file name).
-//   - The files, directories and symlinks in the directory must each be sorted
-//     in lexicographical order by path. The path strings must be sorted by code
-//     point, equivalently, by UTF-8 bytes.
+//
+// * Every child in the directory must have a path of exactly one segment.
+//   Multiple levels of directory hierarchy may not be collapsed.
+// * Each child in the directory must have a unique path segment (file name).
+//   Note that while the API itself is case-sensitive, the environment where
+//   the Action is executed may or may not be case-sensitive. That is, it is
+//   legal to call the API with a Directory that has both "Foo" and "foo" as
+//   children, but the Action may be rejected by the remote system upon
+//   execution.
+// * The files, directories and symlinks in the directory must each be sorted
+//   in lexicographical order by path. The path strings must be sorted by code
+//   point, equivalently, by UTF-8 bytes.
+// * The [NodeProperties][build.bazel.remote.execution.v2.NodeProperty] of files,
+//   directories, and symlinks must be sorted in lexicographical order by
+//   property name.
 //
 // A `Directory` that obeys the restrictions is said to be in canonical form.
 //
@@ -549,7 +636,13 @@ message Platform {
 //       digest: {
 //         hash: "4a73bc9d03...",
 //         size: 65534
-//       }
+//       },
+//       node_properties: [
+//         {
+//           "name": "MTime",
+//           "value": "2017-01-15T01:30:15.01Z"
+//         }
+//       ]
 //     }
 //   ],
 //   directories: [
@@ -586,6 +679,22 @@ message Directory {
 
   // The symlinks in the directory.
   repeated SymlinkNode symlinks = 3;
+
+  // The node properties of the Directory.
+  repeated NodeProperty node_properties = 4;
+}
+
+// A single property for [FileNodes][build.bazel.remote.execution.v2.FileNode],
+// [DirectoryNodes][build.bazel.remote.execution.v2.DirectoryNode], and
+// [SymlinkNodes][build.bazel.remote.execution.v2.SymlinkNode]. The server is
+// responsible for specifying the property `name`s that it accepts. If
+// permitted by the server, the same `name` may occur multiple times.
+message NodeProperty {
+    // The property name.
+    string name = 1;
+
+    // The property value.
+    string value = 2;
 }
 
 // A `FileNode` represents a single file and associated metadata.
@@ -600,6 +709,9 @@ message FileNode {
 
   // True if file is executable, false otherwise.
   bool is_executable = 4;
+
+  // The node properties of the FileNode.
+  repeated NodeProperty node_properties = 5;
 }
 
 // A `DirectoryNode` represents a child of a
@@ -628,11 +740,13 @@ message SymlinkNode {
   // API. The canonical form forbids the substrings `/./` and `//` in the target
   // path. `..` components are allowed anywhere in the target path.
   string target = 2;
+
+  // The node properties of the SymlinkNode.
+  repeated NodeProperty node_properties = 3;
 }
 
 // A content digest. A digest for a given blob consists of the size of the blob
-// and its hash. The hash algorithm to use is defined by the server, but servers
-// SHOULD use SHA-256.
+// and its hash. The hash algorithm to use is defined by the server.
 //
 // The size is considered to be an integral part of the digest and cannot be
 // separated. That is, even if the `hash` field is correctly specified but
@@ -652,11 +766,12 @@ message SymlinkNode {
 // When a `Digest` is used to refer to a proto message, it always refers to the
 // message in binary encoded form. To ensure consistent hashing, clients and
 // servers MUST ensure that they serialize messages according to the following
-// rules, even if there are alternate valid encodings for the same message.
-// - Fields are serialized in tag order.
-// - There are no unknown fields.
-// - There are no duplicate fields.
-// - Fields are serialized according to the default semantics for their type.
+// rules, even if there are alternate valid encodings for the same message:
+//
+// * Fields are serialized in tag order.
+// * There are no unknown fields.
+// * There are no duplicate fields.
+// * Fields are serialized according to the default semantics for their type.
 //
 // Most protocol buffer implementations will always follow these rules when
 // serializing, but care should be taken to avoid shortcuts. For instance,
@@ -709,19 +824,58 @@ message ActionResult {
   reserved 1; // Reserved for use as the resource name.
 
   // The output files of the action. For each output file requested in the
-  // `output_files` field of the Action, if the corresponding file existed after
-  // the action completed, a single entry will be present in the output list.
+  // `output_files` or `output_paths` field of the Action, if the corresponding
+  // file existed after the action completed, a single entry will be present
+  // either in this field, or the `output_file_symlinks` field if the file was
+  // a symbolic link to another file (`output_symlinks` field after v2.1).
   //
-  // If the action does not produce the requested output, or produces a
-  // directory where a regular file is expected or vice versa, then that output
+  // If an output listed in `output_files` was found, but was a directory rather
+  // than a regular file, the server will return a FAILED_PRECONDITION.
+  // If the action does not produce the requested output, then that output
   // will be omitted from the list. The server is free to arrange the output
   // list as desired; clients MUST NOT assume that the output list is sorted.
   repeated OutputFile output_files = 2;
 
+  // The output files of the action that are symbolic links to other files. Those
+  // may be links to other output files, or input files, or even absolute paths
+  // outside of the working directory, if the server supports
+  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy].
+  // For each output file requested in the `output_files` or `output_paths`
+  // field of the Action, if the corresponding file existed after
+  // the action completed, a single entry will be present either in this field,
+  // or in the `output_files` field, if the file was not a symbolic link.
+  //
+  // If an output symbolic link of the same name as listed in `output_files` of
+  // the Command was found, but its target type was not a regular file, the
+  // server will return a FAILED_PRECONDITION.
+  // If the action does not produce the requested output, then that output
+  // will be omitted from the list. The server is free to arrange the output
+  // list as desired; clients MUST NOT assume that the output list is sorted.
+  //
+  // DEPRECATED as of v2.1. Servers that wish to be compatible with v2.0 API
+  // should still populate this field in addition to `output_symlinks`.
+  repeated OutputSymlink output_file_symlinks = 10;
+
+  // New in v2.1: this field will only be populated if the command
+  // `output_paths` field was used, and not the pre v2.1 `output_files` or
+  // `output_directories` fields.
+  // The output paths of the action that are symbolic links to other paths. Those
+  // may be links to other outputs, or inputs, or even absolute paths
+  // outside of the working directory, if the server supports
+  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy].
+  // A single entry for each output requested in `output_paths`
+  // field of the Action, if the corresponding path existed after
+  // the action completed and was a symbolic link.
+  //
+  // If the action does not produce a requested output, then that output
+  // will be omitted from the list. The server is free to arrange the output
+  // list as desired; clients MUST NOT assume that the output list is sorted.
+  repeated OutputSymlink output_symlinks = 12;
+
   // The output directories of the action. For each output directory requested
-  // in the `output_directories` field of the Action, if the corresponding
-  // directory existed after the action completed, a single entry will be
-  // present in the output list, which will contain the digest of a
+  // in the `output_directories` or `output_paths` field of the Action, if the
+  // corresponding directory existed after the action completed, a single entry
+  // will be present in the output list, which will contain the digest of a
   // [Tree][build.bazel.remote.execution.v2.Tree] message containing the
   // directory tree, and the path equal exactly to the corresponding Action
   // output_directories member.
@@ -777,37 +931,56 @@ message ActionResult {
   //   }
   // }
   // ```
+  // If an output of the same name as listed in `output_files` of
+  // the Command was found in `output_directories`, but was not a directory, the
+  // server will return a FAILED_PRECONDITION.
   repeated OutputDirectory output_directories = 3;
 
+  // The output directories of the action that are symbolic links to other
+  // directories. Those may be links to other output directories, or input
+  // directories, or even absolute paths outside of the working directory,
+  // if the server supports
+  // [SymlinkAbsolutePathStrategy.ALLOWED][build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy].
+  // For each output directory requested in the `output_directories` field of
+  // the Action, if the directory existed after the action completed, a
+  // single entry will be present either in this field, or in the
+  // `output_directories` field, if the directory was not a symbolic link.
+  //
+  // If an output of the same name was found, but was a symbolic link to a file
+  // instead of a directory, the server will return a FAILED_PRECONDITION.
+  // If the action does not produce the requested output, then that output
+  // will be omitted from the list. The server is free to arrange the output
+  // list as desired; clients MUST NOT assume that the output list is sorted.
+  //
+  // DEPRECATED as of v2.1. Servers that wish to be compatible with v2.0 API
+  // should still populate this field in addition to `output_symlinks`.
+  repeated OutputSymlink output_directory_symlinks = 11;
+
   // The exit code of the command.
   int32 exit_code = 4;
 
-  // The standard output buffer of the action. The server will determine, based
-  // on the size of the buffer, whether to return it in raw form or to return
-  // a digest in `stdout_digest` that points to the buffer. If neither is set,
-  // then the buffer is empty. The client SHOULD NOT assume it will get one of
-  // the raw buffer or a digest on any given request and should be prepared to
-  // handle either.
+  // The standard output buffer of the action. The server SHOULD NOT inline
+  // stdout unless requested by the client in the
+  // [GetActionResultRequest][build.bazel.remote.execution.v2.GetActionResultRequest]
+  // message. The server MAY omit inlining, even if requested, and MUST do so if inlining
+  // would cause the response to exceed message size limits.
   bytes stdout_raw = 5;
 
   // The digest for a blob containing the standard output of the action, which
   // can be retrieved from the
   // [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage].
-  // See `stdout_raw` for when this will be set.
   Digest stdout_digest = 6;
 
-  // The standard error buffer of the action. The server will determine, based
-  // on the size of the buffer, whether to return it in raw form or to return
-  // a digest in `stderr_digest` that points to the buffer. If neither is set,
-  // then the buffer is empty. The client SHOULD NOT assume it will get one of
-  // the raw buffer or a digest on any given request and should be prepared to
-  // handle either.
+  // The standard error buffer of the action. The server SHOULD NOT inline
+  // stderr unless requested by the client in the
+  // [GetActionResultRequest][build.bazel.remote.execution.v2.GetActionResultRequest]
+  // message. The server MAY omit inlining, even if requested, and MUST do so if inlining
+  // would cause the response to exceed message size limits.
   bytes stderr_raw = 7;
 
   // The digest for a blob containing the standard error of the action, which
   // can be retrieved from the
   // [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage].
-  // See `stderr_raw` for when this will be set.
   Digest stderr_digest = 8;
 
   // The details of the execution that originally produced this result.
@@ -818,10 +991,8 @@ message ActionResult {
 // [FileNode][build.bazel.remote.execution.v2.FileNode], but it is used as an
 // output in an `ActionResult`. It allows a full file path rather than
 // only a name.
-//
-// `OutputFile` is binary-compatible with `FileNode`.
 message OutputFile {
-  // The full path of the file relative to the input root, including the
+  // The full path of the file relative to the working directory, including the
   // filename. The path separator is a forward slash `/`. Since this is a
   // relative path, it MUST NOT begin with a leading forward slash.
   string path = 1;
@@ -833,6 +1004,16 @@ message OutputFile {
 
   // True if file is executable, false otherwise.
   bool is_executable = 4;
+
+  // The contents of the file if inlining was requested. The server SHOULD NOT inline
+  // file contents unless requested by the client in the
+  // [GetActionResultRequest][build.bazel.remote.execution.v2.GetActionResultRequest]
+  // message. The server MAY omit inlining, even if requested, and MUST do so if inlining
+  // would cause the response to exceed message size limits.
+  bytes contents = 5;
+
+  // The supported node properties of the OutputFile, if requested by the Action.
+  repeated NodeProperty node_properties = 6;
 }
 
 // A `Tree` contains all the
@@ -866,6 +1047,30 @@ message OutputDirectory {
   Digest tree_digest = 3;
 }
 
+// An `OutputSymlink` is similar to a
+// [Symlink][build.bazel.remote.execution.v2.SymlinkNode], but it is used as an
+// output in an `ActionResult`.
+//
+// `OutputSymlink` is binary-compatible with `SymlinkNode`.
+message OutputSymlink {
+  // The full path of the symlink relative to the working directory, including the
+  // filename. The path separator is a forward slash `/`. Since this is a
+  // relative path, it MUST NOT begin with a leading forward slash.
+  string path = 1;
+
+  // The target path of the symlink. The path separator is a forward slash `/`.
+  // The target path can be relative to the parent directory of the symlink or
+  // it can be an absolute path starting with `/`. Support for absolute paths
+  // can be checked using the [Capabilities][build.bazel.remote.execution.v2.Capabilities]
+  // API. The canonical form forbids the substrings `/./` and `//` in the target
+  // path. `..` components are allowed anywhere in the target path.
+  string target = 2;
+
+  // The supported node properties of the OutputSymlink, if requested by the
+  // Action.
+  repeated NodeProperty node_properties = 3;
+}
+
 // An `ExecutionPolicy` can be used to control the scheduling of the action.
 message ExecutionPolicy {
   // The priority (relative importance) of this action. Generally, a lower value
@@ -904,9 +1109,19 @@ message ExecuteRequest {
   // omitted.
   string instance_name = 1;
 
-  // If true, the action will be executed anew even if its result was already
-  // present in the cache. If false, the result may be served from the
-  // [ActionCache][build.bazel.remote.execution.v2.ActionCache].
+  // If true, the action will be executed even if its result is already
+  // present in the [ActionCache][build.bazel.remote.execution.v2.ActionCache].
+  // The execution is still allowed to be merged with other in-flight executions
+  // of the same action, however - semantically, the service MUST only guarantee
+  // that the results of an execution with this field set were not visible
+  // before the corresponding execution request was sent.
+  // Note that actions from execution requests setting this field set are still
+  // eligible to be entered into the action cache upon completion, and services
+  // SHOULD overwrite any existing entries that may exist. This allows
+  // skip_cache_lookup requests to be used as a mechanism for replacing action
+  // cache entries that reference outputs no longer available or that are
+  // poisoned in any way.
+  // If false, the result may be served from the action cache.
   bool skip_cache_lookup = 3;
 
   reserved 2, 4, 5; // Used for removed fields in an earlier version of the API.
@@ -970,16 +1185,16 @@ message ExecuteResponse {
   // phase. The keys SHOULD be human readable so that a client can display them
   // to a user.
   map<string, LogFile> server_logs = 4;
+
+  // Freeform informational message with details on the execution of the action
+  // that may be displayed to the user upon failure or when requested explicitly.
+  string message = 5;
 }
 
-// Metadata about an ongoing
-// [execution][build.bazel.remote.execution.v2.Execution.Execute], which
-// will be contained in the [metadata
-// field][google.longrunning.Operation.response] of the
-// [Operation][google.longrunning.Operation].
-message ExecuteOperationMetadata {
-  // The current stage of execution.
-  enum Stage {
+// The current stage of action execution.
+message ExecutionStage {
+  enum Value {
+    // Invalid value.
     UNKNOWN = 0;
 
     // Checking the result against the cache.
@@ -994,8 +1209,16 @@ message ExecuteOperationMetadata {
     // Finished execution.
     COMPLETED = 4;
   }
+}
 
-  Stage stage = 1;
+// Metadata about an ongoing
+// [execution][build.bazel.remote.execution.v2.Execution.Execute], which
+// will be contained in the [metadata
+// field][google.longrunning.Operation.response] of the
+// [Operation][google.longrunning.Operation].
+message ExecuteOperationMetadata {
+  // The current stage of execution.
+  ExecutionStage.Value stage = 1;
 
   // The digest of the [Action][build.bazel.remote.execution.v2.Action]
   // being executed.
@@ -1015,7 +1238,7 @@ message ExecuteOperationMetadata {
 // A request message for
 // [WaitExecution][build.bazel.remote.execution.v2.Execution.WaitExecution].
 message WaitExecutionRequest {
-  // The name of the [Operation][google.longrunning.operations.v1.Operation]
+  // The name of the [Operation][google.longrunning.Operation]
   // returned by [Execute][build.bazel.remote.execution.v2.Execution.Execute].
   string name = 1;
 }
@@ -1033,6 +1256,19 @@ message GetActionResultRequest {
   // The digest of the [Action][build.bazel.remote.execution.v2.Action]
   // whose result is requested.
   Digest action_digest = 2;
+
+  // A hint to the server to request inlining stdout in the
+  // [ActionResult][build.bazel.remote.execution.v2.ActionResult] message.
+  bool inline_stdout = 3;
+
+  // A hint to the server to request inlining stderr in the
+  // [ActionResult][build.bazel.remote.execution.v2.ActionResult] message.
+  bool inline_stderr = 4;
+
+  // A hint to the server to inline the contents of the listed output files.
+  // Each path needs to exactly match one path in `output_files` in the
+  // [Command][build.bazel.remote.execution.v2.Command] message.
+  repeated string inline_output_files = 5;
 }
 
 // A request message for
@@ -1136,7 +1372,7 @@ message BatchReadBlobsRequest {
 // A response message for
 // [ContentAddressableStorage.BatchReadBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchReadBlobs].
 message BatchReadBlobsResponse {
-  // A response corresponding to a single blob that the client tried to upload.
+  // A response corresponding to a single blob that the client tried to download.
   message Response {
     // The digest to which this response corresponds.
     Digest digest = 1;
@@ -1176,7 +1412,8 @@ message GetTreeRequest {
 
   // A page token, which must be a value received in a previous
   // [GetTreeResponse][build.bazel.remote.execution.v2.GetTreeResponse].
-  // If present, the server will use it to return the following page of results.
+  // If present, the server will use that token as an offset, returning only
+  // that page and the ones that succeed it.
   string page_token = 4;
 }
 
@@ -1194,7 +1431,7 @@ message GetTreeResponse {
 }
 
 // A request message for
-// [Capabilities.GetCapabilities][google.devtools.remoteexecution.v2.Capabilities.GetCapabilities].
+// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
 message GetCapabilitiesRequest {
   // The instance of the execution system to operate against. A server may
   // support multiple instances of the execution system (with their own workers,
@@ -1205,7 +1442,7 @@ message GetCapabilitiesRequest {
 }
 
 // A response message for
-// [Capabilities.GetCapabilities][google.devtools.remoteexecution.v2.Capabilities.GetCapabilities].
+// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities].
 message ServerCapabilities {
   // Capabilities of the remote cache system.
   CacheCapabilities cache_capabilities = 1;
@@ -1225,11 +1462,30 @@ message ServerCapabilities {
 
 // The digest function used for converting values into keys for CAS and Action
 // Cache.
-enum DigestFunction {
-  UNKNOWN = 0;
-  SHA256 = 1;
-  SHA1 = 2;
-  MD5 = 3;
+message DigestFunction {
+  enum Value {
+    // It is an error for the server to return this value.
+    UNKNOWN = 0;
+
+    // The SHA-256 digest function.
+    SHA256 = 1;
+
+    // The SHA-1 digest function.
+    SHA1 = 2;
+
+    // The MD5 digest function.
+    MD5 = 3;
+
+    // The Microsoft "VSO-Hash" paged SHA256 digest function.
+    // See https://github.com/microsoft/BuildXL/blob/master/Documentation/Specs/PagedHash.md .
+    VSO = 4;
+
+    // The SHA-384 digest function.
+    SHA384 = 5;
+
+    // The SHA-512 digest function.
+    SHA512 = 6;
+  }
 }
 
 // Describes the server/instance capabilities for updating the action cache.
@@ -1249,25 +1505,29 @@ message PriorityCapabilities {
   repeated PriorityRange priorities = 1;
 }
 
-// Capabilities of the remote cache system.
-message CacheCapabilities {
-  // Describes how the server treats absolute symlink targets.
-  enum SymlinkAbsolutePathStrategy {
+// Describes how the server treats absolute symlink targets.
+message SymlinkAbsolutePathStrategy {
+  enum Value {
+    // Invalid value.
     UNKNOWN = 0;
 
-    // Server will return an INVALID_ARGUMENT on input symlinks with absolute targets.
+    // Server will return an `INVALID_ARGUMENT` on input symlinks with absolute
+    // targets.
     // If an action tries to create an output symlink with an absolute target, a
-    // FAILED_PRECONDITION will be returned.
+    // `FAILED_PRECONDITION` will be returned.
     DISALLOWED = 1;
 
     // Server will allow symlink targets to escape the input root tree, possibly
     // resulting in non-hermetic builds.
     ALLOWED = 2;
   }
+}
 
+// Capabilities of the remote cache system.
+message CacheCapabilities {
   // All the digest functions supported by the remote cache.
   // Remote cache may support multiple digest functions simultaneously.
-  repeated DigestFunction digest_function = 1;
+  repeated DigestFunction.Value digest_function = 1;
 
   // Capabilities for updating the action cache.
   ActionCacheUpdateCapabilities action_cache_update_capabilities = 2;
@@ -1282,19 +1542,22 @@ message CacheCapabilities {
   int64 max_batch_total_size_bytes = 4;
 
   // Whether absolute symlink targets are supported.
-  SymlinkAbsolutePathStrategy symlink_absolute_path_strategy = 5;
+  SymlinkAbsolutePathStrategy.Value symlink_absolute_path_strategy = 5;
 }
 
 // Capabilities of the remote execution system.
 message ExecutionCapabilities {
   // Remote execution may only support a single digest function.
-  DigestFunction digest_function = 1;
+  DigestFunction.Value digest_function = 1;
 
   // Whether remote execution is enabled for the particular server/instance.
   bool exec_enabled = 2;
 
   // Supported execution priority range.
   PriorityCapabilities execution_priority_capabilities = 3;
+
+  // Supported node properties.
+  repeated string supported_node_properties = 4;
 }
 
 // Details for the tool used to call the API.
@@ -1310,8 +1573,14 @@ message ToolDetails {
 // external context of the request. The server may use this for logging or other
 // purposes. To use it, the client attaches the header to the call using the
 // canonical proto serialization:
-// name: build.bazel.remote.execution.v2.requestmetadata-bin
-// contents: the base64 encoded binary RequestMetadata message.
+//
+// * name: `build.bazel.remote.execution.v2.requestmetadata-bin`
+// * contents: the base64 encoded binary `RequestMetadata` message.
+// Note: the gRPC library serializes binary headers encoded in base 64 by
+// default (https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests).
+// Therefore, if the gRPC library is used to pass/retrieve this
+// metadata, the user may ignore the base64 encoding and assume it is simply
+// serialized as a binary message.
 message RequestMetadata {
   // The details for the tool invoking the requests.
   ToolDetails tool_details = 1;
diff --git a/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2.py b/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2.py
index ac42b7b..97ec30c 100644
--- a/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2.py
+++ b/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2.py
@@ -4,7 +4,6 @@
 
 import sys
 _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf.internal import enum_type_wrapper
 from google.protobuf import descriptor as _descriptor
 from google.protobuf import message as _message
 from google.protobuf import reflection as _reflection
@@ -27,13 +26,15 @@ DESCRIPTOR = _descriptor.FileDescriptor(
   package='build.bazel.remote.execution.v2',
   syntax='proto3',
   serialized_options=_b('\n\037build.bazel.remote.execution.v2B\024RemoteExecutionProtoP\001Z\017remoteexecution\242\002\003REX\252\002\037Build.Bazel.Remote.Execution.V2'),
-  serialized_pb=_b('\n6build/bazel/remote/execution/v2/remote_execution.proto\x12\x1f\x62uild.bazel.remote.execution.v2\x1a\x1f\x62uild/bazel/semver/semver.proto\x1a\x1cgoogle/api/annotations.proto\x1a#google/longrunning/operations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17google/rpc/status.proto\"\xd5\x01\n\x06\x41\x63tion\x12?\n\x0e\x63ommand_digest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x42\n\x11input_root_dig [...]
+  serialized_pb=_b('\n6build/bazel/remote/execution/v2/remote_execution.proto\x12\x1f\x62uild.bazel.remote.execution.v2\x1a\x1f\x62uild/bazel/semver/semver.proto\x1a\x1cgoogle/api/annotations.proto\x1a#google/longrunning/operations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17google/rpc/status.proto\"\xf5\x01\n\x06\x41\x63tion\x12?\n\x0e\x63ommand_digest\x18\x01 \x01(\x0b\x32\'.build.bazel.remote.execution.v2.Digest\x12\x42\n\x11input_root_dig [...]
   ,
   dependencies=[build_dot_bazel_dot_semver_dot_semver__pb2.DESCRIPTOR,google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_longrunning_dot_operations__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_rpc_dot_status__pb2.DESCRIPTOR,])
 
-_DIGESTFUNCTION = _descriptor.EnumDescriptor(
-  name='DigestFunction',
-  full_name='build.bazel.remote.execution.v2.DigestFunction',
+
+
+_EXECUTIONSTAGE_VALUE = _descriptor.EnumDescriptor(
+  name='Value',
+  full_name='build.bazel.remote.execution.v2.ExecutionStage.Value',
   filename=None,
   file=DESCRIPTOR,
   values=[
@@ -42,35 +43,32 @@ _DIGESTFUNCTION = _descriptor.EnumDescriptor(
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='SHA256', index=1, number=1,
+      name='CACHE_CHECK', index=1, number=1,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='SHA1', index=2, number=2,
+      name='QUEUED', index=2, number=2,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='MD5', index=3, number=3,
+      name='EXECUTING', index=3, number=3,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='COMPLETED', index=4, number=4,
       serialized_options=None,
       type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7213,
-  serialized_end=7273,
+  serialized_start=4432,
+  serialized_end=4511,
 )
-_sym_db.RegisterEnumDescriptor(_DIGESTFUNCTION)
-
-DigestFunction = enum_type_wrapper.EnumTypeWrapper(_DIGESTFUNCTION)
-UNKNOWN = 0
-SHA256 = 1
-SHA1 = 2
-MD5 = 3
-
+_sym_db.RegisterEnumDescriptor(_EXECUTIONSTAGE_VALUE)
 
-_EXECUTEOPERATIONMETADATA_STAGE = _descriptor.EnumDescriptor(
-  name='Stage',
-  full_name='build.bazel.remote.execution.v2.ExecuteOperationMetadata.Stage',
+_DIGESTFUNCTION_VALUE = _descriptor.EnumDescriptor(
+  name='Value',
+  full_name='build.bazel.remote.execution.v2.DigestFunction.Value',
   filename=None,
   file=DESCRIPTOR,
   values=[
@@ -79,32 +77,40 @@ _EXECUTEOPERATIONMETADATA_STAGE = _descriptor.EnumDescriptor(
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='CACHE_CHECK', index=1, number=1,
+      name='SHA256', index=1, number=1,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='QUEUED', index=2, number=2,
+      name='SHA1', index=2, number=2,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='EXECUTING', index=3, number=3,
+      name='MD5', index=3, number=3,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='COMPLETED', index=4, number=4,
+      name='VSO', index=4, number=4,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SHA384', index=5, number=5,
+      serialized_options=None,
+      type=None),
+    _descriptor.EnumValueDescriptor(
+      name='SHA512', index=6, number=6,
       serialized_options=None,
       type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=3866,
-  serialized_end=3945,
+  serialized_start=6893,
+  serialized_end=6977,
 )
-_sym_db.RegisterEnumDescriptor(_EXECUTEOPERATIONMETADATA_STAGE)
+_sym_db.RegisterEnumDescriptor(_DIGESTFUNCTION_VALUE)
 
-_CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY = _descriptor.EnumDescriptor(
-  name='SymlinkAbsolutePathStrategy',
-  full_name='build.bazel.remote.execution.v2.CacheCapabilities.SymlinkAbsolutePathStrategy',
+_SYMLINKABSOLUTEPATHSTRATEGY_VALUE = _descriptor.EnumDescriptor(
+  name='Value',
+  full_name='build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy.Value',
   filename=None,
   file=DESCRIPTOR,
   values=[
@@ -123,10 +129,10 @@ _CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY = _descriptor.EnumDescriptor(
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=6696,
-  serialized_end=6767,
+  serialized_start=7242,
+  serialized_end=7291,
 )
-_sym_db.RegisterEnumDescriptor(_CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY)
+_sym_db.RegisterEnumDescriptor(_SYMLINKABSOLUTEPATHSTRATEGY_VALUE)
 
 
 _ACTION = _descriptor.Descriptor(
@@ -164,6 +170,13 @@ _ACTION = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='output_node_properties', full_name='build.bazel.remote.execution.v2.Action.output_node_properties', index=4,
+      number=8, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -177,7 +190,7 @@ _ACTION = _descriptor.Descriptor(
   oneofs=[
   ],
   serialized_start=282,
-  serialized_end=495,
+  serialized_end=527,
 )
 
 
@@ -214,8 +227,8 @@ _COMMAND_ENVIRONMENTVARIABLE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=759,
-  serialized_end=809,
+  serialized_start=813,
+  serialized_end=863,
 )
 
 _COMMAND = _descriptor.Descriptor(
@@ -254,14 +267,21 @@ _COMMAND = _descriptor.Descriptor(
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='platform', full_name='build.bazel.remote.execution.v2.Command.platform', index=4,
+      name='output_paths', full_name='build.bazel.remote.execution.v2.Command.output_paths', index=4,
+      number=7, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='platform', full_name='build.bazel.remote.execution.v2.Command.platform', index=5,
       number=5, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='working_directory', full_name='build.bazel.remote.execution.v2.Command.working_directory', index=5,
+      name='working_directory', full_name='build.bazel.remote.execution.v2.Command.working_directory', index=6,
       number=6, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=_b("").decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
@@ -279,8 +299,8 @@ _COMMAND = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=498,
-  serialized_end=809,
+  serialized_start=530,
+  serialized_end=863,
 )
 
 
@@ -317,8 +337,8 @@ _PLATFORM_PROPERTY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=895,
-  serialized_end=934,
+  serialized_start=949,
+  serialized_end=988,
 )
 
 _PLATFORM = _descriptor.Descriptor(
@@ -347,8 +367,8 @@ _PLATFORM = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=811,
-  serialized_end=934,
+  serialized_start=865,
+  serialized_end=988,
 )
 
 
@@ -380,6 +400,13 @@ _DIRECTORY = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='node_properties', full_name='build.bazel.remote.execution.v2.Directory.node_properties', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -392,8 +419,46 @@ _DIRECTORY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=937,
-  serialized_end=1139,
+  serialized_start=991,
+  serialized_end=1265,
+)
+
+
+_NODEPROPERTY = _descriptor.Descriptor(
+  name='NodeProperty',
+  full_name='build.bazel.remote.execution.v2.NodeProperty',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='build.bazel.remote.execution.v2.NodeProperty.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='build.bazel.remote.execution.v2.NodeProperty.value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1267,
+  serialized_end=1310,
 )
 
 
@@ -425,6 +490,13 @@ _FILENODE = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='node_properties', full_name='build.bazel.remote.execution.v2.FileNode.node_properties', index=3,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -437,8 +509,8 @@ _FILENODE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1141,
-  serialized_end=1251,
+  serialized_start=1313,
+  serialized_end=1495,
 )
 
 
@@ -475,8 +547,8 @@ _DIRECTORYNODE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1253,
-  serialized_end=1339,
+  serialized_start=1497,
+  serialized_end=1583,
 )
 
 
@@ -501,6 +573,13 @@ _SYMLINKNODE = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='node_properties', full_name='build.bazel.remote.execution.v2.SymlinkNode.node_properties', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -513,8 +592,8 @@ _SYMLINKNODE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1341,
-  serialized_end=1384,
+  serialized_start=1585,
+  serialized_end=1700,
 )
 
 
@@ -551,8 +630,8 @@ _DIGEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1386,
-  serialized_end=1428,
+  serialized_start=1702,
+  serialized_end=1744,
 )
 
 
@@ -645,8 +724,8 @@ _EXECUTEDACTIONMETADATA = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1431,
-  serialized_end=2051,
+  serialized_start=1747,
+  serialized_end=2367,
 )
 
 
@@ -665,49 +744,70 @@ _ACTIONRESULT = _descriptor.Descriptor(
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='output_directories', full_name='build.bazel.remote.execution.v2.ActionResult.output_directories', index=1,
+      name='output_file_symlinks', full_name='build.bazel.remote.execution.v2.ActionResult.output_file_symlinks', index=1,
+      number=10, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='output_symlinks', full_name='build.bazel.remote.execution.v2.ActionResult.output_symlinks', index=2,
+      number=12, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='output_directories', full_name='build.bazel.remote.execution.v2.ActionResult.output_directories', index=3,
       number=3, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='exit_code', full_name='build.bazel.remote.execution.v2.ActionResult.exit_code', index=2,
+      name='output_directory_symlinks', full_name='build.bazel.remote.execution.v2.ActionResult.output_directory_symlinks', index=4,
+      number=11, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='exit_code', full_name='build.bazel.remote.execution.v2.ActionResult.exit_code', index=5,
       number=4, type=5, cpp_type=1, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='stdout_raw', full_name='build.bazel.remote.execution.v2.ActionResult.stdout_raw', index=3,
+      name='stdout_raw', full_name='build.bazel.remote.execution.v2.ActionResult.stdout_raw', index=6,
       number=5, type=12, cpp_type=9, label=1,
       has_default_value=False, default_value=_b(""),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='stdout_digest', full_name='build.bazel.remote.execution.v2.ActionResult.stdout_digest', index=4,
+      name='stdout_digest', full_name='build.bazel.remote.execution.v2.ActionResult.stdout_digest', index=7,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='stderr_raw', full_name='build.bazel.remote.execution.v2.ActionResult.stderr_raw', index=5,
+      name='stderr_raw', full_name='build.bazel.remote.execution.v2.ActionResult.stderr_raw', index=8,
       number=7, type=12, cpp_type=9, label=1,
       has_default_value=False, default_value=_b(""),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='stderr_digest', full_name='build.bazel.remote.execution.v2.ActionResult.stderr_digest', index=6,
+      name='stderr_digest', full_name='build.bazel.remote.execution.v2.ActionResult.stderr_digest', index=9,
       number=8, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
     _descriptor.FieldDescriptor(
-      name='execution_metadata', full_name='build.bazel.remote.execution.v2.ActionResult.execution_metadata', index=7,
+      name='execution_metadata', full_name='build.bazel.remote.execution.v2.ActionResult.execution_metadata', index=10,
       number=9, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
@@ -725,8 +825,8 @@ _ACTIONRESULT = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2054,
-  serialized_end=2491,
+  serialized_start=2370,
+  serialized_end=3041,
 )
 
 
@@ -758,6 +858,20 @@ _OUTPUTFILE = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='contents', full_name='build.bazel.remote.execution.v2.OutputFile.contents', index=3,
+      number=5, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b(""),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='node_properties', full_name='build.bazel.remote.execution.v2.OutputFile.node_properties', index=4,
+      number=6, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -770,8 +884,8 @@ _OUTPUTFILE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2493,
-  serialized_end=2605,
+  serialized_start=3044,
+  serialized_end=3246,
 )
 
 
@@ -808,8 +922,8 @@ _TREE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2607,
-  serialized_end=2733,
+  serialized_start=3248,
+  serialized_end=3374,
 )
 
 
@@ -846,8 +960,53 @@ _OUTPUTDIRECTORY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2735,
-  serialized_end=2834,
+  serialized_start=3376,
+  serialized_end=3475,
+)
+
+
+_OUTPUTSYMLINK = _descriptor.Descriptor(
+  name='OutputSymlink',
+  full_name='build.bazel.remote.execution.v2.OutputSymlink',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='path', full_name='build.bazel.remote.execution.v2.OutputSymlink.path', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='target', full_name='build.bazel.remote.execution.v2.OutputSymlink.target', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='node_properties', full_name='build.bazel.remote.execution.v2.OutputSymlink.node_properties', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=3477,
+  serialized_end=3594,
 )
 
 
@@ -877,8 +1036,8 @@ _EXECUTIONPOLICY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2836,
-  serialized_end=2871,
+  serialized_start=3596,
+  serialized_end=3631,
 )
 
 
@@ -908,8 +1067,8 @@ _RESULTSCACHEPOLICY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2873,
-  serialized_end=2911,
+  serialized_start=3633,
+  serialized_end=3671,
 )
 
 
@@ -967,8 +1126,8 @@ _EXECUTEREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2914,
-  serialized_end=3221,
+  serialized_start=3674,
+  serialized_end=3981,
 )
 
 
@@ -1005,8 +1164,8 @@ _LOGFILE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3223,
-  serialized_end=3313,
+  serialized_start=3983,
+  serialized_end=4073,
 )
 
 
@@ -1043,8 +1202,8 @@ _EXECUTERESPONSE_SERVERLOGSENTRY = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3544,
-  serialized_end=3635,
+  serialized_start=4321,
+  serialized_end=4412,
 )
 
 _EXECUTERESPONSE = _descriptor.Descriptor(
@@ -1082,6 +1241,13 @@ _EXECUTERESPONSE = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='message', full_name='build.bazel.remote.execution.v2.ExecuteResponse.message', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1094,8 +1260,33 @@ _EXECUTERESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3316,
-  serialized_end=3635,
+  serialized_start=4076,
+  serialized_end=4412,
+)
+
+
+_EXECUTIONSTAGE = _descriptor.Descriptor(
+  name='ExecutionStage',
+  full_name='build.bazel.remote.execution.v2.ExecutionStage',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _EXECUTIONSTAGE_VALUE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=4414,
+  serialized_end=4511,
 )
 
 
@@ -1139,7 +1330,6 @@ _EXECUTEOPERATIONMETADATA = _descriptor.Descriptor(
   ],
   nested_types=[],
   enum_types=[
-    _EXECUTEOPERATIONMETADATA_STAGE,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1147,8 +1337,8 @@ _EXECUTEOPERATIONMETADATA = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3638,
-  serialized_end=3945,
+  serialized_start=4514,
+  serialized_end=4730,
 )
 
 
@@ -1178,8 +1368,8 @@ _WAITEXECUTIONREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3947,
-  serialized_end=3983,
+  serialized_start=4732,
+  serialized_end=4768,
 )
 
 
@@ -1204,6 +1394,27 @@ _GETACTIONRESULTREQUEST = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='inline_stdout', full_name='build.bazel.remote.execution.v2.GetActionResultRequest.inline_stdout', index=2,
+      number=3, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='inline_stderr', full_name='build.bazel.remote.execution.v2.GetActionResultRequest.inline_stderr', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='inline_output_files', full_name='build.bazel.remote.execution.v2.GetActionResultRequest.inline_output_files', index=4,
+      number=5, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1216,8 +1427,8 @@ _GETACTIONRESULTREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=3985,
-  serialized_end=4096,
+  serialized_start=4771,
+  serialized_end=4957,
 )
 
 
@@ -1268,8 +1479,8 @@ _UPDATEACTIONRESULTREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4099,
-  serialized_end=4366,
+  serialized_start=4960,
+  serialized_end=5227,
 )
 
 
@@ -1306,8 +1517,8 @@ _FINDMISSINGBLOBSREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4368,
-  serialized_end=4479,
+  serialized_start=5229,
+  serialized_end=5340,
 )
 
 
@@ -1337,8 +1548,8 @@ _FINDMISSINGBLOBSRESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4481,
-  serialized_end=4578,
+  serialized_start=5342,
+  serialized_end=5439,
 )
 
 
@@ -1375,8 +1586,8 @@ _BATCHUPDATEBLOBSREQUEST_REQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4715,
-  serialized_end=4795,
+  serialized_start=5576,
+  serialized_end=5656,
 )
 
 _BATCHUPDATEBLOBSREQUEST = _descriptor.Descriptor(
@@ -1412,8 +1623,8 @@ _BATCHUPDATEBLOBSREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4581,
-  serialized_end=4795,
+  serialized_start=5442,
+  serialized_end=5656,
 )
 
 
@@ -1450,8 +1661,8 @@ _BATCHUPDATEBLOBSRESPONSE_RESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4913,
-  serialized_end=5016,
+  serialized_start=5774,
+  serialized_end=5877,
 )
 
 _BATCHUPDATEBLOBSRESPONSE = _descriptor.Descriptor(
@@ -1480,8 +1691,8 @@ _BATCHUPDATEBLOBSRESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=4798,
-  serialized_end=5016,
+  serialized_start=5659,
+  serialized_end=5877,
 )
 
 
@@ -1518,8 +1729,8 @@ _BATCHREADBLOBSREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5018,
-  serialized_end=5122,
+  serialized_start=5879,
+  serialized_end=5983,
 )
 
 
@@ -1563,8 +1774,8 @@ _BATCHREADBLOBSRESPONSE_RESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5236,
-  serialized_end=5353,
+  serialized_start=6097,
+  serialized_end=6214,
 )
 
 _BATCHREADBLOBSRESPONSE = _descriptor.Descriptor(
@@ -1593,8 +1804,8 @@ _BATCHREADBLOBSRESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5125,
-  serialized_end=5353,
+  serialized_start=5986,
+  serialized_end=6214,
 )
 
 
@@ -1645,8 +1856,8 @@ _GETTREEREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5356,
-  serialized_end=5496,
+  serialized_start=6217,
+  serialized_end=6357,
 )
 
 
@@ -1683,8 +1894,8 @@ _GETTREERESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5498,
-  serialized_end=5605,
+  serialized_start=6359,
+  serialized_end=6466,
 )
 
 
@@ -1714,8 +1925,8 @@ _GETCAPABILITIESREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5607,
-  serialized_end=5654,
+  serialized_start=6468,
+  serialized_end=6515,
 )
 
 
@@ -1773,8 +1984,33 @@ _SERVERCAPABILITIES = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=5657,
-  serialized_end=6012,
+  serialized_start=6518,
+  serialized_end=6873,
+)
+
+
+_DIGESTFUNCTION = _descriptor.Descriptor(
+  name='DigestFunction',
+  full_name='build.bazel.remote.execution.v2.DigestFunction',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _DIGESTFUNCTION_VALUE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=6875,
+  serialized_end=6977,
 )
 
 
@@ -1804,8 +2040,8 @@ _ACTIONCACHEUPDATECAPABILITIES = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6014,
-  serialized_end=6069,
+  serialized_start=6979,
+  serialized_end=7034,
 )
 
 
@@ -1842,8 +2078,8 @@ _PRIORITYCAPABILITIES_PRIORITYRANGE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6185,
-  serialized_end=6244,
+  serialized_start=7150,
+  serialized_end=7209,
 )
 
 _PRIORITYCAPABILITIES = _descriptor.Descriptor(
@@ -1872,8 +2108,33 @@ _PRIORITYCAPABILITIES = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6072,
-  serialized_end=6244,
+  serialized_start=7037,
+  serialized_end=7209,
+)
+
+
+_SYMLINKABSOLUTEPATHSTRATEGY = _descriptor.Descriptor(
+  name='SymlinkAbsolutePathStrategy',
+  full_name='build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _SYMLINKABSOLUTEPATHSTRATEGY_VALUE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=7211,
+  serialized_end=7291,
 )
 
 
@@ -1924,7 +2185,6 @@ _CACHECAPABILITIES = _descriptor.Descriptor(
   ],
   nested_types=[],
   enum_types=[
-    _CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -1932,8 +2192,8 @@ _CACHECAPABILITIES = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6247,
-  serialized_end=6767,
+  serialized_start=7294,
+  serialized_end=7735,
 )
 
 
@@ -1965,6 +2225,13 @@ _EXECUTIONCAPABILITIES = _descriptor.Descriptor(
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='supported_node_properties', full_name='build.bazel.remote.execution.v2.ExecutionCapabilities.supported_node_properties', index=3,
+      number=4, type=9, cpp_type=9, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -1977,8 +2244,8 @@ _EXECUTIONCAPABILITIES = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6770,
-  serialized_end=6985,
+  serialized_start=7738,
+  serialized_end=7994,
 )
 
 
@@ -2015,8 +2282,8 @@ _TOOLDETAILS = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=6987,
-  serialized_end=7041,
+  serialized_start=7996,
+  serialized_end=8050,
 )
 
 
@@ -2067,8 +2334,8 @@ _REQUESTMETADATA = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7044,
-  serialized_end=7211,
+  serialized_start=8053,
+  serialized_end=8220,
 )
 
 _ACTION.fields_by_name['command_digest'].message_type = _DIGEST
@@ -2082,8 +2349,11 @@ _PLATFORM.fields_by_name['properties'].message_type = _PLATFORM_PROPERTY
 _DIRECTORY.fields_by_name['files'].message_type = _FILENODE
 _DIRECTORY.fields_by_name['directories'].message_type = _DIRECTORYNODE
 _DIRECTORY.fields_by_name['symlinks'].message_type = _SYMLINKNODE
+_DIRECTORY.fields_by_name['node_properties'].message_type = _NODEPROPERTY
 _FILENODE.fields_by_name['digest'].message_type = _DIGEST
+_FILENODE.fields_by_name['node_properties'].message_type = _NODEPROPERTY
 _DIRECTORYNODE.fields_by_name['digest'].message_type = _DIGEST
+_SYMLINKNODE.fields_by_name['node_properties'].message_type = _NODEPROPERTY
 _EXECUTEDACTIONMETADATA.fields_by_name['queued_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _EXECUTEDACTIONMETADATA.fields_by_name['worker_start_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _EXECUTEDACTIONMETADATA.fields_by_name['worker_completed_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
@@ -2094,14 +2364,19 @@ _EXECUTEDACTIONMETADATA.fields_by_name['execution_completed_timestamp'].message_
 _EXECUTEDACTIONMETADATA.fields_by_name['output_upload_start_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _EXECUTEDACTIONMETADATA.fields_by_name['output_upload_completed_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
 _ACTIONRESULT.fields_by_name['output_files'].message_type = _OUTPUTFILE
+_ACTIONRESULT.fields_by_name['output_file_symlinks'].message_type = _OUTPUTSYMLINK
+_ACTIONRESULT.fields_by_name['output_symlinks'].message_type = _OUTPUTSYMLINK
 _ACTIONRESULT.fields_by_name['output_directories'].message_type = _OUTPUTDIRECTORY
+_ACTIONRESULT.fields_by_name['output_directory_symlinks'].message_type = _OUTPUTSYMLINK
 _ACTIONRESULT.fields_by_name['stdout_digest'].message_type = _DIGEST
 _ACTIONRESULT.fields_by_name['stderr_digest'].message_type = _DIGEST
 _ACTIONRESULT.fields_by_name['execution_metadata'].message_type = _EXECUTEDACTIONMETADATA
 _OUTPUTFILE.fields_by_name['digest'].message_type = _DIGEST
+_OUTPUTFILE.fields_by_name['node_properties'].message_type = _NODEPROPERTY
 _TREE.fields_by_name['root'].message_type = _DIRECTORY
 _TREE.fields_by_name['children'].message_type = _DIRECTORY
 _OUTPUTDIRECTORY.fields_by_name['tree_digest'].message_type = _DIGEST
+_OUTPUTSYMLINK.fields_by_name['node_properties'].message_type = _NODEPROPERTY
 _EXECUTEREQUEST.fields_by_name['action_digest'].message_type = _DIGEST
 _EXECUTEREQUEST.fields_by_name['execution_policy'].message_type = _EXECUTIONPOLICY
 _EXECUTEREQUEST.fields_by_name['results_cache_policy'].message_type = _RESULTSCACHEPOLICY
@@ -2111,9 +2386,9 @@ _EXECUTERESPONSE_SERVERLOGSENTRY.containing_type = _EXECUTERESPONSE
 _EXECUTERESPONSE.fields_by_name['result'].message_type = _ACTIONRESULT
 _EXECUTERESPONSE.fields_by_name['status'].message_type = google_dot_rpc_dot_status__pb2._STATUS
 _EXECUTERESPONSE.fields_by_name['server_logs'].message_type = _EXECUTERESPONSE_SERVERLOGSENTRY
-_EXECUTEOPERATIONMETADATA.fields_by_name['stage'].enum_type = _EXECUTEOPERATIONMETADATA_STAGE
+_EXECUTIONSTAGE_VALUE.containing_type = _EXECUTIONSTAGE
+_EXECUTEOPERATIONMETADATA.fields_by_name['stage'].enum_type = _EXECUTIONSTAGE_VALUE
 _EXECUTEOPERATIONMETADATA.fields_by_name['action_digest'].message_type = _DIGEST
-_EXECUTEOPERATIONMETADATA_STAGE.containing_type = _EXECUTEOPERATIONMETADATA
 _GETACTIONRESULTREQUEST.fields_by_name['action_digest'].message_type = _DIGEST
 _UPDATEACTIONRESULTREQUEST.fields_by_name['action_digest'].message_type = _DIGEST
 _UPDATEACTIONRESULTREQUEST.fields_by_name['action_result'].message_type = _ACTIONRESULT
@@ -2139,20 +2414,22 @@ _SERVERCAPABILITIES.fields_by_name['execution_capabilities'].message_type = _EXE
 _SERVERCAPABILITIES.fields_by_name['deprecated_api_version'].message_type = build_dot_bazel_dot_semver_dot_semver__pb2._SEMVER
 _SERVERCAPABILITIES.fields_by_name['low_api_version'].message_type = build_dot_bazel_dot_semver_dot_semver__pb2._SEMVER
 _SERVERCAPABILITIES.fields_by_name['high_api_version'].message_type = build_dot_bazel_dot_semver_dot_semver__pb2._SEMVER
+_DIGESTFUNCTION_VALUE.containing_type = _DIGESTFUNCTION
 _PRIORITYCAPABILITIES_PRIORITYRANGE.containing_type = _PRIORITYCAPABILITIES
 _PRIORITYCAPABILITIES.fields_by_name['priorities'].message_type = _PRIORITYCAPABILITIES_PRIORITYRANGE
-_CACHECAPABILITIES.fields_by_name['digest_function'].enum_type = _DIGESTFUNCTION
+_SYMLINKABSOLUTEPATHSTRATEGY_VALUE.containing_type = _SYMLINKABSOLUTEPATHSTRATEGY
+_CACHECAPABILITIES.fields_by_name['digest_function'].enum_type = _DIGESTFUNCTION_VALUE
 _CACHECAPABILITIES.fields_by_name['action_cache_update_capabilities'].message_type = _ACTIONCACHEUPDATECAPABILITIES
 _CACHECAPABILITIES.fields_by_name['cache_priority_capabilities'].message_type = _PRIORITYCAPABILITIES
-_CACHECAPABILITIES.fields_by_name['symlink_absolute_path_strategy'].enum_type = _CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY
-_CACHECAPABILITIES_SYMLINKABSOLUTEPATHSTRATEGY.containing_type = _CACHECAPABILITIES
-_EXECUTIONCAPABILITIES.fields_by_name['digest_function'].enum_type = _DIGESTFUNCTION
+_CACHECAPABILITIES.fields_by_name['symlink_absolute_path_strategy'].enum_type = _SYMLINKABSOLUTEPATHSTRATEGY_VALUE
+_EXECUTIONCAPABILITIES.fields_by_name['digest_function'].enum_type = _DIGESTFUNCTION_VALUE
 _EXECUTIONCAPABILITIES.fields_by_name['execution_priority_capabilities'].message_type = _PRIORITYCAPABILITIES
 _REQUESTMETADATA.fields_by_name['tool_details'].message_type = _TOOLDETAILS
 DESCRIPTOR.message_types_by_name['Action'] = _ACTION
 DESCRIPTOR.message_types_by_name['Command'] = _COMMAND
 DESCRIPTOR.message_types_by_name['Platform'] = _PLATFORM
 DESCRIPTOR.message_types_by_name['Directory'] = _DIRECTORY
+DESCRIPTOR.message_types_by_name['NodeProperty'] = _NODEPROPERTY
 DESCRIPTOR.message_types_by_name['FileNode'] = _FILENODE
 DESCRIPTOR.message_types_by_name['DirectoryNode'] = _DIRECTORYNODE
 DESCRIPTOR.message_types_by_name['SymlinkNode'] = _SYMLINKNODE
@@ -2162,11 +2439,13 @@ DESCRIPTOR.message_types_by_name['ActionResult'] = _ACTIONRESULT
 DESCRIPTOR.message_types_by_name['OutputFile'] = _OUTPUTFILE
 DESCRIPTOR.message_types_by_name['Tree'] = _TREE
 DESCRIPTOR.message_types_by_name['OutputDirectory'] = _OUTPUTDIRECTORY
+DESCRIPTOR.message_types_by_name['OutputSymlink'] = _OUTPUTSYMLINK
 DESCRIPTOR.message_types_by_name['ExecutionPolicy'] = _EXECUTIONPOLICY
 DESCRIPTOR.message_types_by_name['ResultsCachePolicy'] = _RESULTSCACHEPOLICY
 DESCRIPTOR.message_types_by_name['ExecuteRequest'] = _EXECUTEREQUEST
 DESCRIPTOR.message_types_by_name['LogFile'] = _LOGFILE
 DESCRIPTOR.message_types_by_name['ExecuteResponse'] = _EXECUTERESPONSE
+DESCRIPTOR.message_types_by_name['ExecutionStage'] = _EXECUTIONSTAGE
 DESCRIPTOR.message_types_by_name['ExecuteOperationMetadata'] = _EXECUTEOPERATIONMETADATA
 DESCRIPTOR.message_types_by_name['WaitExecutionRequest'] = _WAITEXECUTIONREQUEST
 DESCRIPTOR.message_types_by_name['GetActionResultRequest'] = _GETACTIONRESULTREQUEST
@@ -2181,13 +2460,14 @@ DESCRIPTOR.message_types_by_name['GetTreeRequest'] = _GETTREEREQUEST
 DESCRIPTOR.message_types_by_name['GetTreeResponse'] = _GETTREERESPONSE
 DESCRIPTOR.message_types_by_name['GetCapabilitiesRequest'] = _GETCAPABILITIESREQUEST
 DESCRIPTOR.message_types_by_name['ServerCapabilities'] = _SERVERCAPABILITIES
+DESCRIPTOR.message_types_by_name['DigestFunction'] = _DIGESTFUNCTION
 DESCRIPTOR.message_types_by_name['ActionCacheUpdateCapabilities'] = _ACTIONCACHEUPDATECAPABILITIES
 DESCRIPTOR.message_types_by_name['PriorityCapabilities'] = _PRIORITYCAPABILITIES
+DESCRIPTOR.message_types_by_name['SymlinkAbsolutePathStrategy'] = _SYMLINKABSOLUTEPATHSTRATEGY
 DESCRIPTOR.message_types_by_name['CacheCapabilities'] = _CACHECAPABILITIES
 DESCRIPTOR.message_types_by_name['ExecutionCapabilities'] = _EXECUTIONCAPABILITIES
 DESCRIPTOR.message_types_by_name['ToolDetails'] = _TOOLDETAILS
 DESCRIPTOR.message_types_by_name['RequestMetadata'] = _REQUESTMETADATA
-DESCRIPTOR.enum_types_by_name['DigestFunction'] = _DIGESTFUNCTION
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 Action = _reflection.GeneratedProtocolMessageType('Action', (_message.Message,), {
@@ -2234,6 +2514,13 @@ Directory = _reflection.GeneratedProtocolMessageType('Directory', (_message.Mess
   })
 _sym_db.RegisterMessage(Directory)
 
+NodeProperty = _reflection.GeneratedProtocolMessageType('NodeProperty', (_message.Message,), {
+  'DESCRIPTOR' : _NODEPROPERTY,
+  '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
+  # @@protoc_insertion_point(class_scope:build.bazel.remote.execution.v2.NodeProperty)
+  })
+_sym_db.RegisterMessage(NodeProperty)
+
 FileNode = _reflection.GeneratedProtocolMessageType('FileNode', (_message.Message,), {
   'DESCRIPTOR' : _FILENODE,
   '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
@@ -2297,6 +2584,13 @@ OutputDirectory = _reflection.GeneratedProtocolMessageType('OutputDirectory', (_
   })
 _sym_db.RegisterMessage(OutputDirectory)
 
+OutputSymlink = _reflection.GeneratedProtocolMessageType('OutputSymlink', (_message.Message,), {
+  'DESCRIPTOR' : _OUTPUTSYMLINK,
+  '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
+  # @@protoc_insertion_point(class_scope:build.bazel.remote.execution.v2.OutputSymlink)
+  })
+_sym_db.RegisterMessage(OutputSymlink)
+
 ExecutionPolicy = _reflection.GeneratedProtocolMessageType('ExecutionPolicy', (_message.Message,), {
   'DESCRIPTOR' : _EXECUTIONPOLICY,
   '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
@@ -2340,6 +2634,13 @@ ExecuteResponse = _reflection.GeneratedProtocolMessageType('ExecuteResponse', (_
 _sym_db.RegisterMessage(ExecuteResponse)
 _sym_db.RegisterMessage(ExecuteResponse.ServerLogsEntry)
 
+ExecutionStage = _reflection.GeneratedProtocolMessageType('ExecutionStage', (_message.Message,), {
+  'DESCRIPTOR' : _EXECUTIONSTAGE,
+  '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
+  # @@protoc_insertion_point(class_scope:build.bazel.remote.execution.v2.ExecutionStage)
+  })
+_sym_db.RegisterMessage(ExecutionStage)
+
 ExecuteOperationMetadata = _reflection.GeneratedProtocolMessageType('ExecuteOperationMetadata', (_message.Message,), {
   'DESCRIPTOR' : _EXECUTEOPERATIONMETADATA,
   '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
@@ -2462,6 +2763,13 @@ ServerCapabilities = _reflection.GeneratedProtocolMessageType('ServerCapabilitie
   })
 _sym_db.RegisterMessage(ServerCapabilities)
 
+DigestFunction = _reflection.GeneratedProtocolMessageType('DigestFunction', (_message.Message,), {
+  'DESCRIPTOR' : _DIGESTFUNCTION,
+  '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
+  # @@protoc_insertion_point(class_scope:build.bazel.remote.execution.v2.DigestFunction)
+  })
+_sym_db.RegisterMessage(DigestFunction)
+
 ActionCacheUpdateCapabilities = _reflection.GeneratedProtocolMessageType('ActionCacheUpdateCapabilities', (_message.Message,), {
   'DESCRIPTOR' : _ACTIONCACHEUPDATECAPABILITIES,
   '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
@@ -2484,6 +2792,13 @@ PriorityCapabilities = _reflection.GeneratedProtocolMessageType('PriorityCapabil
 _sym_db.RegisterMessage(PriorityCapabilities)
 _sym_db.RegisterMessage(PriorityCapabilities.PriorityRange)
 
+SymlinkAbsolutePathStrategy = _reflection.GeneratedProtocolMessageType('SymlinkAbsolutePathStrategy', (_message.Message,), {
+  'DESCRIPTOR' : _SYMLINKABSOLUTEPATHSTRATEGY,
+  '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
+  # @@protoc_insertion_point(class_scope:build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy)
+  })
+_sym_db.RegisterMessage(SymlinkAbsolutePathStrategy)
+
 CacheCapabilities = _reflection.GeneratedProtocolMessageType('CacheCapabilities', (_message.Message,), {
   'DESCRIPTOR' : _CACHECAPABILITIES,
   '__module__' : 'build.bazel.remote.execution.v2.remote_execution_pb2'
@@ -2522,8 +2837,8 @@ _EXECUTION = _descriptor.ServiceDescriptor(
   file=DESCRIPTOR,
   index=0,
   serialized_options=None,
-  serialized_start=7276,
-  serialized_end=7589,
+  serialized_start=8223,
+  serialized_end=8536,
   methods=[
   _descriptor.MethodDescriptor(
     name='Execute',
@@ -2555,8 +2870,8 @@ _ACTIONCACHE = _descriptor.ServiceDescriptor(
   file=DESCRIPTOR,
   index=1,
   serialized_options=None,
-  serialized_start=7592,
-  serialized_end=8062,
+  serialized_start=8539,
+  serialized_end=9009,
   methods=[
   _descriptor.MethodDescriptor(
     name='GetActionResult',
@@ -2588,8 +2903,8 @@ _CONTENTADDRESSABLESTORAGE = _descriptor.ServiceDescriptor(
   file=DESCRIPTOR,
   index=2,
   serialized_options=None,
-  serialized_start=8065,
-  serialized_end=8860,
+  serialized_start=9012,
+  serialized_end=9807,
   methods=[
   _descriptor.MethodDescriptor(
     name='FindMissingBlobs',
@@ -2639,8 +2954,8 @@ _CAPABILITIES = _descriptor.ServiceDescriptor(
   file=DESCRIPTOR,
   index=3,
   serialized_options=None,
-  serialized_start=8863,
-  serialized_end=9052,
+  serialized_start=9810,
+  serialized_end=9999,
   methods=[
   _descriptor.MethodDescriptor(
     name='GetCapabilities',
diff --git a/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2_grpc.py b/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2_grpc.py
index 3769a68..5a30549 100644
--- a/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2_grpc.py
+++ b/src/buildstream/_protos/build/bazel/remote/execution/v2/remote_execution_pb2_grpc.py
@@ -87,6 +87,7 @@ class ExecutionServicer(object):
     action will be reported in the `status` field of the `ExecuteResponse`. The
     server MUST NOT set the `error` field of the `Operation` proto.
     The possible errors include:
+
     * `INVALID_ARGUMENT`: One or more arguments are invalid.
     * `FAILED_PRECONDITION`: One or more errors occurred in setting up the
     action requested, such as a missing input or command or no worker being
@@ -99,6 +100,9 @@ class ExecutionServicer(object):
     * `INTERNAL`: An internal error occurred in the execution engine or the
     worker.
     * `DEADLINE_EXCEEDED`: The execution timed out.
+    * `CANCELLED`: The operation was cancelled by the client. This status is
+    only possible if the server implements the Operations API CancelOperation
+    method, and it was called for the current execution.
 
     In the case of a missing input or command, the server SHOULD additionally
     send a [PreconditionFailure][google.rpc.PreconditionFailure] error detail
@@ -152,10 +156,7 @@ class ActionCacheStub(object):
 
   The lifetime of entries in the action cache is implementation-specific, but
   the server SHOULD assume that more recently used entries are more likely to
-  be used again. Additionally, action cache implementations SHOULD ensure that
-  any blobs referenced in the
-  [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]
-  are still valid when returning a result.
+  be used again.
 
   As with other services in the Remote Execution API, any call may return an
   error with a [RetryInfo][google.rpc.RetryInfo] error detail providing
@@ -192,10 +193,7 @@ class ActionCacheServicer(object):
 
   The lifetime of entries in the action cache is implementation-specific, but
   the server SHOULD assume that more recently used entries are more likely to
-  be used again. Additionally, action cache implementations SHOULD ensure that
-  any blobs referenced in the
-  [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]
-  are still valid when returning a result.
+  be used again.
 
   As with other services in the Remote Execution API, any call may return an
   error with a [RetryInfo][google.rpc.RetryInfo] error detail providing
@@ -206,7 +204,15 @@ class ActionCacheServicer(object):
   def GetActionResult(self, request, context):
     """Retrieve a cached execution result.
 
+    Implementations SHOULD ensure that any blobs referenced from the
+    [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]
+    are available at the time of returning the
+    [ActionResult][build.bazel.remote.execution.v2.ActionResult] and will be
+    for some period of time afterwards. The TTLs of the referenced blobs SHOULD be increased
+    if necessary and applicable.
+
     Errors:
+
     * `NOT_FOUND`: The requested `ActionResult` is not in the cache.
     """
     context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -216,11 +222,6 @@ class ActionCacheServicer(object):
   def UpdateActionResult(self, request, context):
     """Upload a new execution result.
 
-    This method is intended for servers which implement the distributed cache
-    independently of the
-    [Execution][build.bazel.remote.execution.v2.Execution] API. As a
-    result, it is OPTIONAL for servers to implement.
-
     In order to allow the server to perform access control based on the type of
     action, and to assist with client debugging, the client MUST first upload
     the [Action][build.bazel.remote.execution.v2.Execution] that produced the
@@ -229,7 +230,10 @@ class ActionCacheServicer(object):
     `ContentAddressableStorage`.
 
     Errors:
-    * `NOT_IMPLEMENTED`: This method is not supported by the server.
+
+    * `INVALID_ARGUMENT`: One or more arguments are invalid.
+    * `FAILED_PRECONDITION`: One or more errors occurred in updating the
+    action result, such as a missing command or action.
     * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the
     entry to the cache.
     """
@@ -273,8 +277,8 @@ class ContentAddressableStorageStub(object):
   hierarchy, which must also each be uploaded on their own.
 
   For small file uploads the client should group them together and call
-  [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]
-  on chunks of no more than 10 MiB. For large uploads, the client must use the
+  [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs].
+  For large uploads, the client must use the
   [Write method][google.bytestream.ByteStream.Write] of the ByteStream API. The
   `resource_name` is `{instance_name}/uploads/{uuid}/blobs/{hash}/{size}`,
   where `instance_name` is as described in the next paragraph, `uuid` is a
@@ -296,6 +300,9 @@ class ContentAddressableStorageStub(object):
   by the server. For servers which do not support multiple instances, then the
   `instance_name` is the empty path and the leading slash is omitted, so that
   the `resource_name` becomes `uploads/{uuid}/blobs/{hash}/{size}`.
+  To simplify parsing, a path segment cannot equal any of the following
+  keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations` and
+  `capabilities`.
 
   When attempting an upload, if another client has already completed the upload
   (which may occur in the middle of a single upload if another client uploads
@@ -369,8 +376,8 @@ class ContentAddressableStorageServicer(object):
   hierarchy, which must also each be uploaded on their own.
 
   For small file uploads the client should group them together and call
-  [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]
-  on chunks of no more than 10 MiB. For large uploads, the client must use the
+  [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs].
+  For large uploads, the client must use the
   [Write method][google.bytestream.ByteStream.Write] of the ByteStream API. The
   `resource_name` is `{instance_name}/uploads/{uuid}/blobs/{hash}/{size}`,
   where `instance_name` is as described in the next paragraph, `uuid` is a
@@ -392,6 +399,9 @@ class ContentAddressableStorageServicer(object):
   by the server. For servers which do not support multiple instances, then the
   `instance_name` is the empty path and the leading slash is omitted, so that
   the `resource_name` becomes `uploads/{uuid}/blobs/{hash}/{size}`.
+  To simplify parsing, a path segment cannot equal any of the following
+  keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations` and
+  `capabilities`.
 
   When attempting an upload, if another client has already completed the upload
   (which may occur in the middle of a single upload if another client uploads
@@ -447,10 +457,12 @@ class ContentAddressableStorageServicer(object):
     independently.
 
     Errors:
+
     * `INVALID_ARGUMENT`: The client attempted to upload more than the
     server supported limit.
 
     Individual requests may return the following errors, additionally:
+
     * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob.
     * `INVALID_ARGUMENT`: The
     [Digest][build.bazel.remote.execution.v2.Digest] does not match the
@@ -475,6 +487,7 @@ class ContentAddressableStorageServicer(object):
     independently.
 
     Errors:
+
     * `INVALID_ARGUMENT`: The client attempted to read more than the
     server supported limit.
 
@@ -506,6 +519,8 @@ class ContentAddressableStorageServicer(object):
     If part of the tree is missing from the CAS, the server will return the
     portion present and omit the rest.
 
+    Errors:
+
     * `NOT_FOUND`: The requested tree root is not present in the CAS.
     """
     context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -573,7 +588,14 @@ class CapabilitiesServicer(object):
   """
 
   def GetCapabilities(self, request, context):
-    """GetCapabilities returns the server capabilities configuration.
+    """GetCapabilities returns the server capabilities configuration of the
+    remote endpoint.
+    Only the capabilities of the services supported by the endpoint will
+    be returned:
+    * Execution + CAS + Action Cache endpoints should return both
+    CacheCapabilities and ExecutionCapabilities.
+    * Execution only endpoints should return ExecutionCapabilities.
+    * CAS + Action Cache only endpoints should return CacheCapabilities.
     """
     context.set_code(grpc.StatusCode.UNIMPLEMENTED)
     context.set_details('Method not implemented!')