Initial: Guildhouse protobuf definitions

14 proto files across 5 gRPC service domains:
- quartermaster/v1 (6): governance, registry, notary, credentials, capabilities, pipelines
- bascule/v1 (4): session, command, gateway, ceremony
- workspace/v1 (1): workspace management
- runner/v1 (2): pipeline execution
- schematic/v1 (1): composite meta-artifacts

Consumed as a git submodule by guildhouse-platform (Rust) and guildhouse-dashboard (Python).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tyler King 2026-02-26 10:29:06 -05:00
commit 2720a631b8
16 changed files with 1844 additions and 0 deletions

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
# Generated code (language-specific stubs live in consumer repos)
*_pb2.py
*_pb2_grpc.py
*_pb2.pyi
*.rs
# Editor
.idea/
.vscode/
*.swp
*~

27
CLAUDE.md Normal file
View file

@ -0,0 +1,27 @@
# CLAUDE.md -- Guildhouse Proto
## Project Identity
Canonical protobuf definitions for all Guildhouse gRPC services.
Consumed by:
- **guildhouse-platform** (Rust/tonic-build) via git submodule
- **guildhouse-dashboard** (Python/grpcio-tools) via git submodule
## Domains
| Domain | Directory | Files | Purpose |
|--------|-----------|-------|---------|
| Quartermaster | `quartermaster/v1/` | 6 | Governance, registry, notary, credentials, capabilities, pipelines |
| Bascule | `bascule/v1/` | 4 | Session, command, gateway, ceremony |
| Workspace | `workspace/v1/` | 1 | Workspace management |
| Runner | `runner/v1/` | 2 | Pipeline execution |
| Schematic | `schematic/v1/` | 1 | Composite meta-artifacts |
## Versioning
Proto files use domain-versioned paths (e.g., `quartermaster/v1/`). Breaking changes require a new version directory (e.g., `quartermaster/v2/`).
## Related Repos
- `~/projects/guildhouse-platform/` -- Rust services that implement these APIs
- `~/projects/guildhouse-dashboard/` -- Django dashboard that calls these APIs

156
bascule/v1/ceremony.proto Normal file
View file

@ -0,0 +1,156 @@
syntax = "proto3";
package bascule.v1;
import "google/protobuf/timestamp.proto";
// Governance Ceremony Service multi-stakeholder approval flows
// triggered by Accord policy when a mutation requires human sign-off.
service CeremonyService {
// Create a new governance ceremony.
rpc CreateCeremony (CreateCeremonyRequest) returns (CreateCeremonyResponse);
// Record an approval or denial on a pending ceremony.
rpc ApproveCeremony (ApproveCeremonyRequest) returns (ApproveCeremonyResponse);
// Deny a pending ceremony.
rpc DenyCeremony (DenyCeremonyRequest) returns (DenyCeremonyResponse);
// Cancel a pending ceremony (requestor or admin).
rpc CancelCeremony (CancelCeremonyRequest) returns (CancelCeremonyResponse);
// Get the current status of a ceremony.
rpc GetCeremony (GetCeremonyRequest) returns (GetCeremonyResponse);
// List pending ceremonies, optionally filtered.
rpc ListPendingCeremonies (ListPendingCeremoniesRequest) returns (ListPendingCeremoniesResponse);
// Get the resolution proof for a completed ceremony.
rpc GetCeremonyProof (GetCeremonyProofRequest) returns (GetCeremonyProofResponse);
}
// --- Create ---
message CreateCeremonyRequest {
string ceremony_type = 1; // "single_approval", "quorum_approval", etc.
CeremonySubjectMsg subject = 2;
uint32 required_approvals = 3;
repeated string approver_roles = 4;
uint32 ttl_hours = 5; // 0 = default (24h)
string intent_id = 6; // optional linked MutationIntent
string run_id = 7; // optional linked pipeline run
uint64 pr_number = 8; // optional linked PR
string remote_name = 9; // optional remote name
}
message CreateCeremonyResponse {
string ceremony_id = 1;
string status = 2; // "pending" or "approved" (for self-grant)
google.protobuf.Timestamp expires_at = 3;
string error = 4;
}
// --- Approve ---
message ApproveCeremonyRequest {
string ceremony_id = 1;
string approver_identity = 2;
string approver_role = 3;
string comment = 4;
}
message ApproveCeremonyResponse {
bool success = 1;
string status = 2; // updated status after approval
string error = 3;
}
// --- Deny ---
message DenyCeremonyRequest {
string ceremony_id = 1;
string approver_identity = 2;
string approver_role = 3;
string comment = 4;
}
message DenyCeremonyResponse {
bool success = 1;
string status = 2;
string error = 3;
}
// --- Cancel ---
message CancelCeremonyRequest {
string ceremony_id = 1;
}
message CancelCeremonyResponse {
bool success = 1;
string error = 2;
}
// --- Get ---
message GetCeremonyRequest {
string ceremony_id = 1;
}
message GetCeremonyResponse {
string ceremony_id = 1;
string ceremony_type = 2;
CeremonySubjectMsg subject = 3;
string status = 4;
uint32 required_approvals = 5;
uint32 current_approvals = 6;
repeated CeremonyApprovalMsg approvals = 7;
google.protobuf.Timestamp created_at = 8;
google.protobuf.Timestamp expires_at = 9;
string intent_id = 10;
string run_id = 11;
uint64 pr_number = 12;
string remote_name = 13;
string error = 14;
}
// --- List Pending ---
message ListPendingCeremoniesRequest {
string intent_id = 1; // optional filter
}
message ListPendingCeremoniesResponse {
repeated GetCeremonyResponse ceremonies = 1;
}
// --- Proof ---
message GetCeremonyProofRequest {
string ceremony_id = 1;
}
message GetCeremonyProofResponse {
string ceremony_id = 1;
string status = 2;
string proof_hash = 3;
repeated CeremonyApprovalMsg approvals = 4;
google.protobuf.Timestamp resolved_at = 5;
string error = 6;
}
// --- Shared messages ---
message CeremonySubjectMsg {
string subject_type = 1; // "mutation_intent", "pipeline_merge", "schematic_publish", "custom"
string reference_id = 2; // intent_id, run_id, "name:version", or custom ref
string description = 3; // human-readable label
map<string, string> metadata = 4; // extra fields
}
message CeremonyApprovalMsg {
string approver_identity = 1;
string approver_role = 2;
string decision = 3; // "approve" or "deny"
string comment = 4;
google.protobuf.Timestamp decided_at = 5;
}

