The copy-in model means Facet can never push an update: a component in your project is a file in your repository, and nothing reaches back into it. What the CLI offers instead is visibility.
facet diff
npx facet-rbxts diff # every installed componentnpx facet-rbxts diff button # oneCompares each copied file against what the registry would write there today. It replays the ~/
rewrite first, so your project’s alias and directory choices are not reported as changes.
The direction is registry → project. - is what the registry has and + is what your file says, so
applying the + side is what “keep mine” means.
Facet records nothing at copy time — no lock file, no hashes, no note of which registry version a file came from. A difference here is your edit, a change upstream, or both, and diff says so in its own output.
Your version control already knows which lines you wrote.
A component in the registry that is not in your project is reported and skipped.
Taking an upstream change
There is no command for this, and that is the model working as intended:
facet diff button— see what moved.- Decide. Most upstream changes to a component you have edited are not worth taking.
- If you want it,
facet add button --overwritereplaces the file wholesale and your edits are gone. Commit first, then reapply what you want from the diff.
--overwrite is deliberately blunt: there is no three-way merge, because there is no base text to
merge against.
facet remove
npx facet-rbxts remove badgenpx facet-rbxts remove badge --forceTwo refusals, and they are not the same kind of refusal.
A file that differs from the registry is refused without --force. “Differs” is the closest
stand-in for “you changed this”, and it also fires when only upstream moved. In the worst case you
are asked about a file you never touched. That is the safe direction to be wrong in.
A component another installed component still imports is refused, and --force does not cover
it. Deleting utils out from under an installed button leaves a project that does not compile.
That second check runs to a fixed point, which matters more than it sounds:
npx facet-rbxts remove button utilsIf button turns out to be modified and stays, utils is still imported — and a single pass would
already have cleared it. The plan is recomputed until nothing changes.
Directories are left alone, and so is anything you added next to the removed files.
Why there is no lock file
A facet.lock of per-file content hashes is the obvious fix for what diff cannot say, and it was
dropped. A hash answers whether a file differs, not how. Showing that needs the text you started
from, which means a second copy of every component committed to your repository. It also goes stale
for reasons that are not edits: a formatter pass, a rename, a move.
Pinning a registry revision
The default registry moves. https://facet.astra-void.xyz/r is republished on every push to
Facet’s main, so an edit reaches everyone immediately. That includes a project that ran
facet add months ago and will next run facet diff.
Every push also writes an immutable copy under the commit that produced it, and a project can point at one instead:
{ "registry": "https://facet.astra-void.xyz/r/a1b2c3d" }revisions.json lists what exists, newest first.
add, diff, list and doctor all read the field and all print which registry they used.
What pinning fixes: facet diff stops reporting upstream movement. Against a frozen revision a
difference is your edit or nothing — most of what the lock file was
supposed to buy.
What it does not fix: it is per-project, not per-component — “this project builds against that
registry”, not “button came from that revision”. And a pinned project stops receiving fixes until
someone moves the pin.
Pinning removes upstream movement as a source of drift. It does not record what your file started as. Move the pin forward and diff is back to reporting a difference it cannot explain.
What revisions genuinely unlock is that the base text becomes something the CLI could one day fetch rather than something you store. That is not implemented.
What to actually do
- Commit the copied files. They are source, not build output.
- Do not expect updates. If a component is a starting point you rewrote,
diffwill be noisy forever — stop running it on that component. - Run
facet doctorafter upgrading anything. It catches a project set up by an older CLI: copied files current, versions under them not.