Skip to main content
Materialization is the rule that turns what facets publish into what a tool reads: files on disk for text assets, and keyed entries inside tool-owned configuration for MCP server declarations. It runs between verification and the first write. See Composition.
Materialization decides names, never content. Every archive path, every integrity hash, and every field of a declaration is fixed by its publisher and unaffected by anything on this page.

Two identities

fixed by the publisher
The name declared in facet.json. It fixes a text asset’s canonical archive paths, and therefore every integrity value recorded for it. It is what the lockfile stores. Aliasing and omission never change it.
chosen by the project
The name the contribution is materialized under. It equals the authored name unless the project aliased it.
An aliased skill lives on disk under its effective name while its recorded paths stay authored:
Front matter follows the same split: the name written into a materialized asset is the effective name, and description stays as the publisher wrote it. MCP servers have the same two identities. The authored name keys the project’s override and the ownership record; the effective name is the key written into the tool’s document. The declaration body is name-independent, so renaming a server never changes what it launches or connects to.

Dispositions

A project resolves each authored contribution to exactly one outcome.
the default
Materialize under the publisher’s name. Expressed by recording nothing: the absence of an override is the authored disposition. An explicit authored override MUST be rejected, so one state has one spelling.
{ kind: 'aliased', as }
Materialize under a different effective name. as is required and MUST satisfy the single-segment asset-name grammar. An invalid alias MUST be rejected rather than normalized, because silently rewriting a chosen name would make the result unpredictable.
{ kind: 'omitted' }
Do not materialize this contribution or any file it owns. An omitted text asset is still resolved, verified, and recorded in the lockfile. It simply never reaches an adapter, and is never approved or owned.
Two narrower forms derive from these:
  • A project override admits only aliased and omitted, because authored is the absence of one.
  • A materialized disposition admits only authored and aliased, because an omitted contribution was never materialized.
An omitted text asset stays in the lockfile with its complete authored file records. Dropping it would make an omission indistinguishable from a facet that never published it. An omitted server leaves no lockfile trace, because the lockfile records no server intent at all.

Recording intent

Dispositions live in facets.json, keyed by contribution kind and then by authored name:
facets.json
Overrides are keyed by authored name because that is the only stable identifier. An alias is the thing being declared, so it cannot also be the key. Intent is durable. It survives a failed install, a re-add, a version update, and a change of source. It is discarded only when the facet is removed, or when the contribution it names disappears. One server disposition applies to every selected adapter. There is no per-adapter aliasing: a project decides once what a server is called.

Namespaces

Two contributions may share a name across namespaces, never within one.
  • Skills and commands share one namespace, because they materialize into a single flat surface in the tools facets target.
  • Agents occupy their own namespace.
So a skill deploy and a command deploy collide, while an agent deploy coexists with both. MCP servers are not a text asset type. They occupy a separate configuration identity space, keyed by effective server name at project scope, so a server deploy coexists with every text asset named deploy and can only collide with another server.

Collisions

Two text assets collide when their collision keys are equal:
Three properties matter:
  • It uses the effective name, so aliasing can both cause and cure a collision.
  • It folds text asset type into its namespace, giving the rule above.
  • It folds the name portably: Unicode NFC, then Unicode lowercasing. Lowercasing is not ASCII-only, so Ä and ä collide, but it is deliberately not full Unicode case folding, so ß and SS do not fold together. Two names differing only by case or normalization collide rather than silently overwriting each other on a case-insensitive volume.
A collision key is a logical identity and MUST NOT be handed to an adapter. The addressable identity is (scope, type, effective name), using the verbatim name: a skill deploy and a command deploy are two different files even though they may not legally coexist.

Server collisions

Servers collide by project scope and portable effective server name, in the same pass as text assets, with one rule that has no text-asset counterpart:
  • Identical declarations compose. When two facets claim one effective name with declarations whose canonical fingerprints are equal, they agree. One configuration is produced and both facets are retained as claimants.
  • Different declarations collide. Differing fingerprints describe materially different behavior at one key, so they form a collision group naming every claimant.
Two text assets at one name are always two different files, even when their content matches. A server key is a single entry that either says one thing or is contested.

Planning rules

Planning is a single pass, not a fixed-point resolver. Overrides are applied once against authored identity, then the resulting effective set is checked once. Text assets and servers share one planning primitive, so every rule below holds in both identity spaces.
  • Alias swaps are legal. If A aliases to B and B aliases to A, both land, because neither observes the other’s result.
  • Duplicate alias targets fail. Two contributions aliased to one name collide like any other pair.
  • A name freed by an omission is available.
  • Order does not matter. The result never depends on declaration order.
Determinism here is a contract: reordering facets, or the assets a facet declares, MUST NOT change any disposition, whether a collision is detected, or which effective set is materialized. No claimant can win a collision by being listed first. Collision reports MUST be stable: groups, and claimants within a group, come back in a fixed order, so the same conflict reads identically on every machine. That ordering MUST NOT be locale-sensitive. A name that every claimant aliases away from is freed, exactly like one an omission frees. If that name is owned, it is deleted in the same operation, before any alias is written. A file at that name which nothing owns is left alone: freeing a name says nothing about who wrote the file sitting on it.

Stale overrides

An override naming a contribution the resolved version no longer contains is stale, usually because a publisher renamed or dropped it. A stale override is reported rather than fatal. Because intent is durable, it survives a failed operation and is pruned only by a successful install, which reports what it dropped. Under a frozen install the same condition is blocking drift instead, and the override is not removed.

What aliasing does not change

Everything below is anchored to the authored name and is byte-identical whether or not a contribution is aliased:
  • Canonical archive paths, and therefore the per-entry hashes.
  • The facet’s canonical fingerprint.
  • The lockfile’s name and files records.
  • The text asset’s content and its description.
For a server, aliasing leaves the declaration body, its canonical fingerprint, and the facet integrity that pins it unchanged. Because approval is keyed by effective name and fingerprint, aliasing to a name already approved for that same declaration does not re-prompt, while aliasing to a new name does.
Because integrity is anchored to authored paths, an alias can never smuggle different content under a familiar name. Verification happens before materialization and never sees the effective name.