Skills grpc
git clone https://github.com/TerminalSkills/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/grpc" ~/.claude/skills/terminalskills-skills-grpc && rm -rf "$T"
skills/grpc/SKILL.md- pip install
gRPC
Overview
Build high-performance, strongly-typed RPC services using gRPC and Protocol Buffers. gRPC uses HTTP/2 for transport, protobuf for serialization (10x smaller than JSON, 5-10x faster parsing), and generates client/server code in 12+ languages. Ideal for microservice communication, real-time streaming, and performance-critical APIs.
Instructions
Step 1: Install Tools
# Protocol Buffer Compiler brew install protobuf # macOS apt install -y protobuf-compiler # Ubuntu/Debian # Node.js npm install @grpc/grpc-js @grpc/proto-loader # Python pip install grpcio grpcio-tools grpcio-reflection grpcio-health-checking # Go go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Step 2: Define Protocol Buffers
// proto/user_service.proto syntax = "proto3"; package userservice.v1; import "google/protobuf/timestamp.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/field_mask.proto"; service UserService { rpc GetUser(GetUserRequest) returns (User); rpc CreateUser(CreateUserRequest) returns (User); rpc UpdateUser(UpdateUserRequest) returns (User); rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty); rpc ListUsers(ListUsersRequest) returns (ListUsersResponse); rpc WatchUser(WatchUserRequest) returns (stream UserEvent); // Server streaming rpc BatchCreateUsers(stream CreateUserRequest) returns (BatchCreateUsersResponse); // Client streaming rpc Chat(stream ChatMessage) returns (stream ChatMessage); // Bidirectional } message User { string id = 1; string email = 2; string name = 3; Role role = 5; google.protobuf.Timestamp created_at = 6; } enum Role { ROLE_UNSPECIFIED = 0; ROLE_USER = 1; ROLE_ADMIN = 2; } message GetUserRequest { string id = 1; } message CreateUserRequest { string email = 1; string name = 2; string password = 3; } message UpdateUserRequest { string id = 1; string name = 2; google.protobuf.FieldMask update_mask = 4; } message DeleteUserRequest { string id = 1; } message ListUsersRequest { int32 page_size = 1; string page_token = 2; string filter = 3; } message ListUsersResponse { repeated User users = 1; string next_page_token = 2; int32 total_count = 3; } message WatchUserRequest { string id = 1; } message UserEvent { enum EventType { EVENT_TYPE_UNSPECIFIED = 0; EVENT_TYPE_UPDATED = 1; EVENT_TYPE_DELETED = 2; } EventType type = 1; User user = 2; google.protobuf.Timestamp timestamp = 3; } message BatchCreateUsersResponse { int32 created_count = 1; repeated string failed_emails = 2; } message ChatMessage { string sender_id = 1; string text = 2; google.protobuf.Timestamp timestamp = 3; }
Protobuf rules: field numbers are forever (never reuse), use
UNSPECIFIED = 0 for enums, repeated for lists, FieldMask for partial updates, Timestamp for dates, version via package name (userservice.v1).
Step 3: Generate Code
# Python python -m grpc_tools.protoc -I proto --python_out=gen --grpc_python_out=gen --pyi_out=gen proto/user_service.proto # Go protoc -I proto --go_out=gen --go_opt=paths=source_relative --go-grpc_out=gen --go-grpc_opt=paths=source_relative proto/user_service.proto
Node.js can load protos dynamically (no codegen needed):
const grpc = require('@grpc/grpc-js'); const protoLoader = require('@grpc/proto-loader'); const packageDef = protoLoader.loadSync('proto/user_service.proto', { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true, }); const proto = grpc.loadPackageDefinition(packageDef).userservice.v1;
Step 4: Server Implementation (Node.js)
const userService = { GetUser(call, callback) { const user = users.get(call.request.id); if (!user) return callback({ code: grpc.status.NOT_FOUND, message: `User ${call.request.id} not found` }); callback(null, user); }, CreateUser(call, callback) { const { email, name } = call.request; const user = { id: crypto.randomUUID(), email, name, role: 'ROLE_USER', created_at: { seconds: Date.now() / 1000 } }; users.set(user.id, user); callback(null, user); }, WatchUser(call) { // Server streaming const interval = setInterval(() => { const user = users.get(call.request.id); if (user) call.write({ type: 'EVENT_TYPE_UPDATED', user, timestamp: { seconds: Date.now() / 1000 } }); }, 5000); call.on('cancelled', () => clearInterval(interval)); }, BatchCreateUsers(call, callback) { // Client streaming let created = 0; const failed = []; call.on('data', (req) => { users.set(crypto.randomUUID(), { email: req.email, name: req.name }); created++; }); call.on('end', () => callback(null, { created_count: created, failed_emails: failed })); }, Chat(call) { // Bidirectional streaming call.on('data', (msg) => call.write({ sender_id: 'server', text: `Received: ${msg.text}` })); call.on('end', () => call.end()); }, }; const server = new grpc.Server(); server.addService(proto.UserService.service, userService); server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {});
Step 5: Client Implementation
const client = new proto.UserService('localhost:50051', grpc.credentials.createInsecure()); // Unary with deadline const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 5); client.GetUser({ id: '123' }, { deadline }, (err, user) => { if (!err) console.log(user); }); // Server streaming const stream = client.WatchUser({ id: '123' }); stream.on('data', (event) => console.log('Event:', event)); // Client streaming const batch = client.BatchCreateUsers((err, resp) => console.log(`Created: ${resp.created_count}`)); batch.write({ email: 'alice@test.com', name: 'Alice' }); batch.write({ email: 'bob@test.com', name: 'Bob' }); batch.end();
Step 6: Error Handling
gRPC Status Codes: NOT_FOUND (5) — Resource missing (like HTTP 404) INVALID_ARGUMENT (3) — Bad input (like HTTP 400) UNAUTHENTICATED (16) — Not authenticated (like HTTP 401) PERMISSION_DENIED (7) — Forbidden (like HTTP 403) ALREADY_EXISTS (6) — Duplicate (like HTTP 409) RESOURCE_EXHAUSTED (8) — Rate limited (like HTTP 429) DEADLINE_EXCEEDED (4) — Timeout UNAVAILABLE (14) — Service down (like HTTP 503) INTERNAL (13) — Server error (like HTTP 500)
Step 7: Testing with grpcurl
brew install grpcurl grpcurl -plaintext localhost:50051 list grpcurl -plaintext -d '{"email": "alice@test.com", "name": "Alice"}' \ localhost:50051 userservice.v1.UserService/CreateUser
Examples
Example 1: Build a user microservice with gRPC
User prompt: "Create a gRPC user service in Node.js with CRUD operations and server streaming for live user updates."
The agent will:
- Create
withproto/user_service.proto
definingUserService
,GetUser
,CreateUser
(unary RPCs) andListUsers
(server streaming)WatchUser - Load the proto dynamically using
@grpc/proto-loader - Implement handlers for each RPC method, using proper status codes (
,NOT_FOUND
)ALREADY_EXISTS - Start the server on port 50051 and verify with
grpcurl -plaintext localhost:50051 list
Example 2: Add batch user import with client streaming
User prompt: "Add a batch import endpoint to the user service that accepts a stream of user records from a CSV file and returns a summary of created/failed records."
The agent will:
- Add a
RPC to the proto fileBatchCreateUsers(stream CreateUserRequest) returns (BatchCreateUsersResponse) - Implement the server handler with
to process each streamed request, tracking created count and failed emailscall.on('data') - Build a client script that reads the CSV, streams each row as a
, and callsCreateUserRequest
when donebatch.end() - Return the
withBatchCreateUsersResponse
andcreated_count
arrayfailed_emails
Guidelines
- Proto design is your API contract — review it as carefully as database schemas
- Never change field numbers — add new fields, deprecate old ones with
reserved - Use
for updates — distinguishes "not sent" from "set to empty"FieldMask - Always set deadlines — unbound calls leak resources; 5-30s for most RPCs
- Enable reflection in dev — makes debugging with grpcurl/grpcui easy
- Health checks on every service — standard gRPC health protocol for load balancers
- Interceptors for cross-cutting concerns — auth, logging, metrics, tracing
- Use streaming sparingly — unary RPCs are simpler to debug and load-balance
- Version via package name —
,userservice.v1userservice.v2 - Keep messages small — gRPC default max is 4MB; large payloads should be chunked