82
bascule/v1/command.proto Normal file
View file

@ -0,0 +1,82 @@
syntax = "proto3";
package bascule.v1;
import "google/protobuf/struct.proto";
// --- Command execution ---
message ExecuteCommandRequest {
string session_id = 1;
string verb = 2;
optional string namespace = 3;
optional string resource_type = 4;
optional string resource_name = 5;
google.protobuf.Struct parameters = 6;
string output_format = 7;
}
message ExecuteCommandResponse {
bool allowed = 1;
string denied_reason = 2;
oneof result {
CommandResult success = 3;
CommandError error = 4;
}
AuditRef audit = 5;
}
message CommandResult {
string output = 1;
uint32 resources_affected = 2;
bool session_expired_warning = 3;
}
message CommandError {
string message = 1;
string code = 2;
}
// --- Streaming ---
message CommandStreamChunk {
oneof chunk {
string output_line = 1;
string error_line = 2;
bool eof = 3;
}
}
// --- Audit reference ---
message AuditRef {
string event_id = 1;
string classification = 2;
bool notarized = 3;
}
// --- Command discovery ---
message DiscoverCommandsRequest {
string session_id = 1;
}
message DiscoverCommandsResponse {
repeated CommandDescriptor commands = 1;
}
message CommandDescriptor {
string verb = 1;
string description = 2;
string classification = 3;
repeated ParameterDescriptor parameters = 4;
bool requires_namespace = 5;
bool requires_resource = 6;
bool streaming = 7;
}
message ParameterDescriptor {
string name = 1;
string description = 2;
string param_type = 3;
bool required = 4;
}

20
bascule/v1/gateway.proto Normal file
View file

@ -0,0 +1,20 @@
syntax = "proto3";
package bascule.v1;
import "bascule/v1/session.proto";
import "bascule/v1/command.proto";
service BasculeGateway {
// Session lifecycle
rpc RequestSession (RequestSessionRequest) returns (RequestSessionResponse);
rpc GetSessionStatus (GetSessionStatusRequest) returns (GetSessionStatusResponse);
rpc EndSession (EndSessionRequest) returns (EndSessionResponse);
rpc GetCeremonyStatus (GetCeremonyStatusRequest) returns (GetCeremonyStatusResponse);
// Command execution
rpc ExecuteCommand (ExecuteCommandRequest) returns (ExecuteCommandResponse);
rpc StreamCommand (ExecuteCommandRequest) returns (stream CommandStreamChunk);
// Discovery
rpc DiscoverCommands (DiscoverCommandsRequest) returns (DiscoverCommandsResponse);
}

110
bascule/v1/session.proto Normal file
View file

@ -0,0 +1,110 @@
syntax = "proto3";
package bascule.v1;
import "google/protobuf/timestamp.proto";
// --- Session request / response ---
message RequestSessionRequest {
string ceremony_type = 1;
SessionScope requested_scope = 2;
repeated EvidenceItem evidence = 3;
}
message RequestSessionResponse {
oneof result {
SessionGranted granted = 1;
CeremonyPending pending = 2;
CeremonyDenied denied = 3;
}
}
message SessionGranted {
string session_id = 1;
SessionScope granted_scope = 2;
google.protobuf.Timestamp expires_at = 3;
string ceremony_id = 4;
}
message CeremonyPending {
string ceremony_id = 1;
string message = 2;
google.protobuf.Timestamp timeout_at = 3;
}
message CeremonyDenied {
string reason = 1;
}
// --- Scope model ---
message SessionScope {
repeated NamespaceScope namespaces = 1;
GlobalScope global = 2;
repeated string pathways = 3;
optional uint32 mutation_budget = 4;
bool can_delegate = 5;
}
message NamespaceScope {
string namespace = 1;
repeated ScopeRule rules = 2;
repeated string workload_profiles = 3;
repeated string denied_capabilities = 4;
}
message ScopeRule {
repeated string api_groups = 1;
repeated string resources = 2;
repeated string verbs = 3;
}
message GlobalScope {
bool can_view_audit_trail = 1;
bool can_view_profiles = 2;
bool can_view_topology = 3;
}
message EvidenceItem {
string evidence_type = 1;
string reference = 2;
}
// --- Session status ---
message GetSessionStatusRequest {
string session_id = 1;
}
message GetSessionStatusResponse {
string session_id = 1;
string state = 2;
SessionScope scope = 3;
google.protobuf.Timestamp expires_at = 4;
uint32 mutations_used = 5;
optional uint32 mutation_budget = 6;
}
// --- Session end ---
message EndSessionRequest {
string session_id = 1;
}
message EndSessionResponse {
bool success = 1;
uint32 total_commands = 2;
uint32 total_mutations = 3;
}
// --- Ceremony status ---
message GetCeremonyStatusRequest {
string ceremony_id = 1;
}
message GetCeremonyStatusResponse {
string ceremony_id = 1;
string status = 2;
optional SessionGranted session = 3;
}

View file

