[bldr]docs
gRPC APICloud

BldrService

BldrService in Cloud.

Service bldr.service.v1.BldrService, 23 rpcs.

GetMe(GetMeRequest) -> GetMeResponse

── Identity ──────────────────────────────────────────────────────────── The authenticated user plus the organizations they belong to. On the first call for a self-registered user with no organizations, their personal org is provisioned lazily.

Request: GetMeRequest

message GetMeRequest {
  // no fields
}

Response: GetMeResponse

message GetMeResponse {
  optional User user = 1;
  repeated Organization organizations = 2;
}

UpdateUser(UpdateUserRequest) -> User

Update the caller's own profile (display name). Mirrored to Clerk.

Request: UpdateUserRequest

message UpdateUserRequest {
  optional string display_name = 1;
}

Response: User

A user, mirrored from Clerk.

Deletion is a mark, never a row removal: a deleted user keeps its id so everything that ever referenced it still resolves, and a Clerk id is never handed out twice. Deleted users are absent from every response here.

message User {
  optional string id = 1;
  optional string email = 2;
  optional string display_name = 3;
}
Field
idClerk user id (the token sub)
email 
display_name 

DeleteUser(DeleteUserRequest) -> DeleteUserResponse

Delete the caller's own account: removed from Clerk, and marked deleted here. A caller can only delete themselves, so there is no id to pass. Orgs the caller merely belongs to survive; their personal org is marked deleted with them, and a shared org they solely own is refused — hand it over or delete it first, so an organization is never orphaned by one departure.

Request: DeleteUserRequest

message DeleteUserRequest {
  // no fields
}

Response: DeleteUserResponse

message DeleteUserResponse {
  // no fields
}

ListOrganizations(ListOrganizationsRequest) -> ListOrganizationsResponse

── Organizations ────────────────────────────────────────────────────── The organizations the caller is a member of.

Request: ListOrganizationsRequest

message ListOrganizationsRequest {
  // no fields
}

Response: ListOrganizationsResponse

message ListOrganizationsResponse {
  repeated Organization organizations = 1;
}

CreateOrganization(CreateOrganizationRequest) -> Organization

Create a new (shared) organization owned by the caller.

Request: CreateOrganizationRequest

message CreateOrganizationRequest {
  optional string name = 1;
}

Response: Organization

An organization the caller belongs to, with the caller's role/permissions in it (from the Clerk session).

Exactly one of a caller's organizations is personal. It is created for every user on their first authenticated call — there is no RPC that makes one, because there is no state in which a user should not have one — and it is theirs alone: no other member can be added, its name cannot be changed, and it cannot be deleted. It goes when the account goes.

message Organization {
  optional string id = 1;
  optional string name = 2;
  optional bool personal = 4;
  optional string role = 5;
  repeated string permissions = 6;
}
Field
idClerk org id, or personal:<user_id>
name 
personalthe member's own personal org
rolecaller's Clerk org role
permissionscaller's Clerk permissions in this org

GetOrganization(GetOrganizationRequest) -> OrganizationDetail

An organization with its members. Caller must be a member.

Request: GetOrganizationRequest

message GetOrganizationRequest {
  optional string org_id = 1;
}

Response: OrganizationDetail

An organization plus its members.

message OrganizationDetail {
  optional Organization organization = 1;
  repeated Member members = 2;
}

UpdateOrganization(UpdateOrganizationRequest) -> Organization

Rename an organization. Requires org:sys_profile:manage in the active org, and is refused outright on a personal organization, whose name is fixed.

Request: UpdateOrganizationRequest

message UpdateOrganizationRequest {
  optional string org_id = 1;
  optional string name = 2;
}

Response: Organization

The same message as Organization.

DeleteOrganization(DeleteOrganizationRequest) -> DeleteOrganizationResponse

Delete an organization. Requires org:sys_profile:manage; personal orgs cannot be deleted this way.

Request: DeleteOrganizationRequest

message DeleteOrganizationRequest {
  optional string org_id = 1;
}

Response: DeleteOrganizationResponse

message DeleteOrganizationResponse {
  // no fields
}

ListWorkspaces(ListWorkspacesRequest) -> ListWorkspacesResponse

