Skip to content

Refresh proto stubs after a contract change

Once soundverse-proto republishes its generated SDKs, nothing in a consumer repo changes until you pull the new stubs in. This page is about that pull — the last, easy-to-forget hop where a moved contract actually lands in core-database, a Python worker, or the SaaS frontend.

Every consumer ships an update-proto.sh (the frontend calls its update-protos.sh — note the plural) that pulls the freshly-published stubs for that language. There are three shapes:

Consumer language Repos What its update-proto.sh runs
Go manual only core-database, core-mcp go get github.com/soundversegit/soundverse-proto-go@staging then go mod tidy
Python automated via PR core-gateway-consumer, core-identity, core-storage, core-billing, all core-tool-*, template-core-tool, soundverse-py uv sync --upgrade-package soundverse-proto --refresh-package soundverse-proto (repos that also depend on the SDK add a second line for the soundverse package)
Web / TS soundverse-saas-2.0 npm install @soundversegit/soundverse-proto-web --force then a plain npm install + npx tsc --noEmit

The two Go data-plane services pin a frozen go.mod pseudo-version. There is no automation for them — bump by hand:

core-database/update-proto.sh · core-mcp/update-proto.sh
go get github.com/soundversegit/soundverse-proto-go@staging
go mod tidy

soundverse-proto-go is the private Go module CI publishes to the staging branch of soundversegit/soundverse-proto-go. To pin a specific contract commit for prod, go get …@<commit-sha> instead of @staging, then go mod tidy.

From the super-repo root, update-all-protos.sh walks every submodule and runs its refresh script:

core/update-all-protos.sh
./update-all-protos.sh # finds each repo's update-proto.sh / update-protos.sh and runs it in place

It finds update-proto.sh and update-protos.sh at -maxdepth 2, so both the Python/Go scripts and the frontend’s plural-named one get picked up.

  1. Confirm the contract is published. Your change must already be on main in soundverse-proto (staging release fans it out to the per-language repos’ staging branches). If you’re still iterating locally, don’t use this flow — point the dependency at a local path or feature branch and regenerate in place. See Run proto codegen locally.

  2. Run the repo’s refresh script from inside that repo:

    Terminal window
    cd core-tool-sansaarm && ./update-proto.sh
  3. Typecheck / build against the new contract. For Python, make check (ruff + pyright strict + pytest) is the exact CI gate; for Go, go build ./...; the frontend’s script already runs npx tsc --noEmit.

  4. Commit the lockfile. The diff is the pin only — uv.lock for Python, go.mod/go.sum for Go, package-lock.json for the frontend. No generated source is vendored (proto output lives in the published packages, and soundverse-proto’s own gen/ is gitignored).

The automated Python path Deployed

Section titled “The automated Python path ”

You rarely run the Python update-proto.sh by hand, because CI opens the bump for you. Each Python consumer carries .github/workflows/update-private-deps.yml, which runs uv lock --upgrade-package <dep> and opens (or updates in place) a single PR on the fixed branch automation/update-private-deps. It never auto-merges — a human merges once CI is green.

It fires on three triggers:

  • repository_dispatch — the instant path. soundverse-proto’s staging release dispatches proto_updated to the core* repos and soundverse-py; merging soundverse-py then dispatches soundverse_updated to the core-tool-* repos + template-core-tool. That’s a two-hop cascade (proto → SDK → workers), covered end-to-end in Drive the proto → deploy cascade.
  • a daily cron at 0 6 * * * — a safety net for any missed dispatch.
  • workflow_dispatch — fire it manually from the Actions tab.