@ -0,0 +1,87 @@
syntax = "proto3";
package quartermaster.v1;
import "google/protobuf/timestamp.proto";
service QuartermasterCapabilities {
rpc SubmitProfile (SubmitProfileRequest) returns (SubmitProfileResponse);
rpc GetProfile (GetProfileRequest) returns (GetProfileResponse);
rpc ListProfiles (ListProfilesRequest) returns (ListProfilesResponse);
rpc VerifyProfile (VerifyProfileRequest) returns (VerifyProfileResponse);
rpc FlushAnchor (FlushAnchorRequest) returns (FlushAnchorResponse);
}
message SubmitProfileRequest {
string cluster_id = 1;
string image_digest = 2;
bytes profile_canonical = 3;
bytes profile_hash = 4;
string miner_version = 5;
string source_repo = 6;
string source_commit = 7;
}
message SubmitProfileResponse {
string capability_id = 1;
google.protobuf.Timestamp accepted_at = 2;
bool anchored = 3;
string anchor_id = 4;
}
message GetProfileRequest {
bytes manifest_hash = 1;
}
message GetProfileResponse {
string capability_id = 1;
google.protobuf.Timestamp time = 2;
string cluster_id = 3;
bytes manifest_hash = 4;
string image_digest = 5;
string miner_version = 6;
string source_repo = 7;
string source_commit = 8;
bool anchored = 9;
string anchor_id = 10;
int32 leaf_index = 11;
}
message ListProfilesRequest {
string cluster_id = 1;
int64 limit = 2;
}
message ListProfilesResponse {
repeated GetProfileResponse profiles = 1;
}
message VerifyProfileRequest {
bytes manifest_hash = 1;
}
message ProofStepMsg {
enum Direction {
LEFT = 0;
RIGHT = 1;
}
Direction direction = 1;
bytes hash = 2;
}
message VerifyProfileResponse {
bool verified = 1;
string anchor_id = 2;
bytes merkle_root = 3;
repeated ProofStepMsg proof = 4;
string error = 5;
}
message FlushAnchorRequest {
string cluster_id = 1;
}
message FlushAnchorResponse {
string anchor_id = 1;
bytes merkle_root = 2;
int32 leaf_count = 3;
}

View file

@ -0,0 +1,121 @@
syntax = "proto3";
package quartermaster.v1;
import "google/protobuf/timestamp.proto";
service QuartermasterCredentials {
rpc ProvisionDatabase (ProvisionDatabaseRequest) returns (ProvisionDatabaseResponse);
rpc RotateCredential (RotateCredentialRequest) returns (RotateCredentialResponse);
rpc RevokeCredential (RevokeCredentialRequest) returns (RevokeCredentialResponse);
rpc GetCredentialRef (GetCredentialRefRequest) returns (GetCredentialRefResponse);
rpc ListCredentials (ListCredentialsRequest) returns (ListCredentialsResponse);
// Phase 8: Cloud credential provisioning via STS AssumeRole.
rpc ProvisionCloudCredential (ProvisionCloudCredentialRequest) returns (ProvisionCloudCredentialResponse);
rpc RevokeCloudCredential (RevokeCloudCredentialRequest) returns (RevokeCloudCredentialResponse);
rpc GetCloudCredential (GetCloudCredentialRequest) returns (GetCloudCredentialResponse);
}
message ProvisionDatabaseRequest {
string cluster_id = 1;
string service_name = 2;
string database_name = 3;
}
message ProvisionDatabaseResponse {
string credential_id = 1;
string secret_ref = 2;
string secret_namespace = 3;
google.protobuf.Timestamp issued_at = 4;
bytes merkle_leaf = 5;
}
message RotateCredentialRequest {
string credential_id = 1;
}
message RotateCredentialResponse {
string new_credential_id = 1;
string secret_ref = 2;
google.protobuf.Timestamp issued_at = 3;
bytes merkle_leaf = 4;
}
message RevokeCredentialRequest {
string credential_id = 1;
}
message RevokeCredentialResponse {
google.protobuf.Timestamp revoked_at = 1;
}
message GetCredentialRefRequest {
string credential_id = 1;
}
message GetCredentialRefResponse {
string credential_id = 1;
string cluster_id = 2;
string service_name = 3;
string credential_type = 4;
string username = 5;
string database_name = 6;
string secret_ref = 7;
string secret_namespace = 8;
google.protobuf.Timestamp issued_at = 9;
google.protobuf.Timestamp expires_at = 10;
bool revoked = 11;
}
message ListCredentialsRequest {
string cluster_id = 1;
}
message ListCredentialsResponse {
repeated GetCredentialRefResponse credentials = 1;
}
// Phase 8: Cloud credential provisioning messages.
message ProvisionCloudCredentialRequest {
string tenant_id = 1;
string workspace_name = 2;
string operation_id = 3;
string provider_type = 4;
string role_arn = 5;
string session_policy = 6;
uint32 duration_seconds = 7;
string external_id = 8;
}
message ProvisionCloudCredentialResponse {
string credential_ref_id = 1;
map<string, string> credentials = 2;
google.protobuf.Timestamp expires_at = 3;
string session_name = 4;
bytes merkle_leaf = 5;
}
message RevokeCloudCredentialRequest {
string credential_ref_id = 1;
}
message RevokeCloudCredentialResponse {
google.protobuf.Timestamp revoked_at = 1;
}
message GetCloudCredentialRequest {
string credential_ref_id = 1;
}
message GetCloudCredentialResponse {
string credential_ref_id = 1;
string tenant_id = 2;
string provider_type = 3;
string role_arn = 4;
string session_name = 5;
google.protobuf.Timestamp issued_at = 6;
google.protobuf.Timestamp expires_at = 7;
bool revoked = 8;
bytes merkle_leaf = 9;
}

View file

