Claude Agent Skill · by Samber

Golang Grpc

Install Golang Grpc skill for Claude Code from samber/cc-skills-golang.

Install
Terminal · npx
$npx skills add https://github.com/obra/superpowers --skill brainstorming
Works with Paperclip

How Golang Grpc fits into a Paperclip company.

Golang Grpc drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md215 lines
Expand
---name: golang-grpcdescription: "Provides gRPC usage guidelines, protobuf organization, and production-ready patterns for Golang microservices. Use when implementing, reviewing, or debugging gRPC servers/clients, writing proto files, setting up interceptors, handling gRPC errors with status codes, configuring TLS/mTLS, testing with bufconn, or working with streaming RPCs."user-invocable: truelicense: MITcompatibility: Designed for Claude Code or similar AI coding agents, and for projects using Golang.metadata:  author: samber  version: "1.1.3"  openclaw:    emoji: "🌐"    homepage: https://github.com/samber/cc-skills-golang    requires:      bins:        - go        - protoc    install:      - kind: brew        formula: protobuf        bins: [protoc]allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(protoc:*) AskUserQuestion--- **Persona:** You are a Go distributed systems engineer. You design gRPC services for correctness and operability — proper status codes, deadlines, interceptors, and graceful shutdown matter as much as the happy path. **Modes:** - **Build mode** — implementing a new gRPC server or client from scratch.- **Review mode** — auditing existing gRPC code for correctness, security, and operability issues. # Go gRPC Best Practices Treat gRPC as a pure transport layer — keep it separate from business logic. The official Go implementation is `google.golang.org/grpc`. This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform. ## Quick Reference | Concern | Package / Tool || --- | --- || Service definition | `protoc` or `buf` with `.proto` files || Code generation | `protoc-gen-go`, `protoc-gen-go-grpc` || Error handling | `google.golang.org/grpc/status` with `codes` || Rich error details | `google.golang.org/genproto/googleapis/rpc/errdetails` || Interceptors | `grpc.ChainUnaryInterceptor`, `grpc.ChainStreamInterceptor` || Middleware ecosystem | `github.com/grpc-ecosystem/go-grpc-middleware` || Testing | `google.golang.org/grpc/test/bufconn` || TLS / mTLS | `google.golang.org/grpc/credentials` || Health checks | `google.golang.org/grpc/health` | ## Proto File Organization Organize by domain with versioned directories (`proto/user/v1/`). Always use `Request`/`Response` wrapper messages — bare types like `string` cannot have fields added later. Generate with `buf generate` or `protoc`. [Proto & code generation reference](references/protoc-reference.md) ## Server Implementation - Implement health check service (`grpc_health_v1`) — Kubernetes probes need it to determine readiness- Use interceptors for cross-cutting concerns (logging, auth, recovery) — keeps business logic clean- Use `GracefulStop()` with a timeout fallback to `Stop()` — drains in-flight RPCs while preventing hangs- Disable reflection in production — it exposes your full API surface ```gosrv := grpc.NewServer(    grpc.ChainUnaryInterceptor(loggingInterceptor, recoveryInterceptor),)pb.RegisterUserServiceServer(srv, svc)healthpb.RegisterHealthServer(srv, health.NewServer()) go srv.Serve(lis) // On shutdown signal:stopped := make(chan struct{})go func() { srv.GracefulStop(); close(stopped) }()select {case <-stopped:case <-time.After(15 * time.Second):    srv.Stop()}``` ### Interceptor Pattern ```gofunc loggingInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {    start := time.Now()    resp, err := handler(ctx, req)    log.Printf("method=%s duration=%s code=%s", info.FullMethod, time.Since(start), status.Code(err))    return resp, err}``` ## Client Implementation - Reuse connections — gRPC multiplexes RPCs on a single HTTP/2 connection; one-per-request wastes TCP/TLS handshakes- Set deadlines on every call (`context.WithTimeout`) — without one, a slow upstream hangs goroutines indefinitely- Use `round_robin` with headless Kubernetes services via `dns:///` scheme- Pass metadata (auth tokens, trace IDs) via `metadata.NewOutgoingContext` ```goconn, err := grpc.NewClient("dns:///user-service:50051",    grpc.WithTransportCredentials(creds),    grpc.WithDefaultServiceConfig(`{        "loadBalancingPolicy": "round_robin",        "methodConfig": [{            "name": [{"service": ""}],            "timeout": "5s",            "retryPolicy": {                "maxAttempts": 3,                "initialBackoff": "0.1s",                "maxBackoff": "1s",                "backoffMultiplier": 2,                "retryableStatusCodes": ["UNAVAILABLE"]            }        }]    }`),)client := pb.NewUserServiceClient(conn)``` ## Error Handling Always return gRPC errors using `status.Error` with a specific code — a raw `error` becomes `codes.Unknown`, telling the client nothing actionable. Clients use codes to decide retry vs fail-fast vs degrade. | Code                 | When to Use                                 || -------------------- | ------------------------------------------- || `InvalidArgument`    | Malformed input (missing field, bad format) || `NotFound`           | Entity does not exist                       || `AlreadyExists`      | Create failed, entity exists                || `PermissionDenied`   | Caller lacks permission                     || `Unauthenticated`    | Missing or invalid token                    || `FailedPrecondition` | System not in required state                || `ResourceExhausted`  | Rate limit or quota exceeded                || `Unavailable`        | Transient issue, safe to retry              || `Internal`           | Unexpected bug                              || `DeadlineExceeded`   | Timeout                                     | ```go// ✗ Bad — caller gets codes.Unknown, can't decide whether to retryreturn nil, fmt.Errorf("user not found") // ✓ Good — specific code lets clients act appropriatelyif errors.Is(err, ErrNotFound) {    return nil, status.Errorf(codes.NotFound, "user %q not found", req.UserId)}return nil, status.Errorf(codes.Internal, "lookup failed: %v", err)``` For field-level validation errors, attach `errdetails.BadRequest` via `status.WithDetails`. ## Streaming | Pattern | Use Case || --- | --- || Server streaming | Server sends a sequence (log tailing, result sets) || Client streaming | Client sends a sequence, server responds once (file upload, batch) || Bidirectional | Both send independently (chat, real-time sync) | Prefer streaming over large single messages — avoids per-message size limits and lowers memory pressure. ```gofunc (s *server) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error {    for _, u := range users {        if err := stream.Send(u); err != nil {            return err        }    }    return nil}``` ## Testing Use `bufconn` for in-memory connections that exercise the full gRPC stack (serialization, interceptors, metadata) without network overhead. Always test that error scenarios return the expected gRPC status codes. [Testing patterns and examples](references/testing.md) ## Security - TLS MUST be enabled in production — credentials travel in metadata- For service-to-service auth, use mTLS or delegate to a service mesh (Istio, Linkerd)- For user auth, implement `credentials.PerRPCCredentials` and validate tokens in an auth interceptor- Reflection SHOULD be disabled in production to prevent API discovery ## Performance | Setting | Purpose | Typical Value || --- | --- | --- || `keepalive.ServerParameters.Time` | Ping interval for idle connections | 30s || `keepalive.ServerParameters.Timeout` | Ping ack timeout | 10s || `grpc.MaxRecvMsgSize` | Override 4 MB default for large payloads | 16 MB || Connection pooling | Multiple conns for high-load streaming | 4 connections | Most services do not need connection pooling — profile before adding complexity. ## Common Mistakes | Mistake | Fix || --- | --- || Returning raw `error` | Becomes `codes.Unknown` — client can't decide whether to retry. Use `status.Errorf` with a specific code || No deadline on client calls | Slow upstream hangs indefinitely. Always `context.WithTimeout` || New connection per request | Wastes TCP/TLS handshakes. Create once, reuse — HTTP/2 multiplexes RPCs || Reflection enabled in production | Lets attackers enumerate every method. Enable only in dev/staging || `codes.Internal` for all errors | Wrong codes break client retry logic. `Unavailable` triggers retry; `InvalidArgument` does not || Bare types as RPC arguments | Can't add fields to `string`. Wrapper messages allow backwards-compatible evolution || Missing health check service | Kubernetes can't determine readiness, kills pods during deployments || Ignoring context cancellation | Long operations continue after caller gave up. Check `ctx.Err()` | ## Cross-References - → See `samber/cc-skills-golang@golang-context` skill for deadline and cancellation patterns- → See `samber/cc-skills-golang@golang-error-handling` skill for gRPC error to Go error mapping- → See `samber/cc-skills-golang@golang-observability` skill for gRPC interceptors (logging, tracing, metrics)- → See `samber/cc-skills-golang@golang-testing` skill for gRPC testing with bufconn