Skip to content

Latest commit

 

History

History
106 lines (75 loc) · 5.01 KB

msrv-policy.md

File metadata and controls

106 lines (75 loc) · 5.01 KB

Minimum Supported Rust Version (MSRV) Policy

Overview

The brush project maintains a conservative MSRV policy to balance two key concerns:

  1. Binary distribution: Users building brush from source should not need a bleeding-edge compiler
  2. Library usage: Downstream projects depending on brush crates should not face aggressive MSRV increases

These concerns pull against each other, and they do not apply evenly across the workspace. The crates that other projects embed are held to a stricter standard than the ones that exist to produce the shell itself. The workspace is therefore split into two tiers.

Tiers

Library tier

brush-core, brush-parser, brush-builtins, brush-coreutils-builtins, and brush-experimental-builtins are the reusable pieces. Other projects embed them to get a shell runtime, a bash-compatible parser, or a set of builtins without taking on brush's interactive front end. Their dependency sets are deliberately narrow for the same reason.

These crates inherit rust-version from [workspace.package] in the root Cargo.toml. That value is the project's MSRV, and it is the one the rules below are mostly about.

xtask and brush-test-harness inherit the same value. Neither is published, but cargo xtask is how CI runs the MSRV check, so xtask has to compile with the MSRV toolchain. That is why xtask must not depend on brush-shell: the tool that drives the build cannot sit downstream of the thing it builds.

Application tier

brush, brush-shell, brush-interactive, and brush-fuzz exist to produce, host, and exercise the shell. brush-shell and brush-interactive are published as libraries, but their reason to exist is the interactive front end, and they carry its dependencies: line editing, terminal handling, completion. Those dependencies raise their own MSRVs on a schedule the project does not control, and refusing to follow would mean freezing the interactive experience on whatever line editor was current at the time.

These crates declare rust-version in their own manifests, above the workspace value. Those manifests are the only record of it; no other file in the tree repeats the number.

Policy

Updating the library tier

We do not update the workspace MSRV proactively. Updates only occur when:

  • A meaningful set of language features or capabilities becomes available that provides clear value to the project
  • The return-on-investment justifies the potential impact on users and downstream dependencies

When we do update, we move to a Rust version that is at least 4-6 months old at the time of the update. This ensures:

  • Sufficient time for the Rust version to stabilize
  • Wide availability in package managers and development environments
  • Reduced friction for users building from source

Updating the application tier

An application-tier crate raises its rust-version only when a dependency it needs actually requires it, and only as far as that dependency requires. We do not round up to current stable, and we do not move a crate ahead of the workspace speculatively. The commit that raises the value should be the commit that takes the dependency, so the reason is visible in one place rather than inferred later.

The 4-6 month age requirement does not apply to this tier; the forcing dependency's own MSRV decides the number. In exchange, a raise is confined to the crates that need it. If only brush-interactive requires a newer toolchain, brush-shell and brush follow because they depend on it, and the library tier does not move at all.

Communication

MSRV changes are always:

  • Explicitly documented in release notes
  • Considered a notable change requiring user awareness
  • Announced with clear justification for the update

A library-tier change is the more significant of the two, because it reaches every downstream consumer. An application-tier change affects people building the shell from source, and should say which dependency forced it.

Enforcement

CI runs the source-code checks against both the toolchain pinned in rust-toolchain.toml (which Dependabot keeps at the latest stable release) and the workspace MSRV. On the MSRV leg, the build check runs as:

cargo xtask check build --workspace-msrv

Cargo refuses to build any package whose rust-version exceeds the active toolchain, so the application-tier crates cannot be part of that leg. The flag asks cargo metadata which workspace members declare a rust-version above the lowest one in the workspace and excludes exactly those. No list of crate names exists anywhere in the tooling, so moving a crate between tiers needs no change to it. Without the flag, every crate is checked, which is what the pinned-toolchain leg wants.

Rationale

This split recognizes that brush serves two different audiences. A project embedding brush-core wants a stable, predictable compiler requirement and gets one. A person building the shell wants a current line editor and working terminal integration, and that has a cost the embedding audience should not have to pay.