@ -0,0 +1,119 @@
syntax = "proto3";
package quartermaster.v1;
import "google/protobuf/timestamp.proto";
// Governance service for intent lifecycle and SAT issuance.
service GovernanceService {
// Create a MutationIntent called by application at user-request time.
rpc CreateIntent(CreateIntentRequest) returns (CreateIntentResponse);
// Redeem a MutationIntent called by worker at execution time.
rpc RedeemIntent(RedeemIntentRequest) returns (RedeemIntentResponse);
// Revoke a MutationIntent called to cancel pending authorization.
rpc RevokeIntent(RevokeIntentRequest) returns (RevokeIntentResponse);
// Query intents for a tenant (admin/audit use).
rpc ListIntents(ListIntentsRequest) returns (ListIntentsResponse);
}
message CreateIntentRequest {
string registry_type = 1;
string verb = 2;
string artifact_scope = 3;
string tenant_id = 4;
// Identity claim one of these should be set.
oneof identity_claim {
string oidc_token = 5;
ExternalEventClaim external_event = 6;
}
uint32 ttl_seconds = 7;
uint32 max_redemptions = 8;
string idempotency_key = 9;
}
message ExternalEventClaim {
string source = 1;
string event_id = 2;
string event_type = 3;
string verification = 4;
}
message CreateIntentResponse {
string intent_id = 1;
google.protobuf.Timestamp expires_at = 2;
bytes intent_hash = 3;
string error = 4;
bool denied = 5;
string denial_reason = 6;
// If a governance ceremony is required, this field contains the
// ceremony ID. The intent status is "ceremony_pending" and cannot
// be redeemed until the ceremony resolves.
string ceremony_id = 7;
}
message RedeemIntentRequest {
string intent_id = 1;
}
message RedeemIntentResponse {
bool success = 1;
SatToken sat = 2;
int32 remaining_redemptions = 3;
string status = 4;
string error = 5;
}
message SatToken {
bytes sat_hash = 1;
string bearer_svid = 2;
repeated SatScopeMsg scopes = 3;
google.protobuf.Timestamp issued_at = 4;
google.protobuf.Timestamp expires_at = 5;
bytes signature = 6;
bytes sat_bytes = 7;
}
message SatScopeMsg {
string registry_type = 1;
repeated string verbs = 2;
string resource_pattern = 3;
}
message RevokeIntentRequest {
string intent_id = 1;
}
message RevokeIntentResponse {
bool success = 1;
string error = 2;
}
message ListIntentsRequest {
string tenant_id = 1;
string status_filter = 2;
int32 limit = 3;
}
message ListIntentsResponse {
repeated IntentSummary intents = 1;
}
message IntentSummary {
string intent_id = 1;
string registry_type = 2;
string verb = 3;
string artifact_scope = 4;
string tenant_id = 5;
string claim_type = 6;
string claim_subject = 7;
string status = 8;
int32 max_redemptions = 9;
int32 redeemed_count = 10;
google.protobuf.Timestamp authorized_at = 11;
google.protobuf.Timestamp expires_at = 12;
}

View file

@ -0,0 +1,48 @@
syntax = "proto3";
package quartermaster.v1;
import "google/protobuf/timestamp.proto";
service QuartermasterNotary {
rpc CreateAnchor (CreateAnchorRequest) returns (CreateAnchorResponse);
rpc GetLatestAnchor (GetLatestAnchorRequest) returns (GetLatestAnchorResponse);
rpc VerifyInclusion (VerifyInclusionRequest) returns (VerifyInclusionResponse);
}
message CreateAnchorRequest {
string cluster_id = 1;
repeated bytes leaves = 2;
int64 etcd_revision = 3; // 0 means not set
}
message CreateAnchorResponse {
string anchor_id = 1;
bytes merkle_root = 2;
bytes previous_root = 3;
int32 leaf_count = 4;
google.protobuf.Timestamp time = 5;
}
message GetLatestAnchorRequest {
string cluster_id = 1;
}
message GetLatestAnchorResponse {
string anchor_id = 1;
string cluster_id = 2;
bytes merkle_root = 3;
bytes previous_root = 4;
int64 etcd_revision = 5;
int32 leaf_count = 6;
google.protobuf.Timestamp time = 7;
}
message VerifyInclusionRequest {
string anchor_id = 1;
bytes leaf = 2;
repeated bytes proof = 3;
}
message VerifyInclusionResponse {
bool valid = 1;
}

View file

@ -0,0 +1,102 @@
syntax = "proto3";
package quartermaster.v1;
import "google/protobuf/timestamp.proto";
import "quartermaster/v1/capabilities.proto";
service QuartermasterPipelines {
// Notarize a completed pipeline run result.
rpc NotarizePipelineResult (NotarizePipelineResultRequest) returns (NotarizePipelineResultResponse);
// Get the merkle inclusion proof for a notarized pipeline result.
rpc GetPipelineProof (GetPipelineProofRequest) returns (GetPipelineProofResponse);
// Query notarized pipeline results (insurer/auditor API path).
rpc QueryPipelineAttestations (QueryPipelineAttestationsRequest) returns (QueryPipelineAttestationsResponse);
// Get the current merkle root for a cluster.
rpc GetMerkleRoot (GetMerkleRootRequest) returns (GetMerkleRootResponse);
}
// NotarizePipelineResult
message NotarizePipelineResultRequest {
string cluster_id = 1;
string run_id = 2;
bytes result_canonical = 3; // RFC 8785 canonical JSON
bytes result_hash = 4; // hash_leaf(result_canonical)
string pipeline_name = 5;
string commit_hash = 6;
string status = 7; // "succeeded", "failed", "error"
string runner_svid = 8;
int32 step_count = 9;
int32 steps_passed = 10;
int32 steps_failed = 11;
}
message NotarizePipelineResultResponse {
bool accepted = 1;
string run_id = 2;
bool anchored = 3;
string anchor_id = 4;
int32 leaf_index = 5;
bytes merkle_root = 6;
google.protobuf.Timestamp notarized_at = 7;
}
// GetPipelineProof
message GetPipelineProofRequest {
bytes result_hash = 1; // Look up by hash
string run_id = 2; // Or look up by run_id
}
message GetPipelineProofResponse {
bool verified = 1;
string anchor_id = 2;
bytes merkle_root = 3;
repeated ProofStepMsg proof = 4; // Reused from capabilities.proto
string run_id = 5;
string pipeline_name = 6;
string commit_hash = 7;
string status = 8;
string error = 9;
}
// QueryPipelineAttestations
message QueryPipelineAttestationsRequest {
string commit_hash = 1;
string pipeline_name = 2;
string status = 3;
int32 limit = 4; // Default: 20
}
message QueryPipelineAttestationsResponse {
repeated PipelineAttestationSummary attestations = 1;
}
message PipelineAttestationSummary {
string run_id = 1;
string pipeline_name = 2;
string commit_hash = 3;
string status = 4;
bytes result_hash = 5;
bool anchored = 6;
string anchor_id = 7;
int32 leaf_index = 8;
google.protobuf.Timestamp notarized_at = 9;
}
// GetMerkleRoot
message GetMerkleRootRequest {
string cluster_id = 1;
}
message GetMerkleRootResponse {
string anchor_id = 1;
bytes root_hash = 2;
int32 leaf_count = 3;
google.protobuf.Timestamp computed_at = 4;
}

View file

