Skip to content

RFC: Native monorepo versioning - #18

Merged
zkochan merged 26 commits into
mainfrom
rfc/monorepo-versioning
Jul 13, 2026
Merged

RFC: Native monorepo versioning#18
zkochan merged 26 commits into
mainfrom
rfc/monorepo-versioning

Conversation

@zkochan

@zkochan zkochan commented Jul 12, 2026

Copy link
Copy Markdown
Member

Summary

Proposes built-in release management for pnpm workspaces: recording change intents, bumping versions across the workspace (dependent propagation, fixed/linked groups), writing changelogs, and — the headline capability — per-package prerelease lines, which changesets' workspace-global pre mode structurally cannot express.

The intent-file format is changesets-compatible (.changeset/*.md), so existing repositories can adopt it by deleting a devDependency, and a differential test oracle against changesets keeps parity honest. Configuration moves into pnpm-workspace.yaml under a versioning: key.

Also proposes registry-backed changelog storage as the default (repository mode is the changesets-compatible opt-out): no changelog prose lives in version control — a committed changelog only duplicates what git history and the published tarballs already record. Intent files stay the single copy of the text, tracked through the release tag by a consumed-ids ledger and garbage-collected only once the registry confirms the prose is archived in a published tarball; publish composes the full history by extending the previously published version's changelog.

Motivated concretely by the workarounds pnpm's own monorepo needed to release the TypeScript CLI, the Rust CLI (on a 12.0.0-alpha.N line), and pnpr (on a 0.1.0-alpha.N line) from one changesets workspace — see pnpm/pnpm#12949.

Rendered: text/0006-monorepo-versioning.md

Opened as a draft for early feedback; the Unresolved Questions section lists the open bikesheds (command naming, config key, changelog pluggability, git/tagging scope, action/bot story).


Written by an agent (Claude Code, claude-fable-5).

Summary by CodeRabbit

  • Documentation
    • Added an RFC describing native monorepo versioning for pnpm.
    • Documented a changesets-compatible release workflow driven by intent files, including commands to record changes, preview a release plan, and enforce diff-based coverage checks in CI.
    • Defined workspace-aware version-plan generation, fixed/ignored package configuration, changelog storage modes, and changelog/manifest update behavior.
    • Explained prerelease and release-lane semantics, intent cleanup rules, and behavior for snapshot releases.

Propose built-in, changesets-file-format-compatible release management:
recording change intents, workspace version bumping with dependent
propagation and fixed/linked groups, changelog generation, and
per-package prerelease lines (the capability changesets' global pre
mode cannot express), configured in pnpm-workspace.yaml.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@zkochan, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ff6c9a8-0f38-4ea4-8f0f-bfb613087dc3

📥 Commits

Reviewing files that changed from the base of the PR and between dc2c8a5 and ccbccaf.

📒 Files selected for processing (1)
  • text/0006-monorepo-versioning.md
📝 Walkthrough

Walkthrough

The RFC proposes native pnpm monorepo versioning through changeset-compatible intents, CI coverage checks, recursive release planning, workspace configuration, changelog storage modes, release lanes, snapshots, and shared TypeScript/Rust implementation.

Changes

Native monorepo versioning

Layer / File(s) Summary
Intent recording and release flow
text/0006-monorepo-versioning.md
Defines pnpm change, pnpm change status, and pnpm change check, plus intent consumption by pnpm version -r for release plans, manifest updates, changelogs, and cleanup.
Versioning configuration and release state
text/0006-monorepo-versioning.md
Documents versioning limits, fixed groups, epics, changelog storage and ledgers, release lanes, package identity, and snapshot releases.
Implementation scope and unresolved decisions
text/0006-monorepo-versioning.md
Describes alternatives, TypeScript and Rust implementation modules, differential tests, prior art, and open design questions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Poem

I’m a bunny with a changelog bright,
Hopping through intents by moonlight.
Fixed groups thump, prereleases flow,
Workspace versions neatly grow.
“pnpm change!” I cheer with delight—
Release plans bloom by morning light.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the RFC’s main topic: native monorepo versioning for pnpm.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rfc/monorepo-versioning

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

zkochan and others added 8 commits July 12, 2026 11:14
Add a changelog.storage option: "repository" keeps the appended,
committed CHANGELOG.md; "registry" commits only the newest release's
section and composes the full history at publish time by extending the
previously published tarball's changelog. Previous-version selection is
semver-based so concurrent release lines chain on their own ancestry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reviewing the composed section in the release PR duplicates text already
reviewed in the intent files. Instead of committing the newest section,
keep the consumed intent files through the tag, track them in a small
consumed-ids ledger, compose the section at publish time, and delete the
files on the next version run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Before publish, the intent file is the only copy of the changelog prose
in registry storage mode, so deletion must wait until the ledgered
version is confirmed published — which also self-heals releases that
were versioned and tagged but never published.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y the opt-out

Document the preconditions as opt-out guidance (foreign publishers,
Renovate/Dependabot visibility via GitHub releases, byte-reproducibility
for attested builds), harden intent GC to verify the published tarball
actually contains the composed section, and have the migration codemod
set repository mode when committed changelogs exist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The intent files' prose survives in git history after deletion, so a
committed changelog records nothing the repository doesn't already hold;
the browsability trade-off is a convenience, not a loss of information.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add pnpm change check: every package touched by the branch diff must be
named in a pending intent or explicitly declined via a none strategy
(an additive extension to the changesets format), with ignore patterns
for files that never warrant a release. Expand the Yarn prior-art entry
and raise its transitive dependent-decision rule as an open question.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add versioning.maxBump (from Rush's lockedMajor version policy): a
per-branch cap that makes a cherry-picked minor/major intent fail the
version run on a patch-only maintenance branch instead of silently
shipping a feature release. Credit rush change --verify as the original
diff-derived coverage enforcement and expand the Rush prior-art entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bit converges on recorded-intent versioning independently (soft tags
persisted by CI), validating the file-per-intent format by counterexample
(.bitmap conflicts on concurrent PRs) and the mechanical dependent
propagation default (bit auto-tags dependents with an opt-out).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan and others added 8 commits July 12, 2026 11:53
- cite the 2019 request and the catalog change-detection gap in the
  motivation, and make the coverage check catalog-aware (a catalog entry
  change touches every package referencing it)
- record Yarn's nextVersion-in-manifest rewrite (yarnpkg/berry#682) as a
  third case for per-change intent files, and lerna-lite's chase of
  pnpm-native semantics as an argument for the native approach
- new open questions from the threads: rebase-i-style interactive UX,
  a conventional-commits bridge, and Lerna's two-phase atomic publish

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pnpm change check needs no new configuration: the touched-package
computation is the detection behind --filter="[<ref>]", and
changed-files-ignore-pattern / test-pattern already express which files
never warrant a release. Landing catalog-aware attribution in the shared
machinery gives filtered builds and tests the same awareness.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pnpm has no --workspace convention for whole-workspace operations;
the recursive form of pnpm version (bare, no bump argument) consumes
pending intents, the explicit-bump form keeps its npm-style meaning,
and --filter selects a subset of the pending plan (with fixed-group
companions and invalidated dependents pulled in), enabling
single-product releases from multi-product repositories.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…protocol

The version step touches only version fields. Internal dependencies
must use the workspace: protocol, whose concrete ranges pnpm already
materializes at pack time, so range-rewrite machinery doesn't exist
here at all and dependent propagation derives from the protocol
modifier (* → any bump, ~ → minor+, ^ → major) instead of range
matching. Plain-range or catalog-declared internal deps fail loudly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Explain what the grouping keys do and right-size them: fixed groups are
a real need (pnpm ships pacquet + napi in lockstep); ignore shrinks to
freezing releasable packages because auto-exclusion of versionless
private packages covers changesets' main use case; linked is deferred —
rare, surprising jump-to-highest semantics, purely additive later.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Native support for the scheme pnpm's monorepo enforces via a
meta-updater plugin: member majors live in the lead's major × 100 band
(pnpm 11 → 1100-1199), move independently inside it (including their
own breaking changes, unlike a fixed group), and re-base to the band
floor when the lead reaches a new stable major, waiting out prerelease
lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A name glob is the wrong membership primitive: pnpm's own repo hosts
products outside the TS epic that share the @pnpm scope (@pnpm/napi,
@pnpm/pnpr, @pnpm/pnpr.client). Epics select members with pnpm's
existing --filter selector language (name globs, directory selectors,
negations), and a package matched by an epic while belonging to a fixed
group or prerelease line outside it is a configuration error, so an
over-broad glob cannot silently re-base an unrelated product.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ycle

The consumed-intent ledger is mode-independent, not a registry-storage
detail: pending intents are files whose id is not ledgered on any line,
which natively absorbs the .changeset-released mechanism pnpm's repo
built on top of changesets — cherry-picked intents release once per
line, merge-backs cannot re-apply them, and merge-time file
resurrection/deletion becomes harmless by construction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@zkochan
zkochan marked this pull request as ready for review July 12, 2026 11:05
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

RFC: Add native pnpm workspace versioning with per-package prerelease lines

📝 Documentation ✨ Enhancement 🕐 40+ Minutes

Grey Divider

AI Description

• Proposes pnpm-native workspace release management using changesets-compatible intent files.
• Defines version plan assembly (propagation, fixed groups, epics) plus per-package prerelease
 lines.
• Introduces registry-backed changelog storage option and a consumed-intents ledger for branch
 safety.
Diagram

graph TD
A["Contributor"] --> B["pnpm change"] --> C[(".changeset intents")]
C --> D["pnpm version -r"] --> E[("package.json versions")]
D --> F[("consumed-ids ledger")]
G[("pnpm-workspace.yaml versioning") ] --> D
D --> H["pnpm publish -r"] --> I[("registry tarballs (CHANGELOG.md)")]
F --> H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Ship native versioning but keep changelogs in-repo (repository mode only) for v1
  • ➕ Avoids non-reproducible tarball composition concerns and simplifies the mental model
  • ➕ Keeps compatibility with downstream tooling that scrapes repo changelogs (Renovate/Dependabot)
  • ➕ Reduces the number of new lifecycle states (GC + registry confirmation) in the first release
  • ➖ Doesn’t address changelog-PR churn/conflicts that motivated registry storage
  • ➖ Still duplicates prose between intent files (pre-version) and CHANGELOG.md (post-version)
2. Implement per-package prerelease lines as an external plugin initially
  • ➕ De-risks the biggest semantic divergence from changesets by isolating it
  • ➕ Lets pnpm validate intent lifecycle and propagation first, before adding half-consumption state
  • ➖ Splits the UX and undermines the “delete a devDependency” migration story
  • ➖ Makes correctness/parity testing harder because behavior depends on plugin presence
3. Keep recommending changesets + pnpm-maintained wrapper tooling
  • ➕ No new core surface area in pnpm; leverages existing ecosystem
  • ➕ Minimizes immediate maintenance burden
  • ➖ Does not solve the structural limitation: workspace-global pre mode
  • ➖ Continues duplicative config and partial understanding of pnpm-specific semantics (catalogs/workspace protocols)

Recommendation: The RFC’s core direction (pnpm-native plan assembly with changesets-compatible intents and per-package prerelease lines) is strategically strong and addresses real structural gaps. The main decision worth revisiting is defaulting to registry-backed changelog storage: it’s innovative but introduces supply-chain/reproducibility tradeoffs and downstream tooling friction. A pragmatic path is to keep registry mode as an explicit opt-in (at least initially) while proving the ledger + per-package prerelease/half-consumption semantics; once operational experience is positive, revisit the default.

Files changed (1) +232 / -0

Documentation (1) +232 / -0
0006-monorepo-versioning.mdAdd RFC for pnpm-native monorepo versioning and changelog storage +232/-0

Add RFC for pnpm-native monorepo versioning and changelog storage

• Introduces an RFC proposing built-in pnpm workspace versioning using changesets-compatible intent files, including plan assembly (propagation, fixed groups, epics) and per-package prerelease lines. Specifies configuration under pnpm-workspace.yaml, CI coverage checks, and a consumed-intents ledger for maintenance-branch safety. Proposes a default registry-backed changelog storage mode with tarball-based history composition and deferred intent garbage collection.

text/0006-monorepo-versioning.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@text/0006-monorepo-versioning.md`:
- Around line 32-47: Add language identifiers to every fenced code block in
text/0006-monorepo-versioning.md, including the command examples and changeset
Markdown example. Use sh for shell commands and markdown for the changeset
content, covering the additional referenced fenced blocks as well.
- Line 99: Update the release planning flow described in
text/0006-monorepo-versioning.md so versioning.maxBump is validated only after
dependent propagation, fixed-group resolution, and epic rebasing have produced
the complete final plan. Reject any final package bump exceeding the configured
cap, and report the maxBump constraint that caused the violation rather than
validating only declared intent types.
- Around line 145-151: Revise the proposal’s ledger and pending-set rules so
intent consumption is scoped by release line and package (or target release),
rather than by globally unique intent ID. Ensure an intent consumed on
release/11.0 remains pending for main until main’s corresponding package release
records its own consumption, preserving the required bump and changelog entry.
- Line 172: The prerelease design must define an authoritative per-package
consumption ledger before implementation, including how package/version entries
map to intent IDs and how pending detection uses that state. Specify the exact
per-package pending-changelog representation under .changeset, then document
deletion and garbage-collection behavior for both the ledger and pending state,
including half-consumed intents and post-graduation cleanup.
- Line 78: The workspace:^ propagation rules must account for 0.x semver
behavior. Update the dependency bump logic described in the internal dependency
propagation section to evaluate the materialized published range and propagate
dependent bumps when a new 0.x version falls outside the previous ^ range,
including 0.2.x to 0.3.x transitions, while preserving existing behavior for
ranges that remain compatible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8e495b3c-e19f-458d-8029-e16b8263211b

📥 Commits

Reviewing files that changed from the base of the PR and between e992b4a and 2074da2.

📒 Files selected for processing (1)
  • text/0006-monorepo-versioning.md
📜 Review details
🧰 Additional context used
🪛 LanguageTool
text/0006-monorepo-versioning.md

[grammar] ~180-~180: Use a hyphen to join words.
Context: ...ctural, not bugs to wait out: global pre mode and name-keyed data cannot be fixed...

(QB_NEW_EN_HYPHEN)


[grammar] ~211-~211: Use a hyphen to join words.
Context: ...le model this RFC adopts; its global pre mode and name-keyed format are the struc...

(QB_NEW_EN_HYPHEN)


[uncategorized] ~223-~223: The official name of this software platform is spelled with a capital “H”.
Context: ...dencies, or start with built-in plain/github formats only? - **Should `.changeset/c...

(GITHUB)

🪛 markdownlint-cli2 (0.22.1)
text/0006-monorepo-versioning.md

[warning] 32-32: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 63-63: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 157-157: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (3)
text/0006-monorepo-versioning.md (3)

1-24: LGTM!

Also applies to: 28-59, 80-98, 100-119, 153-171, 174-218


130-130: 🗄️ Data Integrity & Integration

This is an open design choice, not a contradiction. The semver-based previous-version rule is the stated default; the graduation-base question below still needs a decision.

			> Likely an incorrect or invalid review comment.

76-76: 🗄️ Data Integrity & Integration

Registry-mode changelog composition is already built into pnpm publish -r. It fetches the previous tarball, prepends the composed section, repacks it, and defers intent cleanup to a later pnpm version -r run.

			> Likely an incorrect or invalid review comment.

Comment thread text/0006-monorepo-versioning.md Outdated
Comment thread text/0006-monorepo-versioning.md Outdated
Comment thread text/0006-monorepo-versioning.md Outdated
Comment thread text/0006-monorepo-versioning.md Outdated
Comment thread text/0006-monorepo-versioning.md Outdated
…n-level maxBump, per-package ledger

- propagation evaluates the materialized semver range instead of a
  per-modifier rule, keeping 0.x caret semantics correct
- maxBump is enforced on the final assembled plan (propagation, fixed
  groups, epic re-base can raise a bump above declared intents)
- ledger consumption is scoped per package, with the explanation of why
  merge-carried entries cannot suppress a needed bump
- the ledger is the single authoritative consumption record for
  half-consumed intents; deletion follows one rule in both storage modes
- language identifiers on the command code fences

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan and others added 3 commits July 12, 2026 14:47
…embership is declared directly in pnpm-workspace.yaml

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stable/unstable

The bare "pre" token sits in npm's bump-keyword slot, where it is itself
a valid node-semver increment type, so a mode-toggling "pre enter/exit"
sub-verb both reads oddly and shadows a real increment. stable/unstable
name the state the packages move to. The commands remain convenience
editors for versioning.prereleases in pnpm-workspace.yaml, which stays
the reviewable source of truth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…npm lane command

Rename the concept to lanes (Bit's name for the same idea) and move the
command out of pnpm version's bump-keyword slot to a root command:

  pnpm lane alpha --filter <pkg>...   # move packages onto the alpha lane
  pnpm lane main --filter <pkg>...    # return them to the main lane
  pnpm lane                           # show lane membership

main is the reserved default lane, as in Bit. The config key becomes
versioning.lanes and stays the reviewable source of truth; the command
is a convenience editor for it. Freeing the word "line" also removes
an overload — it now refers only to maintenance release lines (11.x).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan added a commit to pnpm/pnpm that referenced this pull request Jul 12, 2026
Mirrors the TypeScript implementation of the native monorepo versioning RFC
(pnpm/rfcs#18, plan:
#12952) in the Rust stack:

- New `pacquet-versioning` crate: the changesets-compatible intent
  reader/writer (plain-text frontmatter parsing, BOM/CRLF tolerant,
  embedded human-readable id word lists), the per-package consumed-intents
  ledger (.changeset/ledger.yaml, same YAML shape the TS side writes), the
  release-plan assembler (direct bumps, dependent propagation through
  materialized workspace: ranges evaluated with node-semver, fixed groups,
  ignore, maxBump against the real version distance, --filter narrowing,
  per-package prerelease lines with cumulative stable-target escalation and
  graduation, snapshots), and the applier (manifest version updates,
  byte-identical changelog composition, ledger append, intent GC with the
  prerelease retention exemption). Error codes and messages match the
  TypeScript CLI.
- `versioning` settings parsed from pnpm-workspace.yaml onto Config
  (fixed/ignore/maxBump/prereleases/changelog), mirroring PnpmSettings.
- New `pnpm change` / `pnpm change status` command (dialoguer prompts in
  the interactive path, --bump/--summary scriptable path).
- New `pnpm version` command: the bare `-r` form consumes intents
  (--dry-run, --snapshot [tag], --no-git-checks with the same clean-tree
  check as publish), and `unstable <tag>` / `stable` manage prerelease
  lines through the format-preserving workspace manifest writer. The
  npm-style explicit-bump forms error with a clear not-yet-ported message —
  they did not exist in pacquet before this change either.
- Unit tests mirror the TypeScript engine suite one for one (33 tests), and
  the integration tests drive the built binary through the full record →
  plan → release → prerelease → graduation → snapshot flow.

The two deploy install futures are boxed because Config grew past clippy's
large-future threshold with the new settings field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan added a commit to pnpm/pnpm that referenced this pull request Jul 12, 2026
…anes

Tracks the updated RFC (pnpm/rfcs#18): the concept is
now a lane — a named parallel release track, with `main` as the reserved
default lane every package is on unless assigned elsewhere (the same model,
and name, as Bit's lanes).

- `versioning.prereleases` becomes `versioning.lanes` in
  pnpm-workspace.yaml, in both stacks' settings types.
- Lane management moves off `pnpm version` onto a new root `pnpm lane`
  command: `pnpm lane <name> --filter <pkg>` assigns, `pnpm lane main`
  returns packages to the default lane, and bare `pnpm lane` prints the
  membership. The version-argument slot stays reserved for npm's bump
  grammar, where a mode verb would read as a bump and leave the read side
  homeless.
- Engine internals and messages adopt the lane terminology in both stacks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan and others added 2 commits July 12, 2026 16:17
…ames as aliases

Two workspace projects can publish the same npm name — pnpm's own repo
is heading there with the TS CLI (pnpm11/pnpm, 11.x) and the Rust CLI
(pnpm/npm/pnpm, 12.x) releasing concurrently from one branch. Every
serialized format gets a collision rule: intent files accept directory
path references (the single additive extension to the changesets
format), the ledger records the directory, versioning.lanes keys accept
paths, and an ambiguous bare name is a listed-candidates error, never
a silent pick.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… atomicity for capable registries

Snapshot releases are the producer for the proposed bit-registry lanes
(automatic branch publishing): snapshot with the branch name, --batch
publish so the lane lands atomically, discard — nothing is consumed or
ledgered, so nothing can double-release after merge. The stated hard
requirement is registry-side isolation: lane versions must stay out of
the main packument, or previous-version changelog chaining and ledger
GC confirmation both misbehave. New unresolved questions: basing lane
snapshots on the plan target instead of 0.0.0-*, and defaulting the
dist-tag / registry lane to the versioning-lane name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan added a commit to pnpm/pnpm that referenced this pull request Jul 12, 2026
Tracks the RFC update (pnpm/rfcs#18): the versioning
engine's unit of identity becomes the workspace-relative project directory,
not the package name. Names are aliases resolved against the workspace at read
time, and a name that resolves to more than one project is a hard validation
error naming the candidate directories — never a silent pick. This is the
concrete fix for the name-keying flaw the RFC attributes to changesets, and it
is not hypothetical: pnpm's own repo is heading toward two workspace projects
publishing the name "pnpm" (the TS CLI on the 11.x line and the Rust CLI on
the 12.x line) releasing concurrently from one branch.

Directory identity surfaces in each serialized format, in both stacks:

- Intent files may reference a package by workspace-relative path
  (`"./pnpm/npm/pnpm": patch`) alongside bare names — the one additive
  extension to the changesets format. `pnpm change` writes path references
  automatically when the chosen name is ambiguous, and its interactive picker
  labels colliding names with their directory, so contributors never need to
  know the rule exists.
- Ledger entries record the released project directory
  (`{ dir, intents }`) alongside `package@version`; the bare id-list shape
  is still read for hand-written entries and attributed by the (unambiguous)
  name in the key.
- `versioning.lanes`, `versioning.fixed`, and `versioning.ignore` accept
  directory paths, and `pnpm lane` reads/writes them keyed by project.
- Changelogs already lived in each project directory.

Internal plan assembly, propagation, and changelog composition are now
directory-keyed throughout. A `workspace:` dependency naming an ambiguous
package is rejected (it cannot be linked at install time anyway).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Snapshot is a publish concern: it mutates nothing durable, and the only
work it needs — deriving target versions and rewriting version/workspace:
fields — is a pack-time in-memory manifest transform, the same category
exportable-manifest already owns. pnpm publish -r --snapshot calls the
shared assembler and packs against the derived versions without dirtying
the working tree, eliminating the version --snapshot -> publish ->
git checkout dance. pnpm version -r is now strictly the durable half.
The registry-lane flow collapses to one command:
pnpm publish -r --batch --snapshot <branch>.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
zkochan added a commit to pnpm/pnpm that referenced this pull request Jul 12, 2026
Tracks the RFC update (pnpm/rfcs#18): pnpm version -r
is now strictly the durable half of the release pipeline — it mutates
manifests, consumes intents, writes changelogs, and ledgers, and nothing
else. Snapshot is a pack-time, in-memory concern that belongs to
`pnpm publish` (assemble the plan, pack against the derived versions without
touching the working tree), tied to the registry-lanes story; it is left for
the publish phase tracked in #12952.

Removes the --snapshot flag (and its snapshot-suffix / tag-validation
plumbing) from the version command in both stacks, and drops the applier's
disk-writing snapshot mode — snapshot must never dirty the working tree. The
release-plan assembler keeps its snapshot_suffix capability (the in-memory
version-derivation primitive the publish path will call).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ection

The RFC is about the client half. Snapshots emit 0.0.0-* prereleases
through the ordinary publish path with a dist-tag; ephemeral/branch
distribution and retention of throwaway versions are the registry's
concern and out of scope. Drop the 'versions must stay outside the
main packument' isolation requirement (a single packument is fine)
and the registry-lane unresolved questions; keep the client-side
atomic-publish question.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@text/0006-monorepo-versioning.md`:
- Line 219: Update the CLI commands list in the monorepo versioning plan to
include the first-class `pnpm change check` command alongside `pnpm change` and
`pnpm change status`, while preserving the existing command infrastructure and
configuration wiring references.
- Line 113: Update the membership validation rules in the versioning
specification to detect any package matched by more than one epic, including
overlapping name or directory selectors. Require validation to fail with an
explicit configuration error identifying the package and conflicting epics,
rather than choosing or silently resolving one band.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad7ffc08-f8f7-4732-9323-acb17c5f24bc

📥 Commits

Reviewing files that changed from the base of the PR and between 2074da2 and dc2c8a5.

📒 Files selected for processing (1)
  • text/0006-monorepo-versioning.md
📜 Review details
🧰 Additional context used
🪛 LanguageTool
text/0006-monorepo-versioning.md

[style] ~184-~184: Consider an alternative for the overused word “exactly”.
Context: ...alpha.9), but "usually unambiguous" is exactly the reasoning being retired. - **versi...

(EXACTLY_PRECISELY)


[style] ~194-~194: ‘by accident’ might be wordy. Consider a shorter alternative.
Context: ...sitting on disk waiting to be committed by accident in CI. In normal mode pnpm publish -r...

(EN_WORDINESS_PREMIUM_BY_ACCIDENT)


[grammar] ~200-~200: Use a hyphen to join words.
Context: ...ctural, not bugs to wait out: global pre mode and name-keyed data cannot be fixed...

(QB_NEW_EN_HYPHEN)


[grammar] ~231-~231: Use a hyphen to join words.
Context: ...le model this RFC adopts; its global pre mode and name-keyed format are the struc...

(QB_NEW_EN_HYPHEN)

🔇 Additional comments (1)
text/0006-monorepo-versioning.md (1)

1-61: LGTM!

Also applies to: 62-79, 80-120, 121-152, 153-188, 189-208, 209-218, 220-252

Comment thread text/0006-monorepo-versioning.md Outdated
Comment thread text/0006-monorepo-versioning.md Outdated
zkochan added a commit to pnpm/pnpm that referenced this pull request Jul 12, 2026
… change intents, release plans, per-package release lanes (#12953)

Implements phases 1-2 of the native monorepo versioning plan
(#12952, RFC pnpm/rfcs#18)
in both stacks.

TypeScript: new @pnpm/releasing.versioning package (intent reader/writer for
changesets-compatible .changeset/*.md files with the additive 'none' decline;
the committed per-package consumed-intents ledger .changeset/ledger.yaml;
the release-plan assembler with direct bumps, dependent propagation via
materialized workspace: ranges under real semver semantics, fixed groups,
ignore, maxBump enforced against the real version distance, --filter
narrowing, per-package release lanes with cumulative stable-target
escalation and graduation; the applier with format-preserving
version-only manifest updates, changelog composition in repository storage
mode, ledger append, and intent GC with the prerelease retention exemption).
CLI: pnpm change / change status; bare pnpm version -r (--dry-run,
the new root pnpm lane command manages
versioning.lanes through the format-preserving workspace manifest writer. The versioning key is typed on PnpmSettings/Config and validated by
the workspace manifest reader.

Rust: new pacquet-versioning crate mirroring the engine (same file formats,
error codes, messages, and output), versioning settings on
WorkspaceSettings/Config, and new change/version/lane commands in pacquet-cli.
The npm-style pnpm version <bump> forms remain unported in pacquet (they
did not exist there before) and error with a clear message. The two deploy
install futures are boxed because Config grew past clippy's large-future
threshold.

Both stacks' engine test suites mirror each other one for one; integration
tests drive the real binaries through record -> plan -> release ->
lane -> graduation.
…t pnpm change check

- A package matched by two different epics (overlapping selectors) now
  fails validation naming the conflicting epics, closing the ambiguous-
  band gap the epic + fixed-group / epic + lane rules left open.
- Add pnpm change check to the implementation CLI command list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@zkochan
zkochan merged commit 413a998 into main Jul 13, 2026
1 check passed
jtmthf added a commit to jtmthf/scholia that referenced this pull request Jul 27, 2026
pnpm/rfcs#18 (merged 2026-07-13) proposes a built-in replacement for
@changesets/cli with --bump/--summary flags — exactly the non-interactive
authoring surface @changesets/cli lacks. Adding a "Future" section to
ADR-0026 so a future agent or human has the context to migrate without
re-deriving it: stay on Changesets and write files directly (already
agent-friendly, format-compatible with the RFC), migrate when pnpm
declares native versioning done, our packageManager pin is already past
11.14, and the GitHub-Action question is settled. No code change.
jtmthf added a commit to jtmthf/scholia that referenced this pull request Jul 27, 2026
pnpm/rfcs#18 (merged 2026-07-13) proposes a built-in replacement for
@changesets/cli with --bump/--summary flags — exactly the non-interactive
authoring surface @changesets/cli lacks. Adding a "Future" section to
ADR-0026 so a future agent or human has the context to migrate without
re-deriving it: stay on Changesets and write files directly (already
agent-friendly, format-compatible with the RFC), migrate when pnpm
declares native versioning done, our packageManager pin is already past
11.14, and the GitHub-Action question is settled. No code change.
jtmthf added a commit to jtmthf/scholia that referenced this pull request Jul 27, 2026
* Automate releases with Changesets and trusted publishing

Releases stop being a manual `npm publish` from a laptop. This wires up
Changesets (versioning, changelog generation, CI changeset gate) and an
npm trusted-publishing release workflow (OIDC, no long-lived NPM_TOKEN).
A changeset is required for user-facing CLI changes; private @scholia/*
packages are opted out of versioning. CHANGELOG.md is now generated;
the existing 0.1.0 entry is preserved. Tags and GitHub Releases are
created by changesets/action.

End-to-end verification (a registry-installed patch release) is a
post-merge step — it requires the npm-side trusted-publisher registration
noted in ADR-0026, plus a real release run.

Records the decision in ADR-0026 and notes the workflow in CONTRIBUTING.md.

Closes #21

* Document the changeset rule in AGENTS.md

Every agent session reads AGENTS.md by default, but the changeset
requirement lived only in CONTRIBUTING.md (human-facing) and the CI
gate (catch-as-fail after the fact). Adding it to AGENTS.md makes agents
aware of the rule before they commit, so they add a changeset for
user-facing CLI changes rather than learning about it from a red CI run.
No changeset needed for this commit — AGENTS.md is internal.

* Show the changeset file format in AGENTS.md

`pnpm changeset` is interactive, which an agent can't drive. Replacing
the "run pnpm changeset" instruction with the file format directly
(frontmatter + summary) lets an agent write the changeset file in one
shot instead of burning tokens probing the interactive CLI. No changeset
needed — AGENTS.md is internal.

* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Record pnpm native versioning as the future state in ADR-0026

pnpm/rfcs#18 (merged 2026-07-13) proposes a built-in replacement for
@changesets/cli with --bump/--summary flags — exactly the non-interactive
authoring surface @changesets/cli lacks. Adding a "Future" section to
ADR-0026 so a future agent or human has the context to migrate without
re-deriving it: stay on Changesets and write files directly (already
agent-friendly, format-compatible with the RFC), migrate when pnpm
declares native versioning done, our packageManager pin is already past
11.14, and the GitHub-Action question is settled. No code change.

* Trim AGENTS.md Changesets section to a signpost

The file format and rules moved to .changeset/README.md (the canonical
home for changeset authoring detail). AGENTS.md is sent in every agent
message, so it gets a one-paragraph signpost that links there, not the
full file-format example. Cuts ~20 lines / ~800 bytes of always-on
context. No agent-visible behaviour change — the detail is one click
away at the linked file.

* Trim AGENTS.md Changesets section to one line

One sentence: what needs a changeset, agents write the file directly,
link to the format, link to ADR-0026. The detail lives in
.changeset/README.md and the ADR.

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants