Skip to main content
The lockfile (facets.lock) records resolved installation state: for every declared facet, the exact version, the verified integrity, the provenance it was resolved from, and the assets it contributed — each with a per-file integrity record for every materialized file. It is the resolution counterpart to the project manifest’s intent — the manifest records what the user asked for, the lockfile records what that resolved to. Both files are version-controlled. The lockfile is written only by the install pipeline, as part of the tri-write — never ahead of success, and never by hand. A hand-edited or merge-conflicted lockfile fails validation at load rather than surfacing as a failure deep inside an install.

Example

facets.lock

Fields

number
required
The lockfile schema version. The current schema is 0.2; the numeric 1 names the earlier legacy-alpha schema. Versions are dispatched by exact match, never by numeric ordering (0.2 is numerically less than 1, so ordering would be wrong): a loader recognizes exactly the versions it supports and fails on any other rather than guessing. A normal install MAY migrate a verified legacy 1 lockfile to 0.2; a frozen install never rewrites it, and a 0.2 archive requires a 0.2 lockfile in frozen mode. The authoritative version is the CURRENT_LOCKFILE_VERSION constant in @agent-facets/protocol.
Before the future stable lockfile v1 (which reuses the numeric 1), legacy-alpha-1 parsing is removed and replaced with delete-and-regenerate guidance for old-shape files.
map<name, entry>
required
One entry per resolved facet, keyed by facet name. The name lives only in the key — entries do not repeat it.

Entry fields

tagged union
required
Provenance, discriminated by kind, one variant per source kind so an illegal cross-kind combination is unrepresentable:
  • registry{ kind, registry }. The registry origin (base URL) the artifact was resolved from. Deliberately carries no version specifier: the entry’s version field is the resolved identity, so an unresolved spec (latest, 1.*) has no slot to leak into.
  • git{ kind, url, commit }. The repository URL plus the resolved commit SHA (lowercase hex, at least 8 characters; the pipeline writes a full git rev-parse HEAD). The commit is REQUIRED — it is the immutable identity that makes a git install reproducible. The symbolic ref (#main, a tag) is deliberately NOT recorded: a ref is what the user requested (a project-manifest concern, and mutable), whereas the lockfile records what was resolved.
  • local{ kind, path }. The resolved local path.
string
required
MUST be an exact M.N.P version — no ranges, no wildcards, no prerelease. Always written by the pipeline from resolution, never copied from a specifier.
string
required
The canonical fingerprint (sha256:<hex>) of the verified content. Derived from the freshly verified or built archive — never trusted from input.
array
required
The assets this facet contributed. Each entry is { scope, type, name, files } (scope: system | user | project; type: skill | agent | command). Names MUST pass asset-name validation — a crafted lockfile cannot smuggle path traversal into adapter I/O. Adapter-agnostic by design: the same asset set is applied to every selected adapter, and no per-adapter fields exist here.The files array records every materialized file inside the asset as a deterministically-sorted { path, integrity } record: a skill lists its SKILL.md plus each companion; an agent or command lists its single primary file. The integrity is the recomputed canonical per-entry hash of the verified file — never copied from a self-declared value. Archive-only supplementary files (like README.md) are not materialized and therefore never appear in any asset’s files; they stay protected by facet-level integrity. Install reconciles these per-file records against recomputed archive hashes before writing and fails with the exact mismatching path.

Role in the pipeline

  • Trust anchor. When the lockfile pins a version, the audited content MUST hash to the locked integrity — a mismatch is a hard failure, never a silent re-download. → Commit — Verify
  • Lockfile trust for resolution. Whether a satisfying entry short-circuits version resolution depends on how the facet was requested (addition vs reproduction). → Commit — Resolve
  • Drift-proof deletion. The entry’s assets array — with its per-file files records — is the OLD ownership set; the freshly extracted build manifest is the NEW set; the difference is deleted with no separate bookkeeping. Deletion supplies the validated owned-file set to the adapter, so a skill’s companions are removed with it while unowned files are preserved. → Drift removal
  • Frozen mode. With --frozen-lockfile, the lockfile is the complete, authoritative source of truth and is never written. → Frozen lockfile