@ -0,0 +1,58 @@
syntax = "proto3";
package quartermaster.v1;
import "google/protobuf/timestamp.proto";
import "google/protobuf/struct.proto";
service QuartermasterRegistry {
rpc RegisterCluster (RegisterClusterRequest) returns (RegisterClusterResponse);
rpc GetCluster (GetClusterRequest) returns (GetClusterResponse);
rpc ListClusters (ListClustersRequest) returns (ListClustersResponse);
rpc UpdateClusterMetadata (UpdateClusterMetadataRequest) returns (UpdateClusterMetadataResponse);
}
message RegisterClusterRequest {
string cluster_name = 1;
string trust_domain = 2;
string role = 3; // "authority", "delegate", "peer"
string provisioned_by = 4; // optional cluster_id
}
message RegisterClusterResponse {
string cluster_id = 1;
string cluster_name = 2;
string trust_domain = 3;
string role = 4;
google.protobuf.Timestamp provisioned_at = 5;
}
message GetClusterRequest {
string cluster_id = 1;
}
message GetClusterResponse {
string cluster_id = 1;
string cluster_name = 2;
string trust_domain = 3;
string role = 4;
string provisioned_by = 5;
google.protobuf.Timestamp provisioned_at = 6;
string rmm_endpoint = 7;
google.protobuf.Struct metadata = 8;
}
message ListClustersRequest {}
message ListClustersResponse {
repeated GetClusterResponse clusters = 1;
}
message UpdateClusterMetadataRequest {
string cluster_id = 1;
google.protobuf.Struct metadata = 2;
}
message UpdateClusterMetadataResponse {
string cluster_id = 1;
google.protobuf.Struct metadata = 2;
}

118
runner/v1/runner.proto Normal file
View file

@ -0,0 +1,118 @@
syntax = "proto3";
package runner.v1;
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
// Enums
enum TriggerType {
TRIGGER_TYPE_UNSPECIFIED = 0;
TRIGGER_TYPE_MERGE = 1;
TRIGGER_TYPE_TAG = 2;
TRIGGER_TYPE_MANUAL = 3;
TRIGGER_TYPE_SCHEDULE = 4;
TRIGGER_TYPE_WEBHOOK = 5;
TRIGGER_TYPE_AGENT = 6;
}
enum StepStatus {
STEP_STATUS_UNSPECIFIED = 0;
STEP_STATUS_PENDING = 1;
STEP_STATUS_RUNNING = 2;
STEP_STATUS_SUCCEEDED = 3;
STEP_STATUS_FAILED = 4;
STEP_STATUS_SKIPPED = 5;
STEP_STATUS_CANCELLED = 6;
}
enum RunPhase {
RUN_PHASE_UNSPECIFIED = 0;
RUN_PHASE_PENDING = 1;
RUN_PHASE_RUNNING = 2;
RUN_PHASE_SUCCEEDED = 3;
RUN_PHASE_FAILED = 4;
RUN_PHASE_CANCELLED = 5;
RUN_PHASE_NOTARIZED = 6;
}
// Messages
message TriggerEvent {
TriggerType trigger_type = 1;
string commit_hash = 2;
string branch = 3;
string tag = 4;
string requested_by = 5;
string merge_session_id = 6;
google.protobuf.Timestamp triggered_at = 7;
}
message StepResult {
string name = 1;
string step_type = 2;
StepStatus status = 3;
int32 exit_code = 4;
google.protobuf.Duration duration = 5;
bytes stdout_hash = 6;
bytes stderr_hash = 7;
repeated ArtifactRef artifacts = 8;
string error_message = 9;
uint32 attempt = 10;
google.protobuf.Timestamp started_at = 11;
google.protobuf.Timestamp completed_at = 12;
}
message ArtifactRef {
string name = 1;
string path = 2;
bytes content_hash = 3;
int64 size_bytes = 4;
string media_type = 5;
string oci_digest = 6;
}
message PipelineResult {
string run_id = 1;
string pipeline_name = 2;
TriggerEvent trigger = 3;
RunPhase phase = 4;
repeated StepResult steps = 5;
google.protobuf.Timestamp started_at = 6;
google.protobuf.Timestamp completed_at = 7;
google.protobuf.Duration total_duration = 8;
string runner_svid = 9;
bytes pipeline_yaml_hash = 10;
string cluster_id = 11;
AttestationInfo attestation = 12;
}
message AttestationInfo {
bool anchored = 1;
string anchor_id = 2;
bytes merkle_leaf = 3;
bytes merkle_root = 4;
int32 leaf_index = 5;
}
message LogEntry {
string step_name = 1;
string stream = 2;
string line = 3;
google.protobuf.Timestamp timestamp = 4;
uint64 sequence = 5;
}
message PipelineRunSummary {
string run_id = 1;
string pipeline_name = 2;
RunPhase phase = 3;
TriggerType trigger_type = 4;
string commit_hash = 5;
google.protobuf.Timestamp started_at = 6;
google.protobuf.Timestamp completed_at = 7;
uint32 steps_total = 8;
uint32 steps_succeeded = 9;
uint32 steps_failed = 10;
bool attested = 11;
}

100
runner/v1/service.proto Normal file
View file

