.clinerules/protobuf-development.md
This guide outlines how to add new gRPC endpoints for communication between the webview (frontend) and the extension host (backend).
Cline uses Protobuf to define a strongly-typed API, ensuring efficient and type-safe communication. All definitions are in the /proto directory. The compiler and plugins are included as project dependencies, so no manual installation is needed.
.proto file (e.g., account.proto, task.proto).proto/common.proto (e.g., StringRequest, Empty, Int64Request). This promotes consistency..proto file (see task.proto for examples like NewTaskRequest).PascalCaseService (e.g., AccountService).camelCase (e.g., accountEmailIdentified).PascalCase (e.g., StringRequest).stream keyword on the response type. See subscribeToAuthCallback in account.proto for an example.Here’s how to add a new RPC, using scrollToSettings as an example.
.proto FileAdd your service method to the appropriate file in the proto/ directory.
File: proto/ui.proto
service UiService {
// ... other RPCs
// Scrolls to a specific settings section in the settings view
rpc scrollToSettings(StringRequest) returns (KeyValuePair);
}
Here, we use the common StringRequest and KeyValuePair types.
After editing a .proto file, regenerate the TypeScript code. From the project root, run:
npm run protos
This command compiles all .proto files and outputs the generated code to src/generated/ and src/shared/. Do not edit these generated files manually.
Create the RPC implementation in the backend. Handlers are located in src/core/controller/[service-name]/.
File: src/core/controller/ui/scrollToSettings.ts
import { Controller } from ".."
import { StringRequest, KeyValuePair } from "../../../shared/proto/common"
/**
* Executes a scroll to settings action
* @param controller The controller instance
* @param request The request containing the ID of the settings section to scroll to
* @returns KeyValuePair with action and value fields for the UI to process
*/
export async function scrollToSettings(controller: Controller, request: StringRequest): Promise<KeyValuePair> {
return KeyValuePair.create({
key: "scrollToSettings",
value: request.value || "",
})
}
Call the new RPC from a React component in webview-ui/. The generated client makes this simple.
File: webview-ui/src/components/browser/BrowserSettingsMenu.tsx (Example)
import { UiServiceClient } from "../../../services/grpc"
import { StringRequest } from "../../../../shared/proto/common"
// ... inside a React component
const handleMenuClick = async () => {
try {
await UiServiceClient.scrollToSettings(StringRequest.create({ value: "browser" }))
} catch (error) {
console.error("Error scrolling to browser settings:", error)
}
}