use-protobuf
Design, change, and review Protobuf schemas used as gRPC contracts, streaming protocols, typed data models, grpc-gateway REST APIs, OpenAPI specifications, or generated SDK inputs. Use for .proto files, RPC request/response design, oneof stream events, validation annotations, API
Install
npx skills add https://github.com/moeru-ai/auv/tree/main/.agents/skills/use-protobuf
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install moeru-ai-auv@llmmart
git clone https://github.com/moeru-ai/auv.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole moeru-ai/auv collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Use Protobuf
Treat Protobuf as the canonical typed contract for gRPC, REST gateway bindings, OpenAPI, generated SDKs, and shared data structures. Model the domain before optimizing generated code.
Workflow
- Read repository instructions and inspect existing
.protofiles, packages, versions, imports, generation configuration, and generated output conventions. - Classify each service as gRPC-only or HTTP-exposed before adding annotations.
- Model every RPC, stream packet, enum, error, and reusable message with concrete types.
- Apply transport-specific validation and documentation rules.
- Evaluate compatibility according to the package's release state and version.
- Generate every configured SDK and OpenAPI artifact. Use
$use-bufand$use-buf-pluginswhen available. - Run repository tests and inspect generated diffs; never hand-edit generated code.
Define RPC Contracts Explicitly
- Define a dedicated RPC method for every gRPC operation.
- Name unary messages
MethodRequestandMethodResponse. - Keep request and response messages distinct even when their current fields happen to match.
- Use TitleCase service, method, message, and enum names; use
lower_snake_casefields andUPPER_SNAKE_CASEenum values. - Prefer comments that explain semantics, units, identity, presence, ordering, and lifecycle rather than restating the field name.
rpc GetDocument(GetDocumentRequest) returns (GetDocumentResponse);
Model Streaming Without Base Payloads
Use the appropriate gRPC streaming form:
rpc ImportRecords(stream ImportRecordsStreamRequest) returns (ImportRecordsResponse);
rpc WatchJob(WatchJobRequest) returns (stream WatchJobStreamResponse);
rpc Transfer(stream TransferStreamRequest) returns (stream TransferStreamResponse);
MUST NOT create an abstract, generic, inherited, or catch-all base event/base payload for stream requests or responses. Define concrete stream event, step, or packet messages. When several variants may occur, use oneof whose alternatives are separate messages. Use one homogeneous stream message only when every packet genuinely has the same body and semantics, such as fixed-shape file chunks.
Read references/schema-design.md before designing or changing any streaming RPC.
Separate gRPC-Only and HTTP-Exposed Schemas
For gRPC-only services, do not add google.api.http, grpc-gateway, or grpc.gateway.protoc_gen_openapiv2 imports, method options, message options, enum options, or field options.
For every *Request exposed through grpc-gateway, regardless of GET, POST, body, path, or query placement:
- validate accepted input with
buf.validateannotations; - document every request field with appropriate
openapiv2information such as example, description, format, range, length, pattern, or collection bounds; - keep runtime validation authoritative and make OpenAPI constraints agree with it;
- define the
google.api.httpbinding and operation documentation intentionally.
Do not hardcode a Buf cache path when researching extension fields. Follow the export/query workflow in references/http-and-openapi.md.
Prefer Strong Domain Types
- Use an enum whenever the value belongs to a finite controlled vocabulary; do not disguise it as an unconstrained string.
- Give enums an explicit zero value and document what the enum classifies.
- Prefer dedicated messages, well-known types, repeated fields, maps, and
oneofovergoogle.protobuf.Structorgoogle.protobuf.Any. - Use
StructorAnyonly for a real open-world boundary. Document why typed modeling is impossible and how consumers validate the payload. - In Go, use
protojsonfor Protobuf JSON and a registered type resolver forAny; do not route Protobuf through genericencoding/json. Research the canonical library for every other target language before implementing serialization.
Organize and Version Schemas
- Set
go_packageon first-party schemas that generate Go. - Keep language-neutral source paths and verify Python output with
protoc-gen-pythonplusprotoc-gen-pyi. Do not assume a kebab-case Protobuf source/import path automatically makes Python output invalid, and do not rename the source tree merely out of fear that it might violate Python module conventions; generate and verify the selected plugins' actual module/import behavior. - Put API versions in both package and directory identity, using forms such as
v1,v2,v1alpha1, orv1beta1. - Before release, while a feature is explicitly experimental or feature-flagged, allow deliberate breaking redesigns and field renumbering only when every producer, consumer, stored payload, and generated artifact can be rebuilt together.
- After release, never renumber or reuse field numbers. Reserve removed field numbers and names, and introduce a new version for incompatible redesigns.
- Keep generated Go packages, Python modules, TypeScript modules, and other SDK paths aligned with the source schema path. Preserve each language plugin's conventional leaf layout.
- Change output directories or flattening only when the user explicitly requests it or the repository already declares that convention in generation configuration.
Generate Complete SDK Surfaces
- Generate runtime code and the language's customary typing artifacts.
- For Python, generate
.pyplus.pyiwhen supported. - For TypeScript, generate
.tsor the ecosystem-appropriate.d.ts/.d.mtsartifacts. - Prefer the established generator for each language and OpenAPI ecosystem. Do not write a parallel custom generator or manually maintain generated output.
Read references/schema-design.md for complete modeling and evolution rules, references/http-and-openapi.md for gateway schemas, and references/api-design-sources.md when designing public resources, errors, pagination, or long-running operations.
Files (auv)
-
agents
-
openai.yaml 196 B
interface: display_name: "Use Protobuf" short_description: "Design robust gRPC and HTTP Protobuf schemas" default_prompt: "Use $use-protobuf to design or review this Protobuf API contract."
-
-
references
-
api-design-sources.md 2 KB
# API and Protobuf Design Sources Use these as selected references, not as mutually mandatory specifications. Preserve the repository's established API style unless the user requests a migration. - [Protocol Buffers style guide](https://protobuf.dev/programming-guides/style/): file layout, identifier casing, enum zero values, services, and naming hazards. - [Proto3 language guide](https://protobuf.dev/programming-guides/proto3/): field numbers, presence, `oneof`, imports, `Any`, JSON mapping, and compatible evolution. - [gRPC core concepts](https://grpc.io/docs/what-is-grpc/core-concepts/): unary, client-streaming, server-streaming, bidirectional-streaming, cancellation, deadlines, and metadata. - [JSON:API error objects](https://jsonapi.org/format/#errors): structured HTTP error identity, status, code, title, detail, source, links, and metadata. - [Microsoft REST API Guidelines](https://github.com/microsoft/api-guidelines): public REST consistency, resources, methods, errors, versioning, pagination, and long-running operations. - [Kratos Protobuf guideline](https://go-kratos.dev/docs/guide/api-protobuf/): API directory/version organization, HTTP annotations, and generated service conventions. - [Boston Dynamics API Protobuf guidelines](https://dev.bostondynamics.com/docs/protos/style_guide.html): production schema conventions, services, errors, timestamps, units, and compatibility. - [VictoriaMetrics Practical Protobuf](https://victoriametrics.com/blog/go-protobuf-basic/): practical Go/Protobuf encoding and generated-code considerations; cross-check advice against official Protobuf compatibility rules. - [Go generated code guide](https://protobuf.dev/reference/go/go-generated/): `go_package`, generated package mapping, and Go API generation. - [Python generated code guide](https://protobuf.dev/reference/python/python-generated/): Python module generation and runtime behavior. When sources disagree, prioritize wire compatibility, explicit repository policy, official Protobuf/gRPC behavior, and the user's stated API lifecycle. -
http-and-openapi.md 3.7 KB
# grpc-gateway, Validation, and OpenAPI ## Classify the Transport For gRPC-only services, omit all of the following: - `google/api/annotations.proto` and `google.api.http`; - `protoc-gen-openapiv2/options/annotations.proto`; - grpc-gateway/OpenAPI service, operation, message, enum, and field options. Keep ordinary Protobuf comments and runtime validation when required by the gRPC service itself, but do not make a gRPC-only contract depend on an HTTP documentation toolchain. For an HTTP-exposed RPC, define the binding and document the operation: ```proto rpc CreateWidget(CreateWidgetRequest) returns (CreateWidgetResponse) { option (google.api.http) = { post: "/v1/widgets" body: "*" }; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { operation_id: "widgets_create" summary: "Create a widget." tags: "Widgets" }; } ``` ## Validate Every HTTP Request Apply Protovalidate to every accepted request field regardless of whether it comes from a path, query string, GET request, POST body, or other HTTP method. Validate strings, numbers, enums, collections, nested messages, cross-field constraints, and identifiers according to domain semantics. ```proto message ListWidgetsRequest { string parent = 1 [ (buf.validate.field).string = { min_len: 1 max_len: 200 }, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "Parent collection identifier." example: "\"accounts/42\"" } ]; int32 page_size = 2 [ (buf.validate.field).int32 = { gte: 0 lte: 100 }, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "Maximum number of widgets to return." example: "50" minimum: 0 maximum: 100 } ]; } ``` Treat validation as the executable acceptance rule. Mirror relevant range, pattern, length, format, example, description, and collection information into OpenAPI so generated clients and documentation do not contradict runtime behavior. ## Inspect Extension Definitions Without Cache Paths Do not hardcode `~/.cache`, platform-specific cache roots, module digests, or commit directories. Inspect the dependency declared in `buf.yaml` and pinned in `buf.lock`, then use Buf: ```sh buf dep graph --format json inspection_dir="$(mktemp -d)" buf export buf.build/grpc-ecosystem/grpc-gateway:<pinned-ref> \ --path protoc-gen-openapiv2/options/annotations.proto \ --path protoc-gen-openapiv2/options/openapiv2.proto \ --output "$inspection_dir" rg -n "message JSONSchema|openapiv2_field|example|description" "$inspection_dir" ``` Resolve `<pinned-ref>` from repository configuration/lock state. Remove the temporary directory after inspection. Consult `$use-buf` for dependency resolution and `$use-buf-plugins` for generator behavior. The grpc-gateway OpenAPI documentation explains comment propagation, operation/schema/field options, visibility, merge behavior, enum rendering, and output configuration: - https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/customizing_openapi_output/ ## Public HTTP API Shape Use a consistent resource and error model. When the application adopts JSON:API errors, model typed equivalents of useful members such as status, code, title, detail, source pointer/parameter/header, links, and meta rather than returning an unstructured object. Do not combine mutually incompatible envelope conventions without an explicit API-wide decision. Use the Microsoft API Guidelines and JSON:API as design references for resource naming, HTTP semantics, pagination, idempotency, errors, and long-running operations. Adapt them to the existing API contract rather than importing conventions piecemeal. -
schema-design.md 5.5 KB
# Protobuf Schema Design ## Contents - RPC and message boundaries - Streaming protocols - Strong typing and presence - Reuse without abstraction leakage - Evolution and versioning - Source and generated layout ## RPC and Message Boundaries Give each operation its own request and response, named after the method: ```proto service CatalogService { rpc CreateItem(CreateItemRequest) returns (CreateItemResponse); rpc GetItem(GetItemRequest) returns (GetItemResponse); } ``` Do not use a generic `Request`, `Response`, `Payload`, or `Envelope` across unrelated methods. Dedicated messages allow validation, documentation, authorization, and evolution to diverge safely. Model method inputs in the request even when the transport could carry them elsewhere. Model method results in the response instead of returning a domain entity directly; the response leaves room for metadata and future compatible fields. ## Streaming Protocols Choose the cardinality from behavior: - client streaming: large or incremental input such as JSON records, file chunks, or query batches; - server streaming: progress, events, task steps, query results, or binary output; - bidirectional streaming: interactive/duplex protocols where both sides advance independently. MUST NOT define abstract or generic base stream events or payloads. For heterogeneous streams, use separate messages under `oneof`: ```proto message WatchImportStreamResponse { oneof event { ImportStarted started = 1; ImportProgress progress = 2; ImportWarning warning = 3; ImportCompleted completed = 4; } } message ImportStarted { string import_id = 1; } message ImportProgress { int64 records_processed = 1; optional int64 records_total = 2; } ``` Use the same structure for heterogeneous client streams. For example, define separate header, JSON record, file chunk, commit, and abort messages rather than a base packet with many nullable fields. Use one homogeneous stream message only when every packet has exactly the same semantics. A fixed-shape file chunk can be: ```proto message DownloadFileStreamResponse { bytes data = 1; } ``` If the stream also carries headers, checksums, progress, or trailers, return to `oneof` with concrete variants. Document ordering, which event may appear first/last, repetition, completion, cancellation, resumability, offsets, checksums, and whether an error arrives as gRPC status or an in-band event. ## Strong Typing and Presence - Use enums for finite controlled vocabularies. Prefix top-level enum values with the enum name and give the zero value `_UNSPECIFIED` or `_UNKNOWN` semantics. - Use `optional` when presence differs from the scalar default. Do not add presence when unset and default are semantically identical. - Use `google.protobuf.Timestamp`, `Duration`, `FieldMask`, or other appropriate well-known types instead of strings with implicit formats. - Include units in names or comments for numeric quantities, such as `timeout_seconds` or `size_bytes`. - Use `bytes` for opaque binary content, not base64 text fields. - Use maps only for truly dynamic keyed collections. Prefer repeated typed entries when keys or values need validation, ordering, metadata, or future evolution. - Avoid `Struct` and `Any`. If an upstream opaque payload must be preserved, isolate it at that boundary, document its schema/version and validation, and provide typed projections for first-class fields. For Go JSON conversion, use `google.golang.org/protobuf/encoding/protojson`. For `Any`, configure a resolver/type registry. Research and use the canonical Protobuf JSON/runtime API in every other language. ## Reuse Without Abstraction Leakage Reuse a message when two fields mean the same contract and must evolve together. Import the canonical message instead of duplicating its fields and writing conversion code. Keep package dependency direction intentional and acyclic. Do not reuse merely because two messages currently have the same shape. Separate them when their ownership, validation, authorization, lifecycle, or future evolution differs. Never introduce a generic base request/response/event solely to reduce line count. ## Evolution and Versioning Before a feature is released, while explicitly experimental or feature-flagged, a coordinated breaking redesign may change structure or field numbers. Rebuild all generated SDKs, services, clients, fixtures, queues, and stored payloads together, and still run breaking-change detection so the break is visible. After release: - never change or reuse a field number; - reserve deleted numbers and names; - add fields compatibly whenever possible; - avoid moving fields into or out of an existing `oneof` without studying wire behavior; - introduce `v2` for incompatible changes; - use `v1alpha1`/`v1beta1` to signal unstable contracts when appropriate. Put the version in both directory and package identity, for example `example/catalog/v1` and `example.catalog.v1`. Keep imports explicit and avoid confusing relative resolution across packages. ## Source and Generated Layout - Name source files `lower_snake_case.proto`. - Sort imports and set language file options such as `go_package` where required by the project's generation model. - Keep source directories language-neutral. - Preserve the schema's path in generated Go, Python, TypeScript, and other targets unless the language plugin's established convention adds a conventional leaf directory. - Verify Python with runtime and typing plugins instead of reorganizing the schema tree preemptively. - Never edit generated files by hand.
-
-
SKILL.md 6.3 KB
--- name: use-protobuf description: Design, change, and review Protobuf schemas used as gRPC contracts, streaming protocols, typed data models, grpc-gateway REST APIs, OpenAPI specifications, or generated SDK inputs. Use for .proto files, RPC request/response design, oneof stream events, validation annotations, API versioning, schema evolution, generated package layout, and avoiding weak Struct or Any payloads. --- # Use Protobuf Treat Protobuf as the canonical typed contract for gRPC, REST gateway bindings, OpenAPI, generated SDKs, and shared data structures. Model the domain before optimizing generated code. ## Workflow 1. Read repository instructions and inspect existing `.proto` files, packages, versions, imports, generation configuration, and generated output conventions. 2. Classify each service as gRPC-only or HTTP-exposed before adding annotations. 3. Model every RPC, stream packet, enum, error, and reusable message with concrete types. 4. Apply transport-specific validation and documentation rules. 5. Evaluate compatibility according to the package's release state and version. 6. Generate every configured SDK and OpenAPI artifact. Use `$use-buf` and `$use-buf-plugins` when available. 7. Run repository tests and inspect generated diffs; never hand-edit generated code. ## Define RPC Contracts Explicitly - Define a dedicated RPC method for every gRPC operation. - Name unary messages `MethodRequest` and `MethodResponse`. - Keep request and response messages distinct even when their current fields happen to match. - Use TitleCase service, method, message, and enum names; use `lower_snake_case` fields and `UPPER_SNAKE_CASE` enum values. - Prefer comments that explain semantics, units, identity, presence, ordering, and lifecycle rather than restating the field name. ```proto rpc GetDocument(GetDocumentRequest) returns (GetDocumentResponse); ``` ## Model Streaming Without Base Payloads Use the appropriate gRPC streaming form: ```proto rpc ImportRecords(stream ImportRecordsStreamRequest) returns (ImportRecordsResponse); rpc WatchJob(WatchJobRequest) returns (stream WatchJobStreamResponse); rpc Transfer(stream TransferStreamRequest) returns (stream TransferStreamResponse); ``` MUST NOT create an abstract, generic, inherited, or catch-all base event/base payload for stream requests or responses. Define concrete stream event, step, or packet messages. When several variants may occur, use `oneof` whose alternatives are separate messages. Use one homogeneous stream message only when every packet genuinely has the same body and semantics, such as fixed-shape file chunks. Read [references/schema-design.md](references/schema-design.md) before designing or changing any streaming RPC. ## Separate gRPC-Only and HTTP-Exposed Schemas For gRPC-only services, do not add `google.api.http`, grpc-gateway, or `grpc.gateway.protoc_gen_openapiv2` imports, method options, message options, enum options, or field options. For every `*Request` exposed through grpc-gateway, regardless of GET, POST, body, path, or query placement: - validate accepted input with `buf.validate` annotations; - document every request field with appropriate `openapiv2` information such as example, description, format, range, length, pattern, or collection bounds; - keep runtime validation authoritative and make OpenAPI constraints agree with it; - define the `google.api.http` binding and operation documentation intentionally. Do not hardcode a Buf cache path when researching extension fields. Follow the export/query workflow in [references/http-and-openapi.md](references/http-and-openapi.md). ## Prefer Strong Domain Types - Use an enum whenever the value belongs to a finite controlled vocabulary; do not disguise it as an unconstrained string. - Give enums an explicit zero value and document what the enum classifies. - Prefer dedicated messages, well-known types, repeated fields, maps, and `oneof` over `google.protobuf.Struct` or `google.protobuf.Any`. - Use `Struct` or `Any` only for a real open-world boundary. Document why typed modeling is impossible and how consumers validate the payload. - In Go, use `protojson` for Protobuf JSON and a registered type resolver for `Any`; do not route Protobuf through generic `encoding/json`. Research the canonical library for every other target language before implementing serialization. ## Organize and Version Schemas - Set `go_package` on first-party schemas that generate Go. - Keep language-neutral source paths and verify Python output with `protoc-gen-python` plus `protoc-gen-pyi`. Do not assume a kebab-case Protobuf source/import path automatically makes Python output invalid, and do not rename the source tree merely out of fear that it might violate Python module conventions; generate and verify the selected plugins' actual module/import behavior. - Put API versions in both package and directory identity, using forms such as `v1`, `v2`, `v1alpha1`, or `v1beta1`. - Before release, while a feature is explicitly experimental or feature-flagged, allow deliberate breaking redesigns and field renumbering only when every producer, consumer, stored payload, and generated artifact can be rebuilt together. - After release, never renumber or reuse field numbers. Reserve removed field numbers and names, and introduce a new version for incompatible redesigns. - Keep generated Go packages, Python modules, TypeScript modules, and other SDK paths aligned with the source schema path. Preserve each language plugin's conventional leaf layout. - Change output directories or flattening only when the user explicitly requests it or the repository already declares that convention in generation configuration. ## Generate Complete SDK Surfaces - Generate runtime code and the language's customary typing artifacts. - For Python, generate `.py` plus `.pyi` when supported. - For TypeScript, generate `.ts` or the ecosystem-appropriate `.d.ts`/`.d.mts` artifacts. - Prefer the established generator for each language and OpenAPI ecosystem. Do not write a parallel custom generator or manually maintain generated output. Read [references/schema-design.md](references/schema-design.md) for complete modeling and evolution rules, [references/http-and-openapi.md](references/http-and-openapi.md) for gateway schemas, and [references/api-design-sources.md](references/api-design-sources.md) when designing public resources, errors, pagination, or long-running operations.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.