Lockfile
How apm.lock.yaml pins resolved plugin versions for reproducible applies.
Successful durable ht apply or ht install writes apm.lock.yaml at the repo root. Check it in. It records the resolved plugin name → version set (plus integrity hashes) so re-applies reuse the same resolution until you ask otherwise. The manifest is repo-root apm.yml (ht config init).
ht apply my-setup # reuse lock when consistent with the manifest
ht apply my-setup --update # ignore apm.lock.yaml and re-resolveht status --check reports lock drift (manifest and lock disagree) alongside ordinary project drift.
Manifest vs lockfile
The project manifest is repo-root apm.yml (ht config init). Standard OpenAPM keys (name, version, targets, dependencies) parse. HarnessTap-only fields are first-class top-level keys: default_profile, environments, profiles, plugins.
environments is a mapping (same idea as profiles / plugins). environments.default names the active environment; other keys are named how-value bundles (values and optional secret_refs — refs only). There is no sibling singular environment / default_environment key.
name: demo
version: "1.0.0"
targets: [cursor, claude]
environments:
default: shared
shared:
values:
REGION: usWhat the lockfile records
lockfile_version: "1" (APM lock shape) plus HarnessTap replay metadata at the root: root, resource_map_hash, environment (the bound environment name, a string — not the apm.yml environments mapping), and plugins. Each plugin entry has name, version, source (local / marketplace / git / catalog), integrity, depth, and path.
Every walked git package (root or transitive) records clone identity (repo_url, resolved_commit, the declared ref or constraint, path when set, and declared_license). Apply without --update replays the locked SHA. See Apply git dependencies.
When the executable trust gate is on, the lock may record exec_status per dependency (deployed, gated_pending_approval, denied, or absent). See Executable trust.
Inspect a locked decision:
ht plugin why base
ht plugin why skill:deploy
ht apply my-setup --explain--explain prints the resolution trail. plugin why answers the same questions against the lockfile (or --root when you want a fresh resolve).
Fresh clone
After git clone, teammates who already ran ht init restore with ht install (the same loop as ht apply with no selector). The lockfile pins versions; harness files in the repo are already on disk from the previous apply.
Export the recorded inventory with ht lock export (CycloneDX / SPDX from the lockfile; not an attestation).