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; }