rtb-cli changelog subcommand¶
Status: APPROVED — GTB-parity gap from the v0.22.0 audit (Phase 2,
§B). Feature::Changelog exists in rtb-app (features.rs:36,
"Structured release-notes display") but no command is registered behind
it — a dead flag. This backs it. Also resolves the
feature-has-backing-command edge in the MCP-gating + feature-toggle specs
(see cross-impact). No open design decisions.
Distinction (important): this is not changelog generation —
that is release-plz's job (per CLAUDE.md §Release; per-crate
CHANGELOG.md, do-not-hand-edit), and remains a non-goal. This is the
runtime end-user command mytool changelog that renders the tool's
own already-generated release notes to the user, mirroring GTB's
pkg/cmd/changelog.
1. Surface¶
- no flags → render the full changelog.
--latest→ only the newest version's entry.--version <v>→ only that version's entry (error if absent).--since <v>→ all entries newer thanv(exclusive).--latest/--version/--sinceare mutually exclusive (clap group).
Gated by Feature::Changelog — opt-in (not in Feature::defaults()),
consistent with RTB's safer-by-default posture.
2. Source of the changelog¶
The rendered content is the tool's own CHANGELOG.md, resolved through
App::assets (the rtb-assets overlay filesystem — embedded default +
user override), so a downstream tool embeds its release notes at build
time and may override at runtime. Absent asset → a clean
miette-diagnostic ("this tool ships no changelog").
3. Mechanism¶
- New builtin
ChangelogCmdincrates/rtb-cli/src/builtins.rs,spec()→feature: Some(Feature::Changelog), registered via#[distributed_slice(BUILTIN_COMMANDS)]likeversion/doctor. - Parse
CHANGELOG.mdinto(version, body)sections by the Keep-a-Changelog / release-plz heading convention (## [X.Y.Z] - date). Version compare viasemver(already in the tree via rtb-update). - Render the selected section(s) with
termimad(already a rtb-docs dependency) for styled terminal markdown; fall back to plain text when not a TTY (std::io::IsTerminal). - Filtering (
--latest/--version/--since) operates on the parsed section list before rendering.
4. Scaffolder note¶
The cli preset should ship a starter CHANGELOG.md asset so a scaffolded
tool's changelog command works once the feature is enabled. (Pairs with
the feature-toggle spec: enabling Changelog now yields a working
command, not a dead flag.)
5. Testing (TDD, ≥90%)¶
- Unit: section parser (well-formed, missing-heading, out-of-order
versions);
--versionselects the right body;--sinceis exclusive + ordered;--latestpicks the max semver; mutually-exclusive flags rejected by clap; absent asset → typed diagnostic. - E2E (
assert_cmd+insta): a tool with an embedded fixtureCHANGELOG.mdrenders full /--latest/--version/--since; snapshots of stdout; exit codes. Feature off → command absent from--help.
6. Cross-impact¶
2026-06-23-scaffolder-feature-toggle.md/-mcp-command-exposure-gating.md—Feature::Changelogwas the lone counterexample of a toggleable/gateable feature with no registered command. Implementing this command removes the edge case (the amendments to those specs still add the general "feature-has-backing-command" invariant as a guard against regressions).
7. Out of scope¶
- Changelog generation (release-plz owns it — non-goal).
- Aggregating per-crate workspace changelogs (the tool renders its own
single
CHANGELOG.md; a multi-crate downstream curates what it embeds).