gwm-cli 1.6.0

git worktree manager — TUI + CLI, native libgit2, per-repo bootstrap
Documentation
---
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 — 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
— e.g. 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` — 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
  — 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
  — the single source of truth for `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
  — the SemVer release process and tagging workflow.