Workspaces
Workspaces — directories containing bldr-workspace.yml. CLI-side discovery happens first; the node only ever sees canonical absolute paths.
Workspaces — directories containing bldr-workspace.yml. CLI-side discovery
happens first; the node only ever sees canonical absolute paths.
Service builder.Workspaces, 12 rpcs.
RegisterWorkspace(RegisterWorkspaceRequest) -> RegisterWorkspaceResponse
Register a workspace (a directory with bldr-workspace.yml); returns the
canonical absolute path. Re-registering broadcasts a fresh status snapshot.
Request: RegisterWorkspaceRequest
message RegisterWorkspaceRequest {
optional string workspace_canonical_path = 1;
}Response: RegisterWorkspaceResponse
message RegisterWorkspaceResponse {
// no fields
}CreateWorkspace(CreateWorkspaceRequest) -> CreateWorkspaceResponse
Create a new bldr-workspace.yml at the path and register it. A
parentless workspace is created ready to build: the default controller
image becomes its build-controller member (tag resolved to the current
digest, pinned as content:) and the required build_controller option
selects it. Only the digest is resolved: the workspace is registered
without its initial member sync, so no image is downloaded here — the
first build syncs the members. With parent_cid the new config diffs over
that snapshot and inherits its controller. Fails if a config already
exists there (use RegisterWorkspace for an existing one).
Request: CreateWorkspaceRequest
message CreateWorkspaceRequest {
optional string workspace_canonical_path = 1;
optional string parent_cid = 2;
}| Field | |
|---|---|
workspace_canonical_path | |
parent_cid | Optional CID of a WorkspaceRevisionSnapshot to start from (the new config diffs over it). Empty starts from scratch. |
Response: CreateWorkspaceResponse
message CreateWorkspaceResponse {
optional string canonical_path = 1;
}| Field | |
|---|---|
canonical_path | The canonical path the workspace was registered under (navigate here). |
ListWorkspaces(ListWorkspacesRequest) -> ListWorkspacesResponse
Sorted list of all registered workspace paths.
Request: ListWorkspacesRequest
message ListWorkspacesRequest {
// no fields
}Response: ListWorkspacesResponse
message ListWorkspacesResponse {
repeated string paths = 1;
repeated WorkspaceSummary workspaces = 2;
}| Field | |
|---|---|
paths | Sorted list of registered workspace paths. |
workspaces | Per-workspace activity summary (same set as paths), so a client can show a live "working" indicator and sort by most-recently-active. |
DeregisterWorkspace(DeregisterWorkspaceRequest) -> DeregisterWorkspaceResponse
Drop a workspace. Open WatchWorkspaceStatus streams for it terminate.
Request: DeregisterWorkspaceRequest
message DeregisterWorkspaceRequest {
optional string workspace_canonical_path = 1;
}Response: DeregisterWorkspaceResponse
message DeregisterWorkspaceResponse {
optional bool was_registered = 1;
}| Field | |
|---|---|
was_registered | False if the path wasn't registered. |
GetWorkspaceStatus(GetWorkspaceStatusRequest) -> WorkspaceStatusResponse
Read a fresh status snapshot (config re-read + re-validated on each call).
Request: GetWorkspaceStatusRequest
message GetWorkspaceStatusRequest {
optional string workspace_canonical_path = 1;
}Response: WorkspaceStatusResponse
message WorkspaceStatusResponse {
optional string path = 1;
optional int64 registered_at_seconds = 2;
repeated DiagnosticMessage diagnostics = 5;
repeated MemberFetch members = 6;
optional string build_input_cid = 7;
optional string parent_cid = 9;
optional string revision_cid = 10;
repeated WorkspaceSequence sequences = 11;
oneof _config_present {
bool config_present = 3;
}
oneof _config_yaml {
string config_yaml = 4;
}
oneof _options_json {
string options_json = 8;
}
}| Field | |
|---|---|
path | |
registered_at_seconds | Unix seconds at which the workspace was first registered. Unchanged across re-registrations of the same path. |
config_present | Whether bldr-workspace.yml was readable at status time. |
config_yaml | The workspace config re-serialised back to YAML. Absent when the file is missing or unparseable. |
diagnostics | Parse / validation / filesystem-mismatch diagnostics. Empty when the config is valid and every member resolves to an existing directory. |
members | Per-member fetch state. Empty until the first workspace fetch (or initial fetch after registration) has resolved at least one entry. |
build_input_cid | CID of the BuildInput object assembled from the current member set and stored in local storage. Empty until at least one member has synced successfully. Regenerated on every sync. |
options_json | The workspace options map as a JSON object, for structured editing by a client (the build_controller selection lives here too). Absent when the config is missing or unparseable. Edit with UpdateWorkspace. |
parent_cid | CID of the parent WorkspaceRevisionSnapshot this config is a diff over (parent: in the config), if declared. Empty when the config has no parent. |
revision_cid | CID of the committed WorkspaceRevisionSnapshot for the current merged, fully-resolved member set — the snapshot that is synced and built. Empty until the first successful sync; regenerated each sync. |
sequences | The workspace's sequences (sequences: in the config), sorted by name. Empty when the config declares none or is missing/unparseable. |
WatchWorkspaceStatus(GetWorkspaceStatusRequest) -> stream WorkspaceStatusResponse
Subscribe to status changes: the current snapshot first, then a new snapshot on re-register / on-disk config change / member sync-state change.
Request: GetWorkspaceStatusRequest
The same message as GetWorkspaceStatusRequest.
Response: WorkspaceStatusResponse
The same message as WorkspaceStatusResponse.
GetWorkspacePendingChanges(GetWorkspacePendingChangesRequest) -> stream PendingChange
For each member with tracking:, resolve its upstream content and compare
to the current content:. Streams one PendingChange per member.
Request: GetWorkspacePendingChangesRequest
message GetWorkspacePendingChangesRequest {
optional string workspace_canonical_path = 1;
}Response: PendingChange
One per member, streamed by GetWorkspacePendingChanges.
message PendingChange {
optional string member = 1;
optional PendingChangeKind kind = 2;
optional string current_content = 3;
optional string new_content = 4;
optional map<string, string> metadata = 5;
optional string error = 6;
}| Field | |
|---|---|
member | |
kind | |
current_content | JSON of the member's current content: map (empty if not representable). |
new_content | JSON of the tracking-resolved content: map (set for UP_TO_DATE, LOCAL_OVERRIDE, UPDATABLE). |
metadata | Tracking metadata returned by the provider, e.g. {branch: main}. |
error | Set when kind == PENDING_CHANGE_ERROR. |
EditWorkspace(EditWorkspaceRequest) -> EditWorkspaceResponse
Apply a batch of edits to bldr-workspace.yml in one comment-preserving
read/modify/validate/write. Edits apply in order and the whole batch is
rejected (file untouched) if the result is invalid. This is the unified
edit surface — set/unset/reset at option, member, member-option, tracking,
pin and parent granularity. Git / container member sources resolve
content: from tracking: here, as AddWorkspaceMember did.
Request: EditWorkspaceRequest
── Unified workspace edit ───────────────────────────────────────────────────
message EditWorkspaceRequest {
optional string workspace_canonical_path = 1;
repeated WorkspaceEdit edits = 2;
}| Field | |
|---|---|
workspace_canonical_path | |
edits | Applied in order, atomically. An empty list is a no-op that still returns the current config. |
Response: EditWorkspaceResponse
message EditWorkspaceResponse {
optional string config_yaml = 1;
repeated WorkspaceSequence sequences = 2;
}| Field | |
|---|---|
config_yaml | The config re-serialised after the edits (comments preserved), for display. |
sequences | The workspace's sequences after the edits, so a bump can report the value it produced without a second call or a YAML parser. |
AddWorkspaceMember(AddWorkspaceMemberRequest) -> AddWorkspaceMemberResponse
Deprecated: use EditWorkspace with a SetMember edit.
Edit bldr-workspace.yml (comments preserved). For git / container
sources, content: is resolved from tracking: and both are written.
Request: AddWorkspaceMemberRequest
message AddWorkspaceMemberRequest {
optional string workspace_canonical_path = 1;
optional string name = 2;
oneof source {
GitMemberSource git = 3;
ContainerMemberSource container = 4;
string path = 5;
string blob = 6;
}
}| Field | |
|---|---|
workspace_canonical_path | |
name | |
git | |
container | |
path | watched workspace path |
blob | content addressed by CID |
Response: AddWorkspaceMemberResponse
message AddWorkspaceMemberResponse {
// no fields
}RemoveWorkspaceMember(RemoveWorkspaceMemberRequest) -> RemoveWorkspaceMemberResponse
Deprecated: use EditWorkspace with a RemoveMember edit.
Replace a member with a ~ tombstone.
Request: RemoveWorkspaceMemberRequest
message RemoveWorkspaceMemberRequest {
optional string workspace_canonical_path = 1;
optional string name = 2;
}Response: RemoveWorkspaceMemberResponse
message RemoveWorkspaceMemberResponse {
// no fields
}UpdateWorkspace(UpdateWorkspaceRequest) -> UpdateWorkspaceResponse
Deprecated: use EditWorkspace with a SetOption / UnsetOption edit.
Set a workspace option key: value, or remove it when value is absent.
Request: UpdateWorkspaceRequest
message UpdateWorkspaceRequest {
optional string workspace_canonical_path = 1;
optional string key = 2;
oneof _value {
string value = 3;
}
}| Field | |
|---|---|
workspace_canonical_path | |
key | |
value | Set the option to this value, or remove it when absent. |
Response: UpdateWorkspaceResponse
message UpdateWorkspaceResponse {
// no fields
}PullWorkspaceMembers(PullWorkspaceMembersRequest) -> stream PulledMember
Re-resolve each named member's content: from its tracking: (in
parallel) and write the updated content back to bldr-workspace.yml
(comments preserved). Empty members pulls every tracked member. Streams
one result per member as it resolves.
Request: PullWorkspaceMembersRequest
message PullWorkspaceMembersRequest {
optional string workspace_canonical_path = 1;
repeated string members = 2;
}| Field | |
|---|---|
workspace_canonical_path | |
members | Members to pull; empty pulls every member that has tracking:. |
Response: PulledMember
The outcome of pulling one member's tracked content.
message PulledMember {
optional string member = 1;
optional PullKind kind = 2;
optional string detail = 3;
}| Field | |
|---|---|
member | |
kind | |
detail | The resolved content reference (e.g. repo@sha256:…) on success, or the provider error message when kind == PULL_KIND_ERROR. |
Types used above
WorkspaceSummary
A registered workspace plus its activity, derived from the workspace's builds and deployments (a run/deployment is backed by a build, so builds capture most activity).
message WorkspaceSummary {
optional string path = 1;
optional int64 last_active_seconds = 2;
optional bool active = 3;
}| Field | |
|---|---|
path | |
last_active_seconds | Unix seconds of the most recent build/deployment activity for this workspace (created/started/finished, whichever is latest). 0 if none. |
active | True when the workspace is currently doing something: a build that is pending/running, a watch build still following the workspace, or a pending/running deployment. |
DiagnosticMessage
message DiagnosticMessage {
optional DiagnosticLevel level = 1;
optional string message = 2;
}MemberFetch
One per resolved workspace member directory.
message MemberFetch {
optional string name = 1;
optional string path = 2;
optional string cid = 3;
optional int64 last_fetched_seconds = 4;
optional int64 last_changed_seconds = 5;
optional MemberStatus status = 6;
optional string error = 7;
optional TrackingInfo tracking = 8;
optional bool local_checkout = 9;
optional MemberDiffStatus diff_status = 10;
optional bool inherited = 11;
optional map<string, string> options = 12;
repeated MemberOption option_details = 13;
}| Field | |
|---|---|
name | Member name from the workspace config. |
path | Source descriptor: the absolute directory path for a path source, or a short label (dag:<cid>, inline, <kind> (provider)) for the others. |
cid | CID of the FsNode root stored for this directory. Empty if the member has never successfully fetched. Preserved across a later failed fetch. |
last_fetched_seconds | Unix seconds of the most recent successful fetch, regardless of whether the CID changed. 0 if never fetched. |
last_changed_seconds | Unix seconds of the most recent fetch that produced a different CID from the previous one. Equals last_fetched_seconds for the first fetch. 0 if never fetched. |
status | |
error | Populated when status == FAILED. |
tracking | Upstream tracking for this member, from the workspace config. Always present; an unset kind means no tracking. |
local_checkout | Whether this member is a locally checked-out (path) source — an uncommitted working copy that makes the workspace dirty (no revision snapshot). Only meaningful in detailed status. |
diff_status | How this member relates to the parent snapshot. UNSPECIFIED when the config declares no parent. Orthogonal to the fetch status above. |
inherited | True when this row is inherited from the parent snapshot and is not locally overridden by the config (UNCHANGED / REMOVED rows). For such rows cid is the parent MemberRevision.pin and fetch timestamps are 0. |
options | The member's effective per-member options (the parent snapshot member's options merged with the config's option diff). Editable via EditWorkspace's Set/Unset/ResetMemberOption. Only populated in detailed status. |
option_details | Per-option diff vs the parent snapshot member's options (unchanged / added / changed / removed), for the options editor. Includes removed tombstones (which are absent from options). Only populated in detailed status. |
MemberOption
One per-member option with its diff status. value is the effective value
(for REMOVED, the shadowed parent value).
message MemberOption {
optional string key = 1;
optional string value = 2;
optional MemberOptionStatus status = 3;
}WorkspaceSequence
One workspace sequence: a named counter the workspace keeps as a versioning
service. Edited with the *Sequence WorkspaceEdit ops.
message WorkspaceSequence {
optional string name = 1;
optional string value = 2;
optional SequenceKind kind = 3;
}| Field | |
|---|---|
name | |
value | The value as written: 7 for an integer sequence, 1.2.3 for a semver one. |
kind |
WorkspaceEdit
One edit operation. Three verbs, uniform at every granularity:
set — establish an override (effective = the given value; delta-minimised)
unset — force the effective value absent (a ~ tombstone when needed)
reset — drop the override so the inherited snapshot value shows through
message WorkspaceEdit {
oneof op {
SetOption set_option = 1;
UnsetOption unset_option = 2;
ResetOption reset_option = 3;
SetMember set_member = 4;
RemoveMember remove_member = 5;
ResetMember reset_member = 6;
ResetMemberPin reset_member_pin = 7;
ResetMemberTracking reset_member_tracking = 8;
SetMemberOption set_member_option = 9;
UnsetMemberOption unset_member_option = 10;
ResetMemberOption reset_member_option = 11;
SetParent set_parent = 12;
UnsetParent unset_parent = 13;
CreateSequence create_sequence = 14;
SetSequence set_sequence = 15;
RemoveSequence remove_sequence = 16;
BumpSequence bump_sequence = 17;
}
}SetOption
Workspace options. value is parsed as YAML (scalar / list / map), falling
back to a plain string.
message SetOption {
optional string key = 1;
optional string value = 2;
}UnsetOption
message UnsetOption {
optional string key = 1;
}ResetOption
message ResetOption {
optional string key = 1;
}SetMember
Members. SetMember reuses the AddWorkspaceMember source oneof.
message SetMember {
optional string name = 1;
oneof source {
GitMemberSource git = 2;
ContainerMemberSource container = 3;
string path = 4;
string blob = 5;
}
}| Field | |
|---|---|
name | |
git | |
container | |
path | watched workspace path |
blob | content addressed by CID (dag) |
GitMemberSource
message GitMemberSource {
optional string url = 1;
oneof _branch {
string branch = 2;
}
}| Field | |
|---|---|
url | |
branch | default: the remote's HEAD branch |
ContainerMemberSource
message ContainerMemberSource {
optional string reference = 1;
oneof _tag {
string tag = 2;
}
}| Field | |
|---|---|
reference | |
tag | default: latest |
RemoveMember
message RemoveMember {
optional string name = 1;
}ResetMember
message ResetMember {
optional string name = 1;
}ResetMemberPin
message ResetMemberPin {
optional string name = 1;
}ResetMemberTracking
message ResetMemberTracking {
optional string name = 1;
}SetMemberOption
message SetMemberOption {
optional string name = 1;
optional string key = 2;
optional string value = 3;
}UnsetMemberOption
message UnsetMemberOption {
optional string name = 1;
optional string key = 2;
}ResetMemberOption
message ResetMemberOption {
optional string name = 1;
optional string key = 2;
}SetParent
Parent snapshot.
message SetParent {
optional string cid = 1;
}UnsetParent
message UnsetParent {
// no fields
}CreateSequence
Sequences. value is the text form — 7 (integer) or 1.2.3 (semver) —
and its shape decides the kind. Each op is checked against the config as it
is at write time, inside the same read/modify/write as every other edit, so
two concurrent bumps produce two distinct values.
message CreateSequence {
optional string name = 1;
optional string value = 2;
}SetSequence
message SetSequence {
optional string name = 1;
optional string value = 2;
}RemoveSequence
message RemoveSequence {
optional string name = 1;
}BumpSequence
message BumpSequence {
optional string name = 1;
optional SequenceComponent component = 2;
}MemberStatus
enum MemberStatus {
MEMBER_STATUS_UNSPECIFIED = 0;
MEMBER_STATUS_PENDING = 1;
MEMBER_STATUS_FETCHING = 2;
MEMBER_STATUS_FETCHED = 3;
MEMBER_STATUS_FAILED = 4;
}| Value | |
|---|---|
MEMBER_STATUS_UNSPECIFIED | |
MEMBER_STATUS_PENDING | Discovered in the config but no fetch has started yet. |
MEMBER_STATUS_FETCHING | Currently being fetched + stored. Streamed during workspace fetch. |
MEMBER_STATUS_FETCHED | Last fetch attempt succeeded. cid holds the FsNode root. |
MEMBER_STATUS_FAILED | Last fetch attempt failed. cid keeps the previous-success value (empty if none), error describes the failure. |
MemberDiffStatus
How a member relates to the parent WorkspaceRevisionSnapshot. Orthogonal to the fetch MemberStatus (which reports sync progress).
enum MemberDiffStatus {
MEMBER_DIFF_STATUS_UNSPECIFIED = 0;
MEMBER_DIFF_STATUS_UNCHANGED = 1;
MEMBER_DIFF_STATUS_NEW = 2;
MEMBER_DIFF_STATUS_CHANGED = 3;
MEMBER_DIFF_STATUS_REMOVED = 4;
}| Value | |
|---|---|
MEMBER_DIFF_STATUS_UNSPECIFIED | no parent snapshot declared |
MEMBER_DIFF_STATUS_UNCHANGED | in parent, not touched by the diff |
MEMBER_DIFF_STATUS_NEW | added by the diff (absent from parent) |
MEMBER_DIFF_STATUS_CHANGED | in parent, overridden by the diff |
MEMBER_DIFF_STATUS_REMOVED | ~ tombstone shadowing a parent member |
MemberOptionStatus
How a member option relates to the parent snapshot member's options.
enum MemberOptionStatus {
MEMBER_OPTION_STATUS_UNSPECIFIED = 0;
MEMBER_OPTION_STATUS_UNCHANGED = 1;
MEMBER_OPTION_STATUS_ADDED = 2;
MEMBER_OPTION_STATUS_CHANGED = 3;
MEMBER_OPTION_STATUS_REMOVED = 4;
}| Value | |
|---|---|
MEMBER_OPTION_STATUS_UNSPECIFIED | |
MEMBER_OPTION_STATUS_UNCHANGED | inherited, not overridden |
MEMBER_OPTION_STATUS_ADDED | set by the config, absent from parent |
MEMBER_OPTION_STATUS_CHANGED | set by the config, overriding parent |
MEMBER_OPTION_STATUS_REMOVED | ~ tombstone shadowing a parent option |
SequenceKind
enum SequenceKind {
SEQUENCE_KIND_UNSPECIFIED = 0;
SEQUENCE_KIND_INTEGER = 1;
SEQUENCE_KIND_SEMVER = 2;
}| Value | |
|---|---|
SEQUENCE_KIND_UNSPECIFIED | |
SEQUENCE_KIND_INTEGER | A single counter; bump increments it. |
SEQUENCE_KIND_SEMVER | A major.minor.build triple; bump names the component. |
PendingChangeKind
How a tracked member compares against its upstream.
enum PendingChangeKind {
PENDING_CHANGE_KIND_UP_TO_DATE = 0;
PENDING_CHANGE_KIND_LOCAL_OVERRIDE = 1;
PENDING_CHANGE_KIND_UPDATABLE = 2;
PENDING_CHANGE_KIND_ERROR = 3;
PENDING_CHANGE_KIND_NO_TRACKING = 4;
}| Value | |
|---|---|
PENDING_CHANGE_KIND_UP_TO_DATE | Tracking-resolved content equals the member's current content. |
PENDING_CHANGE_KIND_LOCAL_OVERRIDE | The member's current content is a local path: source; new_content reports what tracking would resolve to. |
PENDING_CHANGE_KIND_UPDATABLE | Resolved content differs from current — an update is available. |
PENDING_CHANGE_KIND_ERROR | The tracking provider failed for this member; error is set. |
PENDING_CHANGE_KIND_NO_TRACKING | The member has no tracking (absent or kind: none). |
SequenceComponent
Which component of a sequence a BumpSequence increments. UNSPECIFIED means BUILD — the last component, and the only one an integer sequence has.
enum SequenceComponent {
SEQUENCE_COMPONENT_UNSPECIFIED = 0;
SEQUENCE_COMPONENT_BUILD = 1;
SEQUENCE_COMPONENT_MINOR = 2;
SEQUENCE_COMPONENT_MAJOR = 3;
}| Value | |
|---|---|
SEQUENCE_COMPONENT_UNSPECIFIED | |
SEQUENCE_COMPONENT_BUILD | |
SEQUENCE_COMPONENT_MINOR | Increments minor and resets build to 0. Refused on an integer sequence. |
SEQUENCE_COMPONENT_MAJOR | Increments major and resets minor and build to 0. Refused on an integer sequence. |
PullKind
enum PullKind {
PULL_KIND_UNSPECIFIED = 0;
PULL_KIND_UPDATED = 1;
PULL_KIND_UP_TO_DATE = 2;
PULL_KIND_NO_TRACKING = 3;
PULL_KIND_ERROR = 4;
}| Value | |
|---|---|
PULL_KIND_UNSPECIFIED | |
PULL_KIND_UPDATED | Content changed and was written back. |
PULL_KIND_UP_TO_DATE | Resolved content already matched — nothing written. |
PULL_KIND_NO_TRACKING | The member has no tracking to pull from. |
PULL_KIND_ERROR | The tracking provider failed; detail is the error. |
Logs
Logs — read content-addressed log streams by their full id {peer_id}/{tenant}/{uuid}. Auth is enforced here: a request may only touch a stream whose tenant equals the tenant stamped by the gRPC middleware.
Networking
Peer / network management. Every RPC returns NOT_FOUND if the node was started without networking.