Change the contract
The proto repository holds everything the other repositories must agree on: the gRPC API, the JWT claims, the validation rules, and the semantic diff engine. This page shows how to change the contract and carry the change into every consumer without breaking existing clients.
What lives in proto
| Path | Defines | Used by |
|---|---|---|
proto/priompt/v1/prompt.proto | PromptService: nine RPCs and their messages | The server implements it. Every client calls it. |
gen/ | Go stubs, generated and committed | Server, promptctl |
claims/ | JWT claims: sub, org, rw, exp, iat, iss | priompt-auth signs them, the server verifies them. |
validate/ | The one definition of a valid prompt | Server (write and read), priompt put, promptctl |
semdiff/ | The semantic diff and the Embedder interface | Server, priompt put, promptctl |
The engines live with the schemas because a verdict only means something if every tool computes it the same way. The RPCs are listed in the gRPC API reference.
Prerequisites
Before you begin, make sure you have:
- The repositories side by side with a Go workspace: see Development setup.
- buf: from buf.build. It uses remote plugins, so
protocand its plugins aren't needed.
1. Change the .proto file
To change the contract:
-
Edit
proto/priompt/v1/prompt.proto. Add fields with new numbers. Never renumber, reuse, or change the type of an existing field. -
Regenerate the Go stubs, from the
protodirectory:buf generategen/priompt/v1/prompt.pb.goandprompt_grpc.pb.gochange. Without a.protochange, the output matches the committed files. -
Check that existing clients still work:
buf breaking --against '.git#branch=main'No output and exit code
0means nothing breaks.
buf lint passes. DiffPromptResponse is shared by DiffPrompt and DiffCommits on purpose, and both RPCs carry an explicit buf:lint:ignore comment that says why. CI runs buf lint and buf breaking on every pull request.
2. Update the Python SDK
buf generate in python-sdk writes the stubs to priompt/v1/, because the proto package is priompt.v1. The SDK ships them under priompt_sdk/v1/, so move them and fix one import.
To regenerate the Python stubs:
-
Generate, from the
python-sdkdirectory:buf generate -
Move the two generated files into the package, and remove the empty directory:
mv priompt/v1/prompt_pb2.py priompt/v1/prompt_pb2_grpc.py priompt_sdk/v1/rm -r priompt -
In
priompt_sdk/v1/prompt_pb2_grpc.py, changefrom priompt.v1 import prompt_pb2tofrom priompt_sdk.v1 import prompt_pb2. -
Run
pytest -q. Commit the regenerated stubs, because the published package ships them.
Don't edit the .priompt.v1.* service paths or the serialized descriptor in the stubs. They're the wire contract.
3. Update the Node SDK and the web UI
Both load the .proto at runtime from a vendored copy. To refresh it:
- In
js-sdk, runnpm run sync-proto. It copies../proto/proto/priompt/v1/prompt.prototoproto/priompt/v1/prompt.proto. - In
ui, runpnpm sync-proto. It does the same copy.
Never edit the vendored copies by hand.
4. Release the change
The Go module is github.com/priompt/proto, released with v* tags. The other modules pin a version in their go.mod.
To release a contract change:
- Merge and tag
proto. - In each Go consumer (
priompt,cli,auth), rungo get github.com/priompt/proto@<new-tag>andgo mod tidy. - Test each consumer with
GOWORK=off go test ./..., so it builds against the tag and not your workspace.
Changes to claims/, validate/, or semdiff/ only need this step. A Go consumer picks them up on its next dependency bump, and a compile error shows anything that no longer fits.
Next steps
- Storage engine: store a new field.
- Testing: the suites to run before you tag.