@ -0,0 +1,100 @@
syntax = "proto3";
package runner.v1;
import "runner/v1/runner.proto";
import "google/protobuf/timestamp.proto";
service RunnerService {
rpc TriggerRun (TriggerRunRequest) returns (TriggerRunResponse);
rpc GetRunStatus (GetRunStatusRequest) returns (GetRunStatusResponse);
rpc StreamLogs (StreamLogsRequest) returns (stream LogEntry);
rpc CancelRun (CancelRunRequest) returns (CancelRunResponse);
rpc ListRuns (ListRunsRequest) returns (ListRunsResponse);
rpc GetPipelineSpec (GetPipelineSpecRequest) returns (GetPipelineSpecResponse);
rpc GetRunAttestation (GetRunAttestationRequest) returns (GetRunAttestationResponse);
}
message TriggerRunRequest {
string pipeline_name = 1;
string commit_hash = 2;
TriggerType trigger_type = 3;
string requested_by = 4;
map<string, string> parameters = 5;
// Branch name (for inbound sync triggers, e.g. "inbound/github-origin/pull/42/head")
string branch = 6;
// Name of the inbound remote that triggered this run (empty for non-inbound triggers)
string inbound_remote = 7;
}
message TriggerRunResponse {
string run_id = 1;
RunPhase phase = 2;
string message = 3;
bool deduplicated = 4;
string dedup_run_id = 5;
}
message GetRunStatusRequest {
string run_id = 1;
}
message GetRunStatusResponse {
PipelineResult result = 1;
}
message StreamLogsRequest {
string run_id = 1;
string step_name = 2;
bool follow = 3;
uint64 since_sequence = 4;
}
message CancelRunRequest {
string run_id = 1;
string reason = 2;
}
message CancelRunResponse {
bool success = 1;
string message = 2;
}
message ListRunsRequest {
string pipeline_name = 1;
RunPhase phase_filter = 2;
TriggerType trigger_filter = 3;
uint32 limit = 4;
string commit_hash = 5;
}
message ListRunsResponse {
repeated PipelineRunSummary runs = 1;
}
message GetPipelineSpecRequest {
string commit_hash = 1;
string pipeline_name = 2;
}
message GetPipelineSpecResponse {
string pipeline_yaml = 1;
string commit_hash = 2;
bytes pipeline_hash = 3;
}
message GetRunAttestationRequest {
string run_id = 1;
}
message GetRunAttestationResponse {
string run_id = 1;
bytes result_hash = 2;
string anchor_id = 3;
bytes merkle_root = 4;
int32 leaf_index = 5;
string runner_svid = 6;
string commit_hash = 7;
string pipeline_name = 8;
string status = 9;
google.protobuf.Timestamp notarized_at = 10;
}

View file

@ -0,0 +1,261 @@
syntax = "proto3";
package schematic.v1;
import "google/protobuf/timestamp.proto";
service SchematicsService {
// Create a new schematic from a file tree
rpc CreateSchematic(CreateSchematicRequest) returns (CreateSchematicResponse);
// Get a schematic version
rpc GetSchematic(GetSchematicRequest) returns (GetSchematicResponse);
// List all versions of a schematic
rpc ListVersions(ListVersionsRequest) returns (ListVersionsResponse);
// Update a draft schematic's file tree
rpc UpdateSchematic(UpdateSchematicRequest) returns (UpdateSchematicResponse);
// Validate a schematic against all validators
rpc ValidateSchematic(ValidateSchematicRequest) returns (ValidateSchematicResponse);
// Record a stakeholder approval
rpc ApproveSchematic(ApproveSchematicRequest) returns (ApproveSchematicResponse);
// Get approval status
rpc GetApprovalStatus(GetApprovalStatusRequest) returns (GetApprovalStatusResponse);
// Publish an approved schematic as an immutable snapshot
rpc PublishSchematic(PublishSchematicRequest) returns (PublishSchematicResponse);
// Create a new version from a published schematic
rpc CreateNextVersion(CreateNextVersionRequest) returns (CreateNextVersionResponse);
// Fork a schematic with template operations
rpc ForkSchematic(ForkSchematicRequest) returns (ForkSchematicResponse);
// Create a deployment binding
rpc CreateDeploymentBinding(CreateDeploymentBindingRequest) returns (CreateDeploymentBindingResponse);
// Get deployment binding status
rpc GetDeploymentBinding(GetDeploymentBindingRequest) returns (GetDeploymentBindingResponse);
}
// --- Create ---
message CreateSchematicRequest {
string name = 1;
string version = 2;
// YAML content of schematic.yaml manifest
bytes manifest_yaml = 3;
// Files as path:content pairs
repeated SchematicFile files = 4;
}
message SchematicFile {
string path = 1;
bytes content = 2;
}
message CreateSchematicResponse {
string name = 1;
string version = 2;
string tree_hash = 3;
string status = 4;
}
// --- Get ---
message GetSchematicRequest {
string name = 1;
string version = 2;
}
message GetSchematicResponse {
string name = 1;
string version = 2;
string tree_hash = 3;
string status = 4;
string parent_hash = 5;
repeated StakeholderInfo stakeholders = 6;
google.protobuf.Timestamp created_at = 7;
}
message StakeholderInfo {
string role = 1;
string identity = 2;
bool required = 3;
}
// --- List Versions ---
message ListVersionsRequest {
string name = 1;
}
message ListVersionsResponse {
repeated VersionInfo versions = 1;
}
message VersionInfo {
string version = 1;
string tree_hash = 2;
string status = 3;
string parent_hash = 4;
google.protobuf.Timestamp created_at = 5;
}
// --- Update ---
message UpdateSchematicRequest {
string name = 1;
string version = 2;
repeated SchematicFile files = 3;
}
message UpdateSchematicResponse {
string tree_hash = 1;
string status = 2;
}
// --- Validate ---
message ValidateSchematicRequest {
string name = 1;
string version = 2;
}
message ValidateSchematicResponse {
bool valid = 1;
int32 error_count = 2;
int32 warning_count = 3;
repeated ValidationResultProto results = 4;
}
message ValidationResultProto {
string validator = 1;
bool passed = 2;
string message = 3;
string severity = 4;
}
// --- Approve ---
message ApproveSchematicRequest {
string name = 1;
string version = 2;
string role = 3;
string identity = 4;
string tree_hash = 5;
string comment = 6;
}
message ApproveSchematicResponse {
bool accepted = 1;
string approval_status = 2;
string message = 3;
}
// --- Approval Status ---
message GetApprovalStatusRequest {
string name = 1;
string version = 2;
}
message GetApprovalStatusResponse {
string status = 1;
repeated string approved_roles = 2;
repeated string remaining_roles = 3;
repeated ApprovalInfo approvals = 4;
}
message ApprovalInfo {
string role = 1;
string identity = 2;
google.protobuf.Timestamp approved_at = 3;
string comment = 4;
}
// --- Publish ---
message PublishSchematicRequest {
string name = 1;
string version = 2;
}
message PublishSchematicResponse {
string tree_hash = 1;
string status = 2;
}
// --- Create Next Version ---
message CreateNextVersionRequest {
string name = 1;
string from_version = 2;
// "major", "minor", or "patch"
string bump = 3;
}
message CreateNextVersionResponse {
string version = 1;
string tree_hash = 2;
string parent_hash = 3;
string status = 4;
}
// --- Fork ---
message ForkSchematicRequest {
string source_name = 1;
string source_version = 2;
string new_name = 3;
string new_version = 4;
repeated TemplateOperation operations = 5;
}
message TemplateOperation {
// "replace", "add", "remove", "remove_section"
string op_type = 1;
string path = 2;
bytes content = 3;
}
message ForkSchematicResponse {
string name = 1;
string version = 2;
string tree_hash = 3;
string status = 4;
}
// --- Deployment Binding ---
message CreateDeploymentBindingRequest {
string schematic_name = 1;
string schematic_version = 2;
string pipeline_name = 3;
string target_env = 4;
}
message CreateDeploymentBindingResponse {
string binding_id = 1;
string status = 2;
}
message GetDeploymentBindingRequest {
string binding_id = 1;
}
message GetDeploymentBindingResponse {
string binding_id = 1;
string schematic_name = 2;
string schematic_version = 3;
string tree_hash = 4;
string pipeline_name = 5;
string target_env = 6;
string status = 7;
string run_id = 8;
google.protobuf.Timestamp created_at = 9;
google.protobuf.Timestamp deployed_at = 10;
}

