This document specifies the locked Protocol Buffer tools used by Studio's Python code generation and Rust build-time generation.
Note: The Python generator uses the compiler bundled with
grpcio-tools; it does not use the systemprotocbinary. Rust'stonic-prost-builduses the system binary at build time.
| Tool | Version | Purpose |
|---|---|---|
| System protoc | v30.2 | Rust ingestion build-time compiler |
| grpcio-tools | 1.76.0 (bundled libprotoc 31.1) | Python protobuf/gRPC code generator |
Python proto files are:
- Generated manually via
./scripts/generate_proto.sh - Committed to git (
backend/app/proto_gen/*.py) - Must be regenerated when
.protofiles change
Why version locking matters: Different protoc versions generate structurally different code. Locking ensures identical code across all environments.
Rust proto files are:
- Generated automatically at compile time via
build.rs - Placed in
target/directory (gitignored) - Regenerated fresh on every
cargo build
The system compiler is locked to v30.2 so local and CI Rust builds use the same input compiler even though Rust output is not committed.
// ingestion/build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_prost_build::configure()
.compile_protos(
&["../proto/ingestion.proto", "../proto/auth.proto"],
&["../proto"],
)?;
Ok(())
}System compiler used by Rust:
$ protoc --version
libprotoc 30.2Compiler bundled with the locked Python generator:
$ cd backend
$ uv run python -m grpc_tools.protoc --version
libprotoc 31.1Generated Python files (header comment):
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: auth.proto
# Protobuf Python Version: 6.31.1 ← Runtime library version (NOT compiler!)✅ Python files showing Protobuf Python Version: 6.31.1 is CORRECT - this is the protobuf Python runtime library version (from protobuf package), NOT the protoc compiler version
✅ Python runtime version can differ from protoc version - grpcio-tools 1.76.0 bundles libprotoc 31.1 and generates code for protobuf 6.31.1. This is normal.
❌ If system protoc --version is not 30.2, Rust validation is not using
the locked compiler.
❌ If uv run python -m grpc_tools.protoc --version is not 31.1, the
backend environment does not match the locked Python generator.
Install system protoc v30.2 for Rust builds:
PROTOC_VERSION=30.2
curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-osx-x86_64.zip
sudo unzip -o protoc-${PROTOC_VERSION}-osx-x86_64.zip -d /usr/local bin/protoc
sudo unzip -o protoc-${PROTOC_VERSION}-osx-x86_64.zip -d /usr/local 'include/*'
rm protoc-${PROTOC_VERSION}-osx-x86_64.zipInstall Python tools (via uv):
cd backend
uv sync # Installs grpcio-tools==1.76.0 from uv.lockInstall system protoc v30.2 for Rust builds:
PROTOC_VERSION=30.2
curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip
sudo unzip -o protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local bin/protoc
sudo unzip -o protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /usr/local 'include/*'
rm protoc-${PROTOC_VERSION}-linux-x86_64.zipInstall Python tools (via uv):
cd backend
uv sync # Installs grpcio-tools==1.76.0 from uv.lockInstall system protoc v30.2 for Rust builds:
$PROTOC_VERSION = "30.2"
Invoke-WebRequest -Uri "https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOC_VERSION/protoc-$PROTOC_VERSION-win64.zip" -OutFile "protoc.zip"
Expand-Archive -Path protoc.zip -DestinationPath "C:\protoc" -Force
# Add C:\protoc\bin to your PATH
Remove-Item protoc.zipInstall Python tools (via uv):
cd backend
uv sync # Installs grpcio-tools==1.76.0 from uv.lockAfter installation, verify versions:
protoc --version
# Expected: libprotoc 30.2
# For Python (from backend directory with uv environment active)
uv run python -m grpc_tools.protoc --version
# Expected: libprotoc 31.1 (bundled with grpcio-tools 1.76.0)cd backend
./scripts/generate_proto.shNo manual regeneration needed. Proto files are generated automatically during:
cargo build
cargo check
cargo runThe pre-commit hook automatically regenerates Python proto files before each commit:
- Regenerates
backend/app/proto_gen/*.pyfiles - Checks tracked and untracked generated output
- Stages updated files automatically
- Prevents commits with stale Python proto code
The root .github/workflows/studio-proto-staleness-check.yml workflow:
- Regenerates Python proto files from scratch
- Inspects scoped Git porcelain status, including untracked generated files
- Fails the build if any differences are detected
The same workflow runs cargo check in the ingestion directory to verify:
- Proto files compile successfully
build.rscorrectly references sharedproto/directory
Every CI job that compiles Studio's Rust ingestion target installs system
protoc 30.2. The backend and ingestion test jobs download the release archive,
verify its pinned SHA-256 checksum, and require the exact libprotoc 30.2
version before compiling.
- Ensure protoc is in your PATH
- Verify installation with
which protoc
- Ensure
backend/uv.lockis current andgrpcio-tools==1.76.0is installed - Verify the bundled generator reports
libprotoc 31.1 - Regenerate:
cd backend && ./scripts/generate_proto.sh
- Your locked Python environment or
grpcio-toolsversion differs from CI - Run
uv sync --lockedfrombackend - Regenerate proto files locally
- Commit the updated files
- Ensure
proto/exists at the Studio root (apps/studio) - Check
ingestion/build.rsreferences correct paths - Run
cargo clean && cargo buildto regenerate
When updating protoc version:
- Update version numbers in this file
- Update
../../.github/workflows/studio-proto-staleness-check.ymland../../.github/workflows/studio-backend-tests.yml - Regenerate Python proto files locally
- Test that Rust
cargo buildstill works - Commit all updated files in a single commit
- Notify developers to update their local installations