Receiving packages
The managed source transfer, the one supported way to bring a package into your repository and to update it.
A package arrives in your repository as source: its folder is copied unchanged into
packages/<name>, and a provenance record says exactly which bytes came from which source state.
There is no registry and no built artefact. Your installation, tests and builds never need a path
to the repository the package came from.
What you need#
-
A pnpm workspace whose
packagesincludepackages/*. -
Node.js 26 or later.
-
A
.gitattributesentry that keeps the transferred bytes exactly as they are, so a checkout on Windows does not convert line ends:Textpackages/** -text -
A TypeScript-aware build: packages ship TypeScript source (
exportspoint tosrc/). Vite compiles a linked workspace package as it is; for Next.js, list the package intranspilePackages.
The two sides#
| Side | Tool | What it does |
|---|---|---|
| the source repository | rps- | composes a bundle for the packages you request: their folders, what they need, provenance |
| your repository | rps- | the applier: plans and applies a bundle in your repository, and checks your managed state |
The applier is two files, rps-apply.mjs and rps-contract.mjs, that you keep in your own
repository under tools/rps/. Every bundle carries a reference copy of them under tooling/, so
you can take them from the first bundle you receive. Review them before you commit them.
Every package in the catalogue is maintained in Foundation, which composes its
bundles with pnpm rps:transfer bundle --products <product> --owners <owner> --channel <channel> --out <folder>. A product (such as active-ui, active-grid or active-i18n) brings the owners
it needs along; an owner (active-format, active-virtual, active-helpers, eslint-config) is
requested on its own with --owners. The lint preset never comes along by itself: add --owners eslint-config when you want it in your set. typescript-config is not transferred this way; see
the development basis. A bundle always holds your whole managed set: a
package left out of it is removed by the update. Ask the maintainer for a bundle; you never need
access to the source repository yourself.
Receiving a package, step by step#
From the root of your repository, in this order:
-
Receive. Plan the bundle, then apply exactly that plan:
Terminal# The ordered decision. Changes nothing; prints the operations and a digest.node tools/rps/rps-apply.mjs plan --bundle <bundle-folder> --development # Apply exactly that plan.node tools/rps/rps-apply.mjs apply --bundle <bundle-folder> --expect-plan <digest> --developmentThe package now sits in
packages/<name>. Do not edit it there. -
Declare the package where you use it, for example in your app's
package.json:JSON{ "dependencies": { "@workspace/active-format": "workspace:*" }} -
Install:
Terminalpnpm install -
Verify that the app resolves the managed copy:
Terminalnode tools/rps/rps-apply.mjs verify-install --from <app-folder>The output must name every package you declared, each as
current:Textcurrent @workspace/active-format 1.0.0 from apps/web (workspace link: packages/active-format)verify-installchecks only the managed packages the app declares. If it lists no package, it checked nothing: declare the package (step 2) and install (step 3) first. -
Use the package; see its Getting started page, for example active-format.
Channels#
- release: carries only recorded releases, each with exactly its recorded content.
- development: a visibly marked trial. The applier refuses it unless you pass
--development, and the provenance records it. A development transfer is never a release.
Updating#
An update brings your whole managed set to one new source state: every managed package moves together, and the plan shows which files are kept, updated, added or deleted. You decide when you update. A release in the source repository never changes your repository by itself.
Request the whole set every time. Your repository has one provenance record from one source. A
managed package that is missing from the next bundle is deleted by that update. Ask for a bundle
of every package in the request of your .rps/provenance.json (plus any you want to add), and
read the plan before you apply it: its line Requested packages kept: …; added: …; removed: … must
say removed: - unless you mean to remove a package.
Afterwards, repeat steps 3 and 4: install, and verify every app that uses the managed packages.
Local changes and conflicts#
Never edit a managed file. A change in a managed folder blocks the next update:
RPS-E4: a managed file differs from its recorded hash;RPS-E5: a folder the bundle would add already exists and is not managed;RPS-E16andRPS-E17: a managed file is missing or replaced by something else.
The plan names each conflict and changes nothing. Make the improvement in the source repository
and receive it with the next transfer. An interrupted application is recovered with
rps-apply recover --rollback; rps-apply status shows your managed state, and
rps-apply reconcile --bundle <folder> compares your files with a bundle without changing anything.
Your version and the newest version#
Your .rps/provenance.json records the packages, versions, channel and source state you use. The
package pages of this site show the version Foundation documents. When the two differ, read the
package's changelog between your version and the documented one before you update.