── Workspaces ────────────────────────────────────────────────────────── The workspaces of an organization. Caller must be a member.

Request: ListWorkspacesRequest

message ListWorkspacesRequest {
  optional string org_id = 1;
}

Response: ListWorkspacesResponse

message ListWorkspacesResponse {
  repeated Workspace workspaces = 1;
}

GetWorkspace(GetWorkspaceRequest) -> WorkspaceDetail

One workspace, addressed by its slug within the organization, with its revisions. Caller must be a member.

Request: GetWorkspaceRequest

message GetWorkspaceRequest {
  optional string org_id = 1;
  optional string slug = 2;
}

Response: WorkspaceDetail

A workspace plus its revisions, newest first.

message WorkspaceDetail {
  optional Workspace workspace = 1;
  repeated WorkspaceRevision revisions = 2;
}

CreateWorkspace(CreateWorkspaceRequest) -> Workspace

Create a workspace. Its slug is its identity and cannot be changed afterwards, so this is the only call that sets one. Creating it also creates revision 1, which becomes the current revision — a workspace is never without one.

Request: CreateWorkspaceRequest

message CreateWorkspaceRequest {
  optional string org_id = 1;
  optional string slug = 2;
}
Field
org_id 
slugLowercase letters, digits and hyphens; must start and end alphanumeric. Rejected rather than rewritten: a slug the caller did not choose is a surprise in every URL that follows.

Response: Workspace

A workspace: a named thing an organization owns, with a history of revisions.

The slug is the identity, not a display label beside one. It is unique within the owning organization, it is what a URL and an API call address the workspace by, and it is fixed at creation — renaming would break every reference to it, and a mutable second name is the thing organizations just stopped having.

message Workspace {
  optional string slug = 1;
  optional string org_id = 2;
  optional uint32 current_revision = 3;
  optional int64 created_at_unix = 4;
  optional uint32 revision_count = 5;
}
Field
slugunique within the org; immutable
org_id 
current_revisionThe revision currently in effect. Always >= 1: creating a workspace creates revision 1, and exactly one revision is current at any moment.
created_at_unix 
revision_count 

CreateBuild(CreateBuildRequest) -> Build

── Builds ────────────────────────────────────────────────────────────── Start a build of a workspace. Caller must be a member.

Always accepted. A regular build then waits its turn: any number may be queued for a workspace and at most one runs at a time, because each commits the next revision and revision N+1 is defined in terms of N. A dry run runs the same build and commits no revision, so it is ordered against nothing and never waits.

Request: CreateBuildRequest

message CreateBuildRequest {
  optional string org_id = 1;
  optional string workspace_slug = 2;
  optional BuildKind kind = 3;
  optional BuildDefinition definition = 4;
}

Response: Build

A build of a workspace.

message Build {
  optional uint32 number = 1;
  optional string workspace_slug = 2;
  optional string org_id = 3;
  optional BuildKind kind = 4;
  optional BuildState state = 5;
  optional BuildDefinition definition = 6;
  optional uint32 parent_revision = 7;
  optional uint32 produced_revision = 8;
  optional string created_by = 9;
  optional int64 created_at_unix = 10;
  optional int64 started_at_unix = 11;
  optional int64 finished_at_unix = 12;
  optional uint32 queue_position = 13;
  optional string message = 14;
}
Field
numberSequential within the workspace, from 1.
workspace_slug 
org_id 
kind 
state 
definition 
parent_revisionThe workspace revision this build runs against — its parent snapshot.
produced_revisionThe revision this build committed, or 0 — the one thing that distinguishes the two kinds. Only a successful regular build sets it.
created_by 
created_at_unix 
started_at_unix 
finished_at_unix 
queue_positionHow many regular builds are ahead of this one — queued or running. 0 unless this build is itself QUEUED.
messageWhy it failed or was cancelled; empty otherwise.

ListBuilds(ListBuildsRequest) -> ListBuildsResponse

A workspace's builds, newest first.

Request: ListBuildsRequest

message ListBuildsRequest {
  optional string org_id = 1;
  optional string workspace_slug = 2;
}

Response: ListBuildsResponse

message ListBuildsResponse {
  repeated Build builds = 1;
}

GetBuild(GetBuildRequest) -> Build

One build by its number within the workspace.

Request: GetBuildRequest

message GetBuildRequest {
  optional string org_id = 1;
  optional string workspace_slug = 2;
  optional uint32 number = 3;
}

Response: Build

The same message as Build.

CancelBuild(CancelBuildRequest) -> Build

Cancel a build that has not finished. A queued build is dropped; a running one is asked to stop.

Request: CancelBuildRequest

message CancelBuildRequest {
  optional string org_id = 1;
  optional string workspace_slug = 2;
  optional uint32 number = 3;
}

Response: Build

The same message as Build.

ListMembers(ListMembersRequest) -> ListMembersResponse

── Membership management ──────────────────────────────────────────────── Members of an organization. Caller must be a member.

Request: ListMembersRequest

message ListMembersRequest {
  optional string org_id = 1;
}

Response: ListMembersResponse

message ListMembersResponse {
  repeated Member members = 1;
}

InviteMember(InviteMemberRequest) -> Invitation

Invite a user (by email) to the active org. Requires org:sys_memberships:manage. Returns the pending invitation.

Request: InviteMemberRequest

message InviteMemberRequest {
  optional string org_id = 1;
  optional string email = 2;
  optional string role = 3;
}
Field
org_id 
email 
rolee.g. "org:member" / "org:admin"

Response: Invitation

A pending invitation to join an organization.

message Invitation {
  optional string id = 1;
  optional string email = 2;
  optional string role = 3;
  optional string status = 4;
}
Field
id 
email 
role 
statuse.g. "pending"

UpdateMemberRole(UpdateMemberRoleRequest) -> Member

Change a member's role. Requires org:sys_memberships:manage, and is refused when it would demote the organization's last admin — including the caller demoting themselves, which is the only way to reach that state.

Request: UpdateMemberRoleRequest

message UpdateMemberRoleRequest {
  optional string org_id = 1;
  optional string user_id = 2;
  optional string role = 3;
}

Response: Member

A member of an organization.

message Member {
  optional string user_id = 1;
  optional string email = 2;
  optional string display_name = 3;
  optional string role = 4;
  repeated string permissions = 5;
}

RemoveMember(RemoveMemberRequest) -> RemoveMemberResponse

Remove another member from the org. Requires org:sys_memberships:manage. To remove yourself, use LeaveOrganization — leaving has rules of its own that removing someone else does not.

Request: RemoveMemberRequest

message RemoveMemberRequest {
  optional string org_id = 1;
  optional string user_id = 2;
}

Response: RemoveMemberResponse

message RemoveMemberResponse {
  // no fields
}

LeaveOrganization(LeaveOrganizationRequest) -> LeaveOrganizationResponse

Leave an organization. Needs no permission — membership is the caller's to give up — but it is refused in two cases, because both would leave an organization nobody can run:

  • the caller is its last member. There would be nothing left to belong to it, so the organization is to be deleted instead (DeleteOrganization), which is a different decision and a different button;
  • the caller is its last admin while other members remain. Someone else has to be promoted first.

A personal organization cannot be left at all: it is the caller, and it goes when the account does.

Request: LeaveOrganizationRequest

message LeaveOrganizationRequest {
  optional string org_id = 1;
}

Response: LeaveOrganizationResponse

message LeaveOrganizationResponse {
  // no fields
}

ApproveCliLogin(ApproveCliLoginRequest) -> ApproveCliLoginResponse

Approve a pending bldr login for one of the caller's organizations, and return the one-time authorization code the CLI exchanges at CliOAuth.Token. The code lives for ten minutes and redeems once.

Request: ApproveCliLoginRequest

The authorization request the CLI put in the console URL, plus what the person chose on the consent page.

message ApproveCliLoginRequest {
  optional string client_id = 1;
  optional string redirect_uri = 2;
  optional string code_challenge = 3;
  optional string code_challenge_method = 4;
  optional string org_id = 5;
  optional string name = 6;
}
Field
client_idThe CLI's OAuth parameters, passed through from the URL unchanged.
redirect_uriA loopback http://127.0.0.1:<port>/… (or localhost, [::1]) the CLI listens on, or urn:ietf:wg:oauth:2.0:oob when the CLI has no browser and the console shows the code for pasting.
code_challenge 
code_challenge_method"S256"; nothing else is accepted
org_idThe organization the CLI will act in. The caller must be a member.
nameA label for the settings pages, from the CLI. Trimmed and capped.

