Internals

Contributing

PR lifecycle, review requirements, labels, and how a merge rides the release train to devnet, testnet, and mainnet.

View as Markdown

Lifecycle of a pull request

  1. Develop your change on a branch and open a pull request targeting main. Start it as a draft until it's ready for other developers to look at. Any change to pallet or runtime code must be accompanied by unit and/or integration tests covering its edge cases — see Testing for how to run every suite.
  2. CI validates the PR from several angles:
    • check-rust.yml — fmt, clippy, custom lints, zepter, cargo test
    • Clone Upgrade Check — sudo-upgrades a clone of live mainnet with your runtime, then runs the clone regression tests, the Python SDK suites, and the docs/website build. A runtime change that breaks the SDK or docs fails the PR.
    • try-runtime.yml — replays your migrations against live network state.
    • Spec Version Check — runtime-affecting PRs must bump spec_version above what mainnet is running, or carry the no-spec-version-bump label (see below).
  3. Mark the PR "Ready for Review" once the Rust CI is green and request review from the core (Nucleus) team. Reviews may request changes; three positive reviews are required.
  4. After approvals, you or an administrator merge to main — which starts the release train.

New to the codebase? Start with the repository layout.

Pull requests from forks

CI on a fork PR waits until a maintainer opens the PR's merge status panel and clicks Approve workflows to run. Approval is needed again for every new push. The runs use the PR's own workflow files, on self-hosted runners, with no repository secrets and a read-only token. Before approving, check every change under .github/: a modified workflow can choose its own runners or report a required check as passed without running it.

The release train

Merging to main triggers release-train.yml, a build-once promotion pipeline (full detail: Release process):

push to main
  └─ build wasm once (deterministic srtool build)
       └─ deploy devnet ── smoke-check devnet
            └─ deploy testnet ── smoke-check testnet ── publish SDK rc
                 └─ propose mainnet upgrade (environment gate + triumvirate multisig)

Key properties:

  • The runtime is built exactly once per train. Promotion between networks is a setCode extrinsic plus a smoke suite, never a rebuild — every network runs the identical wasm.
  • The ship lever is the spec_version bump. A merge without a bump builds and then no-ops at every deploy guard. This is why the Spec Version Check exists: without a bump (or the explicit opt-out label) your change would silently never ship.
  • Human gates live in GitHub environment settings, not in the workflow: devnet deploys automatically; testnet and mainnet promotion wait for whatever reviewers are configured on those environments.
  • Mainnet is never upgraded directly by CI. The train submits a multisig proposal (CI holds one key of a 2-of-2 deployment multisig with a SudoUncheckedSetCode proxy); the triumvirate approves 2-of-3 out-of-band. Once the upgrade executes on chain, watch-mainnet-release.yml cuts the GitHub release and moves the mainnet branch, which publishes the Docker images, with no further approval. The stable Python SDK and the production website/docs follow after a mainnet environment approval.

After your change deploys to testnet, it is your responsibility to verify it works there. If it doesn't, coordinate with a core team administrator and open a follow-up PR promptly.

PR labels

LabelEffect
red-teamMarks feature additions/changes (informational)
blue-teamMarks safety measures / dev-UX improvements (informational)
runtimeMarks substantive runtime or pallet changes (informational)
breaking-changeNotifies the relevant teams automatically — use for anything requiring synchronized changes elsewhere
no-spec-version-bumpSkips the spec-version gate for changes that deliberately ship without a runtime release
skip-clone-upgradeSkips the mainnet-clone upgrade check — reserve for changes that cannot affect the runtime, SDK, or docs
mainnet-cloneSpins up a live, publicly tunneled mainnet clone running your PR's runtime and posts the wss:// endpoint as a PR comment for interactive testing
apply-benchmark-patchApplies the benchmark bot's proposed weights.rs patch to the PR
skip-cargo-auditSkips the dependency audit

Documentation

All documentation lives in the repo-root docs/ folder — the single source of truth rendered to bittensor.com/docs by the website app (website/apps/bittensor-website).

  • User-facing concepts and guides: docs/concepts/, docs/guides/
  • Generated SDK reference (docs/tx/, docs/query/, docs/errors/): never hand-edit; regenerate with website/apps/bittensor-website/scripts/generate.py
  • Runtime internals and contributor docs: docs/internals/

The docs/website build runs as part of the Clone Upgrade Check, so a PR that breaks the docs build fails CI.