// A protobuf-based API for communication between // the Warp client and the remote server binary. // // Messages are length-prefixed: [4-byte little-endian length][protobuf bytes]. syntax = "proto3"; package remote_server; // ── Top-level envelopes ─────────────────────────────────────────── // Top-level envelope for all client → server messages. message ClientMessage { string request_id = 1; oneof message { Initialize initialize = 2; Abort abort = 3; NavigatedToDirectory navigated_to_directory = 4; LoadRepoMetadataDirectory load_repo_metadata_directory = 5; SessionBootstrapped session_bootstrapped = 6; WriteFile write_file = 7; DeleteFile delete_file = 8; RunCommandRequest run_command = 9; ReadFileContextRequest read_file_context = 10; Authenticate authenticate = 11; } } // Top-level envelope for all server → client messages. // Push messages use an empty request_id to distinguish them from // request/response pairs. message ServerMessage { string request_id = 1; oneof message { InitializeResponse initialize_response = 2; ErrorResponse error = 3; NavigatedToDirectoryResponse navigated_to_directory_response = 4; RepoMetadataSnapshot repo_metadata_snapshot = 5; RepoMetadataUpdatePush repo_metadata_update = 6; LoadRepoMetadataDirectoryResponse load_repo_metadata_directory_response = 7; WriteFileResponse write_file_response = 8; DeleteFileResponse delete_file_response = 9; RunCommandResponse run_command_response = 10; ReadFileContextResponse read_file_context_response = 11; } } // ── Initialize handshake // Sent by the client immediately after connecting to negotiate the protocol. message Initialize { // Optional bearer token used by the daemon for Warp-server requests. // Empty means no credential was available and does not clear an existing // daemon credential. string auth_token = 1; } // Sent by the client when its bearer credential rotates after initialization. // This is a notification (fire-and-forget) — the server does not send a response. message Authenticate { // Optional bearer token used by the daemon for Warp-server requests. // Empty means no credential was available and does not clear an existing // daemon credential. string auth_token = 1; } // Sent by the client to cancel an in-progress request. // This is a notification (fire-and-forget) — the server does not send a response. message Abort { string request_id_to_abort = 1; } // Returned by the server in response to Initialize. message InitializeResponse { string server_version = 1; string host_id = 2; } // Sent by the client after the SSH session has been bootstrapped. // This is a notification (fire-and-forget) — the server does not send a // response. The server uses this to create a per-session // LocalCommandExecutor matching the bootstrapped shell. message SessionBootstrapped { uint64 session_id = 1; string shell_type = 2; // The full path to the shell binary (e.g. "/usr/bin/zsh"). // When present, the server uses this directly instead of doing a PATH lookup. optional string shell_path = 3; } // Sent by the client to execute a shell command on the remote host. message RunCommandRequest { string command = 1; // Working directory for the command. If empty, uses the server's default. optional string working_directory = 2; // Environment variables to set for the command. map environment_variables = 3; // The session whose shell executor should run this command. uint64 session_id = 4; } // Specific error codes for RunCommandRequest failures. enum RunCommandErrorCode { RUN_COMMAND_ERROR_CODE_UNSPECIFIED = 0; // The session ID has no associated executor (session was never bootstrapped). SESSION_NOT_FOUND = 1; // The command could not be executed (e.g. the shell process failed to spawn). EXECUTION_FAILED = 2; } message RunCommandError { RunCommandErrorCode code = 1; string message = 2; } message RunCommandSuccess { bytes stdout = 1; bytes stderr = 2; // Absent when the process was killed by a signal (Unix). optional int32 exit_code = 3; } // Returned by the server with the result of a RunCommandRequest. message RunCommandResponse { oneof result { RunCommandSuccess success = 1; RunCommandError error = 2; } } // ── Shared error response ───────────────────────────────────────── enum ErrorCode { ERROR_CODE_UNSPECIFIED = 0; // The request was malformed (e.g. missing oneof variant). INVALID_REQUEST = 1; // An unexpected server-side failure. INTERNAL = 2; } message ErrorResponse { ErrorCode code = 1; string message = 2; } // ── Shared repo metadata sub-messages ───────────────────────────── // Mirror the Rust types in repo_metadata/src/file_tree_update.rs. // Mirrors RepoNodeMetadata in Rust. message RepoNodeMetadata { oneof node { DirectoryNodeMetadata directory = 1; FileNodeMetadata file = 2; } } // Mirrors DirectoryNodeMetadata in Rust. message DirectoryNodeMetadata { string path = 1; bool ignored = 2; bool loaded = 3; } // Mirrors FileNodeMetadata in Rust. message FileNodeMetadata { string path = 1; optional string extension = 2; bool ignored = 3; } // Mirrors FileTreeEntryUpdate in Rust. Describes a subtree patch rooted // at a parent directory. message RepoMetadataEntryUpdate { string parent_path_to_replace = 1; repeated RepoNodeMetadata subtree_metadata = 2; } // ── NavigatedToDirectory ────────────────────────────────────────── // Client → server: "I navigated to this directory, please index it." message NavigatedToDirectory { string path = 1; } // Response after the server has run git detection on the requested path. // When is_git is true, indexed_path is the git repo root and full indexing // runs in the background. A RepoMetadataSnapshot push will follow. // When is_git is false, the directory was lazily indexed at first level. // A RepoMetadataSnapshot push with the lazy tree data will follow. message NavigatedToDirectoryResponse { string indexed_path = 1; bool is_git = 2; } // ── LoadRepoMetadataDirectory ───────────────────────────────────── // Client → server: load the next level of a subdirectory within an // already-tracked repo (lazy expand). message LoadRepoMetadataDirectory { string repo_path = 1; string dir_path = 2; } // Response with the loaded subtree entries for the requested directory. message LoadRepoMetadataDirectoryResponse { string repo_path = 1; string dir_path = 2; repeated RepoMetadataEntryUpdate entries = 3; } // ── File write/delete operations ────────────────────────────────── // Shared error type for file operations (read/write/delete). message FileOperationError { string message = 1; } // Client → server: write content to a file, creating parent dirs if needed. message WriteFile { string path = 1; string content = 2; } // Server → client: result of a WriteFile request. message WriteFileResponse { oneof result { WriteFileSuccess success = 1; FileOperationError error = 2; } } message WriteFileSuccess {} // Client → server: delete a file. message DeleteFile { string path = 1; } // Server → client: result of a DeleteFile request. message DeleteFileResponse { oneof result { DeleteFileSuccess success = 1; FileOperationError error = 2; } } message DeleteFileSuccess {} // ── Read file context (batch) ───────────────────────────────────── // A single file to read, with optional line ranges. message ReadFileContextFile { string path = 1; // 1-indexed line ranges (start..end). Empty = read entire file. repeated LineRange line_ranges = 2; } message LineRange { uint32 start = 1; uint32 end = 2; } // Client → server: batch read multiple files with full context. message ReadFileContextRequest { repeated ReadFileContextFile files = 1; // Per-file byte limit. Absent = use server default. optional uint32 max_file_bytes = 2; // Cumulative byte budget across all files. Absent = no batch limit. optional uint32 max_batch_bytes = 3; } // Server → client: result of a ReadFileContextRequest. // Per-file failures are reported in `failed_files`, not as a top-level error. // Catastrophic server errors (malformed request, etc.) use the generic ErrorResponse. message ReadFileContextResponse { repeated FileContextProto file_contexts = 1; repeated FailedFileRead failed_files = 2; } message FailedFileRead { string path = 1; FileOperationError error = 2; } message FileContextProto { string file_name = 1; oneof content { string text_content = 2; bytes binary_content = 3; } // Optional 1-indexed line range this segment covers. optional uint32 line_range_start = 4; optional uint32 line_range_end = 5; optional uint64 last_modified_epoch_millis = 6; uint32 line_count = 7; } // ── Server → client push messages ───────────────────────────────── // Full or lazy-loaded repo metadata snapshot. Pushed by the server after // NavigatedToDirectory completes indexing (either lazy or full git). message RepoMetadataSnapshot { string repo_path = 1; repeated RepoMetadataEntryUpdate entries = 2; bool sync_complete = 3; } // Incremental repo metadata update. Mirrors RepoMetadataUpdate in Rust. message RepoMetadataUpdatePush { string repo_path = 1; repeated string remove_entries = 2; repeated RepoMetadataEntryUpdate update_entries = 3; }