facet install.
Ordering
An install MUST resolve and verify the complete desired set, and MUST compose one plan over all of it, before writing anything. Composing globally is what makes collision detection possible: two facets claiming one name cannot be detected once the first is already on disk. See Materialization. Project state MUST NOT be written unless every check passes. A failure before the first write leaves the project byte-identical. From the first write onward, an implementation MUST record enough state to restore every file it changes. A failure MUST then restore text assets, native configuration documents, and project state to their exact prior bytes, except where a path was changed by something else after this operation wrote it, or cannot be read or written back. Such a path MUST be left as it stands rather than overwritten, and every path an implementation could not return to its prior bytes MUST be reported.Resolve
Whether the lockfile is trusted for version resolution depends on how an entry was requested, not on a flag.- Implicit request. A non-exact specifier in an addition, such as a bare name,
1.*, orlatest, MUST resolve to the newest matching version even when the lockfile already satisfies it. The user asked for that range now. - Explicit request. An exact specifier, and any reproduction of an already-declared facet, MUST reuse a satisfying lockfile entry. Only an absent or stale entry triggers resolution.
- Reviewed update. A version chosen during an update’s read-only discovery MUST be installed as reviewed. Resolution MUST NOT be repeated at write time, so a release published in between cannot silently change what is installed.
Verification
Verification obligations are defined in the Integrity Model. An install MUST apply them:- Cached content MUST be re-verified on every use, and content that fails MUST NOT be materialized.
- When the lockfile pins a version, the verified integrity MUST equal the locked integrity. A mismatch MUST fail.
- When a lockfile entry is created or replaced, the integrity MUST be confirmed against the registry’s published fingerprint. An unreachable registry MUST fail rather than record an unconfirmed entry.
- A git source MUST verify its built content against the locked integrity, which is what detects a moved tag.
- Failures MUST be reported under distinct checks, so a frozen local-source failure is never reported as a git failure.
0.4 entry pins, its recorded server inventory MUST also agree with the verified declarations, whatever the source kind or cache state:
- The recorded authored names MUST equal the declared names, omitted servers included. A mismatch MUST report the sorted names that are locked but not declared, and declared but not locked.
- Each recorded fingerprint MUST equal the fingerprint recomputed from its declaration. A mismatch MUST report the facet, the server, and both fingerprints.
0.2 or 0.3 entry, has nothing to reconcile, and its inventory is derived fresh from verified content.
Composition
The desired set is computed by the deterministic planner defined in Materialization. Text assets and MCP servers are planned in separate identity spaces. A collision MUST NOT be resolved by choosing a winner or inventing a name. An implementation MUST either collect the user’s decision, recorded as durable intent infacets.json, or report every claimant and stop.
MCP configuration
A new or changed MCP server declaration MUST be approved before it is materialized.- Approval MUST be keyed by the effective server name and the declaration’s canonical content, so an unchanged declaration does not ask again and any change to what would launch or connect does.
- Interactive consumers MUST be shown the exact command, arguments, and environment assignments, or the exact URL, before anything is written. Non-interactive consumers MUST require an explicit opt-in.
- Approval MUST be recorded only by a fully successful operation. A declined, failed, or rolled back run MUST bank nothing.
- Approval MUST be machine-local. It MUST NOT be stored in version-controlled project state, because a committed file must not be able to claim that another machine consented to running something.
Ownership
Two rules govern every kind of state.- Desired state authorizes writes. Every desired identity is reconciled. When what is already present matches byte for byte, the write MAY be skipped, and the identity is still recorded as owned.
- Recorded ownership authorizes deletion. Only an identity this machine recorded materializing may be deleted. A lockfile entry alone is not evidence, because a lockfile is shared state that can arrive from a teammate.
Untracked destinations
A desired identity already occupied by state this machine does not own MUST be disclosed before it is adopted or replaced. Equivalent state MUST be adopted without rewriting it. Divergent state MAY be replaced once the user continues. State at an identity the desired set does not name MUST NOT be inspected or modified.Manifest write policy
The value written tofacets.json depends on the specifier shape, and is applied only as part of the final write.
An update decides its manifest value from the choice the user reviewed. Taking a facet’s range target never rewrites the specifier, and the authored string is preserved rather than re-rendered. Taking the latest release widens the specifier by the smallest edit that admits it:
Materialization overrides are carried across a version change untouched. An override naming something the new version no longer contains is pruned and reported.
Comments in
facets.json MUST survive a write.
Transactional tri-write
On success, a non-frozen install MUST write the project manifest, the lockfile, and the machine-local ownership record together. A failure anywhere MUST leave all three exactly as they were, and MUST restore every text asset and every native configuration document the operation touched, under the restoration rule in Ordering. Every successful non-frozen write produces lockfile0.4, including a migration from 0.2 or 0.3. Its server inventories MUST come from verified facet content, never from adapters, native configuration, or the ownership record, and a facet with no servers MUST receive an explicit empty inventory.
Removal
A removal-only operation MAY rewrite the lockfile without resolving the facets that remain, carrying their entries forward unverified, but only when local state answers the operation completely:- Every remaining facet has a
0.4entry matching its manifest source and specifier, and its recorded asset and server dispositions equal manifest intent with no collision. - The machine-local ownership record covers every remaining facet and agrees with its entry: versions, integrity, materialized assets, and every active server record by authored name, disposition, and fingerprint, in both directions. An omitted server needs no ownership record.
- No identity a remaining facet keeps was also claimed by another facet. For a text asset, any other recorded claimant counts, compared by namespace and portably folded name. For a server, recorded claims at that identity with different fingerprints count; identical fingerprints may be shared. Otherwise the bytes on disk may be another claimant’s, and only resolution can restore the kept content.
0.2 or 0.3 lockfile with any remaining facet always falls back, because no complete inventory exists to carry forward. It MUST NOT invent an inventory or write a legacy version. A failed fallback MUST commit nothing and MUST report both why resolution was needed and the underlying failure.
Removing every facet needs no inventory, so it MUST NOT fetch removed content to produce an empty 0.4 lockfile. In every case, deletion authority stays with the ownership record: a lockfile record never authorizes deleting a native entry.
Frozen lockfile
Frozen mode treats the lockfile as authoritative for what to reproduce. It is not authority to delete: that stays with the machine-local record. Only a reproduction can run frozen. An addition, removal, or update has no frozen form. Frozen mode MUST NOT prompt, for a collision or for approval, though it MAY use approval supplied in advance. These gates MUST run before any network access, so a frozen install can refuse without fetching anything:1
Coverage
Every manifest facet MUST have a satisfying lockfile entry, the lockfile MUST NOT pin anything the manifest dropped, and git and local sources MUST match their locked provenance.
2
Format capability
A lockfile version that cannot record a disposition the manifest declares MUST fail, rather than ignore the intent. Each kind has an exact set of capable versions, never a numeric threshold:
The reported required version names the capability that is missing, not the version a normal install writes, which is always
0.4.3
Plan over the locked set
The planner runs against the lockfile’s recorded text assets and, for
0.4, its recorded server names and fingerprints. Every manifest facet takes part, including one with an empty inventory. A collision or invalid alias in recorded state is reported before anything is downloaded, with servers identified by fingerprint because no declaration has been read.4
Stale intent
An override naming a text asset the locked version does not contain, or a server absent from a
0.4 entry’s inventory, is blocking drift. Frozen mode reports it without removing it.5
Intent against recorded disposition
For every locked text asset and every
0.4 server record, omitted ones included, what the manifest asks for MUST equal what the lockfile records. A missing override means authored, so dropping a recorded alias is drift rather than a request to keep it. Editing an alias without a normal install is drift, exactly like editing a version, even when the edit would cure a collision.0.4, its recorded server inventory, as defined in Verification.
MCP adds its own pre-mutation gates after content is acquired: an unresolved collision among declarations, an adapter that cannot configure servers, an unparseable native document, or an unapproved declaration MUST fail before any write. A locked fingerprint is never approval.
A 0.2 or 0.3 lockfile with no server override still reproduces. Its servers are taken from the verified facet content under their authored names, and no inventory is recorded.
Once every check passes, frozen mode MAY reconcile native configuration and the machine-local record, including removing an owned entry the project no longer desires. It MUST NOT write the project manifest or lockfile.
An otherwise successful frozen install MAY still succeed if its machine-local ownership record cannot be persisted. The implementation MUST report that failure and any incomplete restoration of the record, and MUST NOT treat unpersisted ownership or approval as recorded.
Version axes
The archivefacetVersion, the project manifest version, and the lockfile version are independent axes. Each is classified by exact match against a supported set, never by numeric ordering, so an unrecognized version is refused rather than guessed at.
An implementation that also supports adapters carries its own adapter SDK API axis on top of these.
An archive whose facetVersion is unsupported MUST fail with the observed and supported versions, so a consumer can be told what to upgrade.
Boundaries
- Text is never fetched or assembled at install time. Everything installed comes from the verified archive.
- Skill companion files materialize with their skill. Every other supplementary file ships in the archive and MUST NOT be written to disk.
- Materializing a declaration MUST NOT install, launch, probe, or authenticate to an MCP server, and MUST NOT store credentials.
- An installer MUST NOT modify user-wide or system-wide tool configuration.