View file

@ -0,0 +1,424 @@
syntax = "proto3";
package workspace.v1;
import "google/protobuf/timestamp.proto";
service WorkspaceController {
// Initialize the canonical repository (first-time setup)
rpc InitCanonical(InitCanonicalRequest) returns (InitCanonicalResponse);
// Get canonical repo status
rpc GetCanonicalHead(GetCanonicalHeadRequest) returns (GetCanonicalHeadResponse);
// Session workspace lifecycle
rpc CreateWorkspace(CreateWorkspaceRequest) returns (CreateWorkspaceResponse);
rpc GetWorkspaceStatus(GetWorkspaceStatusRequest) returns (GetWorkspaceStatusResponse);
rpc DestroyWorkspace(DestroyWorkspaceRequest) returns (DestroyWorkspaceResponse);
// Diff and commit
rpc GetDiff(GetDiffRequest) returns (GetDiffResponse);
rpc StageFiles(StageFilesRequest) returns (StageFilesResponse);
rpc Commit(CommitRequest) returns (CommitResponse);
rpc GetLog(GetLogRequest) returns (GetLogResponse);
// Abandon (discard all changes)
rpc Abandon(AbandonRequest) returns (AbandonResponse);
// List active workspaces
rpc ListWorkspaces(ListWorkspacesRequest) returns (ListWorkspacesResponse);
// Get a tar archive of the canonical repo at a specific commit
rpc GetArchive(GetArchiveRequest) returns (stream ArchiveChunk);
// --- Remote sync (Phase 3) ---
// Push canonical branch to a configured remote
rpc PushToRemote(PushToRemoteRequest) returns (PushToRemoteResponse);
// Fetch refs from a configured remote into inbound/ branches
rpc FetchFromRemote(FetchFromRemoteRequest) returns (FetchFromRemoteResponse);
// List configured remotes from .guildhouse/remotes.yaml
rpc ListRemotes(ListRemotesRequest) returns (ListRemotesResponse);
// Get sync status between canonical and a remote
rpc GetRemoteSyncStatus(GetRemoteSyncStatusRequest) returns (GetRemoteSyncStatusResponse);
// Report commit status check to a remote provider (GitHub/Forgejo/GitLab)
rpc ReportStatus(ReportStatusRequest) returns (ReportStatusResponse);
// --- Merge operations (Phase 4) ---
// Merge an inbound branch into canonical main
rpc MergeToCanonical(MergeToCanonicalRequest) returns (MergeToCanonicalResponse);
// Clean up an inbound branch after merge or rejection
rpc CleanupInboundBranch(CleanupInboundBranchRequest) returns (CleanupInboundBranchResponse);
// List inbound branches (fetched from remotes)
rpc ListInboundBranches(ListInboundBranchesRequest) returns (ListInboundBranchesResponse);
// Lightweight remote HEAD check (ls-remote equivalent no objects fetched)
rpc LsRemote(LsRemoteRequest) returns (LsRemoteResponse);
}
// --- Canonical ---
message InitCanonicalRequest {
// Path to a directory of manifests to import as the initial commit.
// If empty, creates an empty repo with just .guildhouse/ structure.
string import_path = 1;
// Commit author
string author = 2;
}
message InitCanonicalResponse {
string commit_hash = 1;
string message = 2;
}
message GetCanonicalHeadRequest {}
message GetCanonicalHeadResponse {
string commit_hash = 1;
string message = 2;
string author = 3;
google.protobuf.Timestamp timestamp = 4;
uint32 total_files = 5;
}
// --- Session workspace lifecycle ---
message CreateWorkspaceRequest {
string session_id = 1;
// Branch to base the workspace on (default: "main")
string base_branch = 2;
// Git author for commits in this workspace
string author_name = 3;
string author_email = 4;
// If true, workspace is read-only (no branch created, just a checkout)
bool read_only = 5;
}
message CreateWorkspaceResponse {
// Filesystem path to the workspace root
string workspace_path = 1;
// Git branch name (empty if read_only)
string branch_name = 2;
// SHA of the base commit
string base_commit = 3;
}
message GetWorkspaceStatusRequest {
string session_id = 1;
}
message GetWorkspaceStatusResponse {
string session_id = 1;
string branch_name = 2;
string base_commit = 3;
string head_commit = 4;
uint32 commits_ahead = 5;
uint32 files_changed = 6;
uint32 insertions = 7;
uint32 deletions = 8;
bool has_uncommitted_changes = 9;
bool read_only = 10;
}
message DestroyWorkspaceRequest {
string session_id = 1;
}
message DestroyWorkspaceResponse {
bool success = 1;
string message = 2;
}
// --- Diff and commit ---
message GetDiffRequest {
string session_id = 1;
// If true: diff uncommitted changes only (workspace vs HEAD)
// If false: diff entire branch vs base (session branch vs main)
bool uncommitted_only = 2;
}
message GetDiffResponse {
repeated FileDiff files = 1;
string base_ref = 2;
string head_ref = 3;
uint32 total_insertions = 4;
uint32 total_deletions = 5;
}
message FileDiff {
string path = 1;
// "added", "modified", "deleted", "renamed"
string status = 2;
// Unified diff text (empty for binary files)
string diff_text = 3;
uint32 insertions = 4;
uint32 deletions = 5;
// For renames: the old path
string old_path = 6;
}
message StageFilesRequest {
string session_id = 1;
// File paths to stage (relative to workspace root).
// Empty = stage all changes (git add -A).
repeated string paths = 2;
}
message StageFilesResponse {
uint32 files_staged = 1;
}
message CommitRequest {
string session_id = 1;
string message = 2;
// Override author (if empty, uses the author from CreateWorkspace)
string author_name = 3;
string author_email = 4;
}
message CommitResponse {
string commit_hash = 1;
uint32 files_committed = 2;
string message = 3;
}
message GetLogRequest {
string session_id = 1;
// Max number of commits to return (default: 20)
uint32 limit = 2;
}
message GetLogResponse {
repeated CommitEntry commits = 1;
}
message CommitEntry {
string hash = 1;
string short_hash = 2;
string message = 3;
string author_name = 4;
string author_email = 5;
google.protobuf.Timestamp timestamp = 6;
uint32 files_changed = 7;
}
// --- Abandon ---
message AbandonRequest {
string session_id = 1;
}
message AbandonResponse {
bool success = 1;
uint32 commits_discarded = 2;
string message = 3;
}
// --- List workspaces ---
message ListWorkspacesRequest {}
message ListWorkspacesResponse {
repeated WorkspaceSummary workspaces = 1;
}
message WorkspaceSummary {
string session_id = 1;
string branch_name = 2;
string base_commit = 3;
string head_commit = 4;
uint32 commits_ahead = 5;
bool has_uncommitted_changes = 6;
bool read_only = 7;
google.protobuf.Timestamp created_at = 8;
}
// --- Archive ---
message GetArchiveRequest {
// Commit hash to archive (empty = HEAD)
string commit_hash = 1;
// Subset of paths to include (empty = all files)
repeated string paths = 2;
}
message ArchiveChunk {
bytes data = 1;
}
// --- Remote sync ---
message PushToRemoteRequest {
// Name of the remote (must exist in .guildhouse/remotes.yaml)
string remote_name = 1;
// Local branch to push (default: "main")
string branch = 2;
// Force push always false in Phase 3
bool force = 3;
}
message PushToRemoteResponse {
bool success = 1;
// Remote ref that was updated (e.g. "refs/heads/main")
string remote_ref = 2;
// Commit hash that was pushed
string commit_hash = 3;
string error = 4;
}
message FetchFromRemoteRequest {
// Name of the remote (must exist in .guildhouse/remotes.yaml)
string remote_name = 1;
// Ref patterns to fetch (e.g. "refs/pull/*/head").
// If empty, uses fetch_refs from remotes.yaml config.
repeated string ref_patterns = 2;
}
message FetchFromRemoteResponse {
repeated FetchedRef refs_fetched = 1;
string error = 2;
}
message FetchedRef {
// Local ref name (e.g. "inbound/github-origin/pull/42/head")
string ref_name = 1;
// Commit hash at the tip of this ref
string commit_hash = 2;
// True if this is a newly fetched ref (not previously seen)
bool is_new = 3;
}
message ListRemotesRequest {}
message ListRemotesResponse {
repeated RemoteInfo remotes = 1;
}
message RemoteInfo {
string name = 1;
string url = 2;
// "github", "forgejo", or "gitlab"
string provider = 3;
string push_branch = 4;
// Last commit hash successfully pushed to this remote (empty if never pushed)
string last_push_hash = 5;
// Last time a fetch was performed from this remote
google.protobuf.Timestamp last_fetch_time = 6;
}
message GetRemoteSyncStatusRequest {
string remote_name = 1;
}
message GetRemoteSyncStatusResponse {
string remote_name = 1;
string canonical_head = 2;
string remote_head = 3;
uint32 commits_ahead = 4;
uint32 commits_behind = 5;
google.protobuf.Timestamp last_push = 6;
google.protobuf.Timestamp last_fetch = 7;
}
message ReportStatusRequest {
// Name of the remote (determines provider + credentials)
string remote_name = 1;
// Commit SHA to report status for
string commit_hash = 2;
// Status state: "pending", "success", "failure", "error"
string state = 3;
// Context label (e.g. "guildhouse/pipeline")
string context = 4;
// Human-readable description
string description = 5;
// URL to link to (e.g. pipeline run URL)
string target_url = 6;
// Attestation hash (hex-encoded) to include in description
string attestation_hash = 7;
}
message ReportStatusResponse {
bool success = 1;
// URL of the created status check (provider-specific)
string url = 2;
string error = 3;
}
// --- Merge operations ---
message MergeToCanonicalRequest {
// Branch name to merge (e.g. "inbound/github-origin/pull/42/head")
string branch_name = 1;
// Merge commit message
string merge_message = 2;
// Author for the merge commit
string author_name = 3;
string author_email = 4;
// Ceremony ID if the merge was approved via Accord
string ceremony_id = 5;
}
message MergeToCanonicalResponse {
bool success = 1;
// New HEAD commit hash after merge
string new_head = 2;
// "fast_forward" or "merge_commit"
string merge_type = 3;
// Error message (empty on success)
string error = 4;
// Number of files changed in the merge
uint32 files_changed = 5;
}
message CleanupInboundBranchRequest {
// Branch name to clean up
string branch_name = 1;
}
message CleanupInboundBranchResponse {
bool success = 1;
string message = 2;
}
message ListInboundBranchesRequest {
// Optional: filter by remote name
string remote_name = 1;
}
message ListInboundBranchesResponse {
repeated InboundBranchInfo branches = 1;
}
message InboundBranchInfo {
string branch_name = 1;
string commit_hash = 2;
string remote_name = 3;
// Original ref (e.g. "pull/42/head")
string original_ref = 4;
}
// --- Lightweight remote ref check ---
message LsRemoteRequest {
// Name of the remote
string remote_name = 1;
// Ref patterns to query (e.g. "refs/heads/main")
repeated string refs = 2;
}
message LsRemoteResponse {
repeated RemoteRef refs = 1;
string error = 2;
}
message RemoteRef {
string ref_name = 1;
string commit_hash = 2;
}