Skip to content

Lock File Specification

Version
0.1 (Working Draft)
Date
2026-03-09
Editors
Daniel Meppiel (Microsoft)
Repository
https://github.com/microsoft/apm
Format
YAML 1.2

This is a Working Draft. The lock file format is stable at version "1" and breaking changes will be gated behind a lockfile_version bump.

apm.lock records the exact resolved state of every dependency in an APM project. It is the receipt of what was installed — commit SHAs, source URLs, and every file deployed into the workspace. Its role is analogous to package-lock.json (npm) or .terraform.lock.hcl (Terraform): given the same lock file, APM MUST reproduce the same file tree.


The key words “MUST”, “MUST NOT”, “SHOULD”, “SHOULD NOT”, and “MAY” in this document are to be interpreted as described in RFC 2119.

The lock file serves four goals:

  1. Reproducibility — the same lock file yields the same deployed files on every machine, every time.
  2. Provenance — every dependency is traceable to an exact source commit.
  3. Completenessdeployed_files lists every file APM placed in the project, enabling precise removal.
  4. Auditabilitygit log apm.lock provides a full history of dependency changes across the lifetime of the project.

apm.lock is created and updated at well-defined points:

EventEffect on apm.lock
apm install (first run)Created. All dependencies resolved, commits pinned, files recorded.
apm install (subsequent)Read. Locked commits reused. New dependencies appended.
apm install --updateRe-resolved. All refs re-resolved to latest matching commits.
apm deps updateRe-resolved. Refreshes versions for specified or all dependencies.
apm packEnriched. A pack: section is prepended to the bundled copy (see section 6).
apm uninstallUpdated. Removed dependency entries and their deployed_files references.

The lock file SHOULD be committed to version control. It MUST NOT be manually edited — APM is the sole writer.

A conforming lock file MUST be a YAML 1.2 document with the following top-level structure:

lockfile_version: "1"
generated_at: "2026-03-09T14:00:00Z"
apm_version: "0.7.7"
dependencies:
- repo_url: https://github.com/acme-corp/security-baseline
resolved_commit: a1b2c3d4e5f6789012345678901234567890abcd
resolved_ref: v2.1.0
version: "2.1.0"
depth: 1
package_type: apm_package
deployed_files:
- .github/instructions/security.instructions.md
- .github/agents/security-auditor.agent.md
- repo_url: https://github.com/acme-corp/common-prompts
resolved_commit: f6e5d4c3b2a1098765432109876543210fedcba9
resolved_ref: main
depth: 2
resolved_by: https://github.com/acme-corp/security-baseline
package_type: apm_package
deployed_files:
- .github/instructions/common-guidelines.instructions.md
FieldTypeRequiredDescription
lockfile_versionstringMUSTLock file format version. Currently "1".
generated_atstring (ISO 8601)MUSTUTC timestamp of when the lock file was last written.
apm_versionstringMUSTVersion of APM that generated this lock file.
dependenciesarrayMUSTOrdered list of resolved dependencies (see section 4.2).
mcp_serversarrayMAYList of MCP server identifiers registered by installed packages.

The dependencies list MUST be sorted by depth (ascending), then by repo_url (lexicographic). Each entry is a YAML mapping with the following fields:

FieldTypeRequiredDescription
repo_urlstringMUSTSource repository URL.
hoststringMAYGit host identifier (e.g., github.com). Omitted when inferrable from repo_url.
resolved_commitstringMUSTFull 40-character commit SHA that was checked out.
resolved_refstringMUSTGit ref (tag, branch, SHA) that resolved to resolved_commit.
versionstringMAYSemantic version of the package, if declared in its manifest.
virtual_pathstringMAYSub-path within the repository for virtual (monorepo) packages.
is_virtualbooleanMAYtrue if the package is a virtual sub-package. Omitted when false.
depthintegerMUSTDependency depth. 1 = direct dependency, 2+ = transitive.
resolved_bystringMAYrepo_url of the parent that introduced this transitive dependency. Present only when depth >= 2.
package_typestringMUSTPackage type: apm_package, plugin, virtual, or other registered types.
deployed_filesarray of stringsMUSTEvery file path APM deployed for this dependency, relative to project root.

Fields with empty or default values (empty strings, false booleans, empty lists) SHOULD be omitted from the serialized output to keep the file concise.

Each dependency is uniquely identified by its repo_url, or by the combination of repo_url and virtual_path for virtual packages. A conforming lock file MUST NOT contain duplicate entries for the same key.

All paths in deployed_files MUST use forward slashes (POSIX format), regardless of the host operating system. Paths are relative to the project root directory.

# Correct
deployed_files:
- .github/instructions/security.instructions.md
- .github/agents/code-review.agent.md
# Incorrect — backslashes are not permitted
deployed_files:
- .github\instructions\security.instructions.md

This convention ensures lock files are portable across operating systems and produce consistent diffs in version control.

When apm pack creates a bundle, it prepends a pack: section to the lock file copy included in the bundle. This section is informational and is not written back to the project’s apm.lock.

pack:
format: apm
target: vscode
packed_at: "2026-03-09T14:30:00Z"
lockfile_version: "1"
generated_at: "2026-03-09T14:00:00Z"
# ... rest of lock file
FieldTypeDescription
pack.formatstringBundle format: "apm" or "plugin".
pack.targetstringTarget environment: "vscode", "claude", or "all".
pack.packed_atstring (ISO 8601)UTC timestamp of when the bundle was created.

The original lock file is not mutated. The enriched copy exists only inside the packed archive.

The dependency resolver interacts with the lock file as follows:

  1. First install — resolve all refs to commits, write apm.lock.
  2. Subsequent installs — read apm.lock, reuse locked commits. Only newly added dependencies trigger resolution.
  3. Update (--update flag or apm deps update) — re-resolve all refs, overwrite the lock file with fresh commits.

When a locked commit is no longer reachable (force-pushed branch, deleted tag), APM MUST report an error and refuse to install until the lock file is updated.

The lock file reader supports one historical migration:

  • deployed_skills — renamed to deployed_files. If a lock file contains the legacy key, it is silently migrated on read. New lock files MUST use deployed_files.

Because apm.lock is committed to version control, standard Git operations provide a complete audit trail:

Terminal window
# Full history of dependency changes
git log --oneline apm.lock
# What changed in the last commit
git diff HEAD~1 -- apm.lock
# State of dependencies at a specific release
git show v4.2.1:apm.lock
# Who last modified the lock file
git log -1 --format='%an <%ae> %ai' -- apm.lock

In CI pipelines, apm audit --ci verifies the lock file is in sync with the manifest and that all deployed files are present.

lockfile_version: "1"
generated_at: "2026-03-09T14:00:00Z"
apm_version: "0.7.7"
dependencies:
- repo_url: https://github.com/acme-corp/security-baseline
resolved_commit: a1b2c3d4e5f6789012345678901234567890abcd
resolved_ref: v2.1.0
version: "2.1.0"
depth: 1
package_type: apm_package
deployed_files:
- .github/instructions/security.instructions.md
- .github/agents/security-auditor.agent.md
- .github/agents/threat-model.agent.md
- repo_url: https://github.com/acme-corp/common-prompts
resolved_commit: f6e5d4c3b2a1098765432109876543210fedcba9
resolved_ref: main
depth: 2
resolved_by: https://github.com/acme-corp/security-baseline
package_type: apm_package
deployed_files:
- .github/instructions/common-guidelines.instructions.md
- repo_url: https://github.com/example-org/monorepo-tools
host: github.com
resolved_commit: 0123456789abcdef0123456789abcdef01234567
resolved_ref: v1.0.0
version: "1.0.0"
virtual_path: packages/linter-config
is_virtual: true
depth: 1
package_type: virtual
deployed_files:
- .github/instructions/linter.instructions.md
mcp_servers:
- security-scanner

VersionDateChanges
0.12026-03-09Initial working draft.