--- title: Stability & compatibility description: What gwm's 1.0 SemVer promise covers, what it deliberately leaves free to change, the MSRV policy, and how deprecations are run. navigation: title: Stability --- # Stability & compatibility gwm follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) (`MAJOR.MINOR.PATCH`). This page is the explicit, published compatibility contract that backs the `1.0` line: it states which surfaces are covered by that promise (a breaking change there forces a **major** bump) and which are deliberately left free to change in a **minor** or **patch**. The rule of thumb: anything a *machine* parses is covered; anything a *human* reads on screen is not. ## Covered by SemVer (breaking change → major) These surfaces are part of the public contract. A backward-incompatible change (renaming or removing something, or changing its type or documented meaning) is a conscious **major** version decision. - **CLI surface**: the subcommands, their flags, and their documented argument shapes. Adding a subcommand or an optional flag is additive (minor); renaming or removing one is breaking. - **Exit codes**: the deterministic `0` / `1` / `2` contract documented per command (e.g. `gwm doctor`'s severity-derived code). Scripts and CI jobs key off these, so a code's meaning is frozen under this promise. - **`--format=json` output schemas**: the JSON payloads of `gwm list`, `gwm doctor`, `gwm path`, and `gwm status --json`, documented under [`docs/schema/`](https://github.com/kbrdn1/gwm-cli/tree/main/docs/schema) and pinned by `tests/contract_tests.rs`. - **Daemon JSON-RPC 2.0 protocol**: the `list` / `doctor` / `path` / `subscribe` methods, the `worktrees.changed` notification, and the standard JSON-RPC error codes. A daemon `list` result is byte-identical to `gwm list --format=json`, so the two share one `SCHEMA_VERSION`. - **`.gwm.toml` schema**: the top-level key set (`forge`, `worktree`, `bootstrap`, `hooks`, `doctor`, `tui`, `theme`, `git_tui`, `review`, `labels`, `milestones`, `branch_types`, `aliases`, `gitmoji`, `issue_template`, `pr_template`, `exec`, `clean`). A renamed or removed stable key is breaking; adding an optional one (as `forge` was in #419) is not. ### Frozen by test vs. covered by promise Three of these surfaces are *mechanically* frozen, and a rename fails CI before it can ship: the **JSON schemas**, the **daemon method/notification names**, and the **`.gwm.toml` section set**, all pinned by `tests/contract_tests.rs` against the single source of truth in [`src/contract.rs`](https://github.com/kbrdn1/gwm-cli/blob/main/src/contract.rs). The **CLI subcommands/flags** and the **exit-code meanings** are *not* freeze- tested end-to-end (only `doctor`'s `exit_code` field rides the JSON schema); they are covered by this written SemVer promise and reviewed per PR. Treat them as just as binding: the absence of a guard test is not a licence to break them silently. ### The machine-contract detail lives elsewhere The per-field tiers (which exact fields are **stable** vs **experimental**), the drift-detection mechanism (`SCHEMA_VERSION` on the daemon notification, `gwm --version` for one-shot CLI consumers), and the `additionalProperties` rules are documented in full in [`docs/schema/README.md`](https://github.com/kbrdn1/gwm-cli/blob/main/docs/schema/README.md). Notably, a few fields are **experimental** and may change without a major bump, among them the workspace-only `repo` field on a `list` row and the top-level `repo` on `status --json`. When in doubt about a specific field, that tiers table is authoritative. ## NOT covered by SemVer (may change in minor/patch) These are free to change without a major bump. Do not build automation on top of them. - **TUI layout & colours**: pane arrangement, widget placement, the theme / colour scheme, and any visual detail of the ratatui interface. Scripting against the rendered TUI is unsupported. - **Human-readable strings**: log lines, status-bar messages, help blurbs, the human (non-`--format=json`) output of any command. Parse the JSON surface instead; the prose is allowed to be reworded at any time. - **Internal Rust API**: the `gwm-cli` crate publishes a `[lib]` target (named `gwm`) alongside the binary, but **only as a byproduct**: the binary and the `tests/` integration suite share one module tree, and Rust integration tests can reach it only through a `pub` lib. That surface (~460 `pub` items across ~33 modules) is an internal test seam, **not** a public API: it is `#![doc(hidden)]` (nothing is advertised on docs.rs) and carries **no SemVer guarantee**. Do not `cargo add gwm-cli` to depend on `gwm::*`; those items may change in any release. (Decision recorded for [#342]: the library API is *disclaimed*, not gated with `cargo-semver-checks`, because owning ~460 items as a frozen contract would trip a major bump on every routine internal refactor, which is the wrong trade-off for a seam that exists to be tested, not consumed.) [#342]: https://github.com/kbrdn1/gwm-cli/issues/342 ## MSRV policy The Minimum Supported Rust Version is declared as `rust-version` in [`Cargo.toml`](https://github.com/kbrdn1/gwm-cli/blob/main/Cargo.toml) (currently **1.95**), the floor the crate is expected to compile against. Two CI jobs hold that floor. The clippy job runs on the *stable* toolchain with `-D warnings`, and `clippy::incompatible_msrv` is warn-by-default, so an accidental use of a **std API** newer than the declared floor fails CI. The `msrv` job installs the declared toolchain itself (read out of `Cargo.toml`, never hardcoded) and runs `cargo check --all-targets --locked`, which covers what clippy cannot: a newer **language / edition** feature, or a **dependency** whose own floor is higher than ours. `--locked` matters twice over. Cargo's `rust-version` gate is evaluated at *resolve* time against the committed lockfile, so a dependency that **declares** a higher floor fails before anything is built; and the compile that follows is the only thing that catches a dependency which declares **nothing at all**. That last case is not hypothetical, and it is why this section no longer recommends reading the floor out of `cargo metadata`. Until [#491](https://github.com/kbrdn1/gwm-cli/issues/491) the declared floor read `1.86` with nothing enforcing it. Metadata put the real floor at `1.88` (the ratatui 0.30 stack, `time 0.3.47`); compiling put it at `1.95`, because `libsqlite3-sys 0.38.1` (a normal dependency, via `rusqlite` with `bundled`) declares no `rust-version` and its build script uses `cfg_select!`, stable since 1.95.0. A crate that declares nothing is invisible to every metadata-based check, so the floor is whatever a build says it is. In practice an MSRV bump rides a **minor** release, not a major one. It has historically been driven by a dependency raising its own floor (the `1.86` bump came in with `tui-term` / `portable-pty` when the PTY overlay landed, the `1.95` bump with `rusqlite`'s bundled `libsqlite3-sys`), and is treated as a routine toolchain update rather than a breaking change to the public contract. Bumps are called out in the changelog so packagers are not surprised. ## Deprecation process When a covered surface has to change in a backward-incompatible way: 1. **Announce**: document the deprecation in the changelog under the release that introduces it, and (where the surface supports it) emit a runtime warning pointing at the replacement. 2. **Keep the old path working** through the rest of the current major line: a deprecation is a heads-up, not an immediate removal. 3. **Remove only on a major bump**, with the removal listed in that release's notes alongside the migration path. Additive changes (a new subcommand, an optional flag, a new optional JSON field, a new daemon method) are **not** deprecations: they ship in a minor release and require no warning, because existing consumers keep working unchanged (consumers MUST ignore unknown JSON fields). ## See also - [`docs/schema/README.md`](https://github.com/kbrdn1/gwm-cli/blob/main/docs/schema/README.md) for the per-field stable/experimental tiers and the drift-detection contract. - [`src/contract.rs`](https://github.com/kbrdn1/gwm-cli/blob/main/src/contract.rs) for the single source of truth on `SCHEMA_VERSION` and the frozen method/section sets. - [Contributing → Releases](/development/contributing) and [`CONTRIBUTING.md`](https://github.com/kbrdn1/gwm-cli/blob/main/CONTRIBUTING.md) for the SemVer release process and tagging workflow.