# Stability, versioning & the path to 1.0
How far each crate has settled, what a version number promises, the MSRV
contract, and the gate this workspace holds itself to before tagging a `1.0`.
## Versioning
Every crate is **versioned and published independently** and adheres to
[SemVer](https://semver.org/spec/v2.0.0.html); each has its own `CHANGELOG.md`
([Keep a Changelog](https://keepachangelog.com/en/1.1.0/)) and is tagged
`<crate>-v<version>`. There is no workspace-wide version.
While a crate is **pre-1.0 (`0.x`)**, a SemVer **minor** bump (`0.x → 0.(x+1)`)
may carry breaking changes and a **patch** (`0.x.y → 0.x.(y+1)`) is
non-breaking — the standard Cargo `^0.x` interpretation. Breaking changes are
allowed at `0.x` and called out in the changelog's `### Changed`/`### Removed`.
After a crate reaches **`1.0`**, it switches to strict SemVer: breaking changes
require a **major** bump.
Because the crates depend on each other (`vcs-core` → `vcs-git`/`vcs-jj`; the
wrappers → the foundational `vcs-diff`/`vcs-cli-support`), each intra-workspace
dependency carries a `^MAJOR.MINOR` requirement that must stay in range when a
dependency crosses a boundary — see the release process in
[AGENTS.md](https://github.com/ZelAnton/vcs-toolkit-rs/blob/main/AGENTS.md) and the publish ordering in `release.yml`.
## Stability tiers
All crates are **pre-1.0** today — the API may still change. Relative maturity:
| `vcs-diff` | 0.1 | settling |
| `vcs-cli-support` | 0.1 | settling |
| `vcs-testkit` | 0.1 | stable-ish (dev-only) |
| `vcs-git` | 0.4 | maturing |
| `vcs-jj` | 0.4 | maturing |
| `vcs-github` | 0.4 | maturing |
| `vcs-core` | 0.2 | evolving |
| `vcs-gitlab` | 0.1 | new |
| `vcs-gitea` | 0.1 | new |
| `vcs-forge` | 0.1 | new |
| `vcs-watch` | 0.1 | new |
| `vcs-mcp` | 0.1 | new |
**What the tiers mean — and the per-crate caveats:**
- **settling** — close to its 1.0 shape; small and pure. `vcs-diff` (diff model +
parser, `Version`) and `vcs-cli-support` (the argv guard, fetch policy, error
classifiers) are narrow surfaces unlikely to change much.
- **stable-ish (dev-only)** — `vcs-testkit` is a dev-dependency only, so its churn
never reaches a release build.
- **maturing** — broad, consumer-validated surfaces that still grow *additively*:
`vcs-git`, `vcs-jj` (tracks jj, whose CLI/template surface churns — see the CI
version matrix), and `vcs-github` (the `gh` PR/issue/run/release surface).
- **evolving** — `vcs-core`'s common facade surface grows as cross-backend needs
surface (e.g. `snapshot`); expect the most movement among the non-`new` crates.
- **new** — just landed; the surface and the empirically-validated CLI argv/JSON may
still shift. `vcs-gitlab` / `vcs-gitea` are lean MR/PR lifecycles, mostly
fixture-pinned (`vcs-gitea` is the narrower of the two — see its capability notes);
`vcs-forge`'s unified DTOs grow with the wrappers; `vcs-watch` is the workspace's
first runtime-tokio + streaming API (its event set may shift); `vcs-mcp` is the MCP
server (a lib + binary), whose tool catalogue, names, and JSON shapes will grow.
## MSRV policy
The **minimum supported Rust version is 1.88** (edition 2024 needs 1.85, but the
wrappers use let-chains, stabilised in 1.88). It is declared once in
`[workspace.package]` as `rust-version = "1.88"` and inherited by every crate, so
`cargo build` on an older toolchain fails early with a clear message — the
contract is **machine-checked**, not just documented.
An MSRV bump is treated as a **minor**-version change (a `0.x` minor today; a
major after 1.0 if a consumer pins an older toolchain) and is called out in the
changelog. We bump the MSRV only when a dependency or a genuinely useful language
feature requires it — not casually.
## Public-API review checklist (the 1.0 gate)
Before any crate is tagged `1.0`, its public surface is reviewed against the
invariants this workspace already holds (most are enforced today; 1.0 makes them
a promise):
- **Trait object-safety & mockability.** Every public trait stays object-safe
(no generic methods, no nested-reference lifetimes — owned
`&[String]`/`Option<String>`, not `&[&str]`/`Option<&str>`), so `&dyn Api` and
`async-trait` keep working. The **wrapper** traits (`GitApi`/`JjApi`/
`GitHubApi`/`GitLabApi`/`GiteaApi`) are additionally `mockall`-friendly: the
`mock` feature generates a `Mock*Api`. The **facade** traits (`VcsRepo`,
`ForgeApi`) deliberately carry **no** `mock` feature — they're generated by a
`macro_rules!` whose `:ty` signatures `mockall::automock` can't parse — so the
facades are tested over a fake runner (`Repo::from_git` / `Forge::for_github`),
which is their documented test path anyway.
- **`#[non_exhaustive]` on returned types.** Every struct/enum a consumer *reads*
(DTOs, parsed results) is `#[non_exhaustive]` so a new field/variant isn't a
breaking change — except deliberate value types (`Version`) that callers
legitimately construct.
- **Structured errors.** Failures surface as `processkit::Error` variants
(`Exit`/`Timeout`/`Spawn`/`Parse`), never a stringly-typed blob; the facade adds
only repo-detection variants. Classifiers (`is_merge_conflict`, …) give intent
without matching on internals.
- **Injection-safe by default.** Caller strings in bare positional argv slots are
guarded (`reject_flag_like`); flag-value slots are documented as exempt.
- **No leaked internals.** Re-exports are explicit (no glob leaks); private
parsers/helpers stay private; the `cli_client!` seam isn't part of the surface.
- **Docs + tests.** Every public method has a doc comment and at least a hermetic
test pinning its argv/parse; the pure parsers are property-tested for
panic-freedom; real-binary behaviour is covered by the `#[ignore]` integration
suites (CI version-matrixes jj).
## See also
- [AGENTS.md](https://github.com/ZelAnton/vcs-toolkit-rs/blob/main/AGENTS.md) — the release process, changelog curation, and
dependency conventions.
- [Process model & errors](https://docs.rs/vcs-core/latest/vcs_core/guide/process_model/) — the error model the API review
references.
- [ROADMAP.md](https://github.com/ZelAnton/vcs-toolkit-rs/blob/main/ROADMAP.md) — `6.12` and the remaining path-to-1.0 work.