Assembly Lock, SkillBOM, and Replay¶
Turning an assembly into files on disk is a three-step, digest-gated
pipeline: resolve (pure), preview (builds a plan, zero writes), and
apply (writes files and durable provenance). This guide covers that
pipeline, the two provenance records it produces (skillmeat.lock and a
SkillBOM sidecar), and how to recover from a failed or stale apply.
The three steps¶
# 1. resolve — pure computation, no plan, zero writes
skillmeat assembly resolve managed:assembly/my-assembly --format json
# 2. preview — resolve + build a MaterializationPlan (still zero writes)
skillmeat assembly preview managed:assembly/my-assembly \
--project <project-id> --adapter-ref claude_skill --format json
# returns plan_digest + idempotency_key alongside the resolve output
# 3. apply — digest-gated: materializes the SAME plan just previewed
skillmeat assembly apply managed:assembly/my-assembly \
--project <project-id> --adapter-ref claude_skill -y
If you omit --plan-digest/--idempotency-key on apply, the CLI runs
preview internally first and applies exactly that result — you never need
a separate round trip just to get the digest. Pass both flags explicitly
only when you're scripting a two-step flow (e.g. showing a user a preview,
then applying only after they confirm) and want the guarantee that what gets
applied is the exact plan they saw, not a silent re-resolution.
apply never re-resolves silently: if the assembly (or anything it depends
on) changed since your preview call, the digest no longer matches and the
call is rejected rather than materializing something you didn't see.
skillmeat.lock¶
A successful apply writes (or updates) one entry in
<project-root>/skillmeat.lock, keyed by the assembly's qualified ref. This
is an exact lock of the last applied state, not a history log — applying
the same assembly again overwrites its own entry. History and audit trail
live in the MaterializationRecord and SkillBOM instead.
skillmeat.lock is a separate authority from collection.lock (artifact
source pinning) and .skillmeat-deployed.toml (legacy deployment tracking) —
neither of those files is touched by assembly apply, and assembly apply
doesn't touch them.
is the read-only accessor — there is no corresponding write endpoint; apply
is the sole writer.
SkillBOM provenance¶
Every successful apply also emits a SkillBOM v0 sidecar recording the
resolution/materialization/graph digests for that apply. The skillmeat.lock
entry and the SkillBOM sidecar are built from the same provenance
section, so the two always agree on those digests for a given apply — you
never have to reconcile two different records of what happened.
Deterministic replay¶
Resolution and plan-building are pure functions of their inputs: the same assembly, presets, rule facts, and module content always resolve to the same plan digest. That means:
- Re-running
previewwith identical inputs always returns the identicalplan_digest/idempotency_key. - Re-running
applywith the sameidempotency_keyagainst an already-applied record is a no-op — it detects the existing record and returns without writing anything a second time. - Retrying an interrupted
apply(see Recovery below) recomputes identical content and file writes are idempotent no-ops for any path already correct.
Recovery states¶
apply never returns a false success. Every failure path is one of these,
distinguishable by response shape:
| Situation | Response | What to do |
|---|---|---|
Definition changed since your preview |
409 materialization_stale_plan |
Re-run preview, review the new plan, apply again. |
| Resolution itself failed (conflicts, unresolved bindings) | 422 assembly_resolution_failed with diagnostics |
Fix the assembly/preset/rule issue the diagnostics describe; nothing was written. |
| A pre-write validation failed (e.g. an output path would escape the project directory) | 422 materialization_error with errors |
Fix the offending module's output_claims; nothing was written. |
| A write succeeded but durable provenance (lock/BOM/record) could not be committed | 200 with applied: false and a populated recovery object (stage, manifest_path, compensation, retryable: true) |
Retry the identical apply call (same plan_digest/idempotency_key/inputs) — it converges rather than duplicating writes. |
The third row is the one to understand operationally: past the point where files are actually written, a failure is never rolled back (the write is already correct) and never silently reported as success (provenance isn't done yet). The response tells you exactly which stage failed and gives you everything needed to retry the same call safely.
Before that point — anything that fails during file writes themselves — is fully reversible: SkillMeat restores every already-written output from its backup and raises a plain error; no partial state is left on disk.
Related guides¶
- Authoring — building the assembly you're resolving/previewing/applying.
- Presets & Rules — how binding provenance and
rule decisions end up in the resolve/preview/apply response, and in
skillmeat.lock. - Editions — where
MaterializationRecordand lock storage differ between local and enterprise.