Response: ApproveCliLoginResponse

message ApproveCliLoginResponse {
  optional string code = 1;
}
Field
codeThe one-time authorization code. The console appends it to a loopback redirect_uri, or shows it for pasting.

ListCliAuthorizations(ListCliAuthorizationsRequest) -> ListCliAuthorizationsResponse

Live CLI authorizations. With no org_id, the caller's own, across every organization. With one, the authorizations in that organization: all of them for a member holding org:sys_memberships:manage, the caller's own otherwise.

Request: ListCliAuthorizationsRequest

message ListCliAuthorizationsRequest {
  optional string org_id = 1;
}
Field
org_idempty: the caller's own, across organizations

Response: ListCliAuthorizationsResponse

message ListCliAuthorizationsResponse {
  repeated CliAuthorization authorizations = 1;
}
Field
authorizationsnewest first

RevokeCliAuthorization(RevokeCliAuthorizationRequest) -> RevokeCliAuthorizationResponse

Revoke a CLI authorization. Its holder may revoke it, and so may anyone holding org:sys_memberships:manage in the organization it is bound to.

Request: RevokeCliAuthorizationRequest

message RevokeCliAuthorizationRequest {
  optional string id = 1;
}

Response: RevokeCliAuthorizationResponse

message RevokeCliAuthorizationResponse {
  // no fields
}

Types used above

WorkspaceRevision

One revision of a workspace. Numbered from 1, sequentially, per workspace.

message WorkspaceRevision {
  optional uint32 number = 1;
  optional int64 created_at_unix = 2;
  optional string created_by = 3;
  optional bool current = 4;
}
Field
number 
created_at_unix 
created_byuser id
current 

BuildDefinition

What a build builds: the same thing a bldr-workspace.yml says, applied on top of the workspace's current revision.

This is a diff, exactly as the open-source WorkspaceConfig is: the workspace's current revision is the parent snapshot, and these members and options override it. removed_members is this API's spelling of that file's ~ tombstone — proto3 maps cannot carry a null, so removal is a separate list rather than an absent value.

message BuildDefinition {
  optional map<string, BuildMember> members = 1;
  optional map<string, string> options = 2;
  repeated string removed_members = 3;
  repeated string args = 4;
}
Field
members 
optionsFree-form build options, as in the workspace file's options:. The reserved key build_controller selects the build controller.
removed_membersMembers of the parent revision to drop from this build.
argsBuild arguments, passed through to the controller.

BuildMember

One member of the build's workspace definition.

message BuildMember {
  optional BuildMemberSource source = 1;
  optional map<string, string> options = 2;
}
Field
source 
optionsPer-member options carried into the build input.

BuildMemberSource

Where one workspace member's content comes from.

This mirrors the open-source MemberSource — the same shapes a bldr-workspace.yml can write — with one omission: there is no path. A path source means "watch this directory in the working copy", and a build started through this API has no working copy to watch. Everything else is here.

message BuildMemberSource {
  oneof source {
    string dag = 1;
    string inline_yaml = 2;
    ProviderSource provider = 3;
  }
}
Field
dagContent already addressed by a CID.
inline_yamlA YAML document stored as a single IPLD block.
providerDelegate to the node's registered content-provider/&lt;kind> — git, container-registry, … — with free-form settings.

ProviderSource

message ProviderSource {
  optional string kind = 1;
  optional map<string, string> settings = 2;
}

BuildKind

What a build does with the workspace it runs against.

enum BuildKind {
  BUILD_KIND_UNSPECIFIED = 0;
  BUILD_KIND_REGULAR = 1;
  BUILD_KIND_DRY_RUN = 2;
}
Value
BUILD_KIND_UNSPECIFIED 
BUILD_KIND_REGULAROn success, the snapshot this build resolved becomes the workspace's next revision. That is what makes these queue: revision N+1 is defined as a diff on N, so two of them cannot run at once — though any number may wait.
BUILD_KIND_DRY_RUNThe same build, without the revision. It runs exactly as a regular build does — same definition, same members, same targets, same artifacts — and then commits nothing: the workspace's current revision does not move.

BuildState

enum BuildState {
  BUILD_STATE_UNSPECIFIED = 0;
  BUILD_STATE_QUEUED = 1;
  BUILD_STATE_RUNNING = 2;
  BUILD_STATE_SUCCEEDED = 3;
  BUILD_STATE_FAILED = 4;
  BUILD_STATE_CANCELLED = 5;
}
Value
BUILD_STATE_UNSPECIFIED 
BUILD_STATE_QUEUEDWaiting for the workspace's running build to finish. Regular builds only.
BUILD_STATE_RUNNING 
BUILD_STATE_SUCCEEDED 
BUILD_STATE_FAILED 
BUILD_STATE_CANCELLED 

On this page

GetMe(GetMeRequest) -> GetMeResponseRequest: GetMeRequestResponse: GetMeResponseUpdateUser(UpdateUserRequest) -> UserRequest: UpdateUserRequestResponse: UserDeleteUser(DeleteUserRequest) -> DeleteUserResponseRequest: DeleteUserRequestResponse: DeleteUserResponseListOrganizations(ListOrganizationsRequest) -> ListOrganizationsResponseRequest: ListOrganizationsRequestResponse: ListOrganizationsResponseCreateOrganization(CreateOrganizationRequest) -> OrganizationRequest: CreateOrganizationRequestResponse: OrganizationGetOrganization(GetOrganizationRequest) -> OrganizationDetailRequest: GetOrganizationRequestResponse: OrganizationDetailUpdateOrganization(UpdateOrganizationRequest) -> OrganizationRequest: UpdateOrganizationRequestResponse: OrganizationDeleteOrganization(DeleteOrganizationRequest) -> DeleteOrganizationResponseRequest: DeleteOrganizationRequestResponse: DeleteOrganizationResponseListWorkspaces(ListWorkspacesRequest) -> ListWorkspacesResponseRequest: ListWorkspacesRequestResponse: ListWorkspacesResponseGetWorkspace(GetWorkspaceRequest) -> WorkspaceDetailRequest: GetWorkspaceRequestResponse: WorkspaceDetailCreateWorkspace(CreateWorkspaceRequest) -> WorkspaceRequest: CreateWorkspaceRequestResponse: WorkspaceCreateBuild(CreateBuildRequest) -> BuildRequest: CreateBuildRequestResponse: BuildListBuilds(ListBuildsRequest) -> ListBuildsResponseRequest: ListBuildsRequestResponse: ListBuildsResponseGetBuild(GetBuildRequest) -> BuildRequest: GetBuildRequestResponse: BuildCancelBuild(CancelBuildRequest) -> BuildRequest: CancelBuildRequestResponse: BuildListMembers(ListMembersRequest) -> ListMembersResponseRequest: ListMembersRequestResponse: ListMembersResponseInviteMember(InviteMemberRequest) -> InvitationRequest: InviteMemberRequestResponse: InvitationUpdateMemberRole(UpdateMemberRoleRequest) -> MemberRequest: UpdateMemberRoleRequestResponse: MemberRemoveMember(RemoveMemberRequest) -> RemoveMemberResponseRequest: RemoveMemberRequestResponse: RemoveMemberResponseLeaveOrganization(LeaveOrganizationRequest) -> LeaveOrganizationResponseRequest: LeaveOrganizationRequestResponse: LeaveOrganizationResponseApproveCliLogin(ApproveCliLoginRequest) -> ApproveCliLoginResponseRequest: ApproveCliLoginRequestResponse: ApproveCliLoginResponseListCliAuthorizations(ListCliAuthorizationsRequest) -> ListCliAuthorizationsResponseRequest: ListCliAuthorizationsRequestResponse: ListCliAuthorizationsResponseRevokeCliAuthorization(RevokeCliAuthorizationRequest) -> RevokeCliAuthorizationResponseRequest: RevokeCliAuthorizationRequestResponse: RevokeCliAuthorizationResponseTypes used aboveWorkspaceRevisionBuildDefinitionBuildMemberBuildMemberSourceProviderSourceBuildKindBuildState