Module lockfile

Module lockfile 

Source
Expand description

Lockfile management for reproducible installations across environments.

This module provides comprehensive lockfile functionality for AGPM, similar to Cargo’s Cargo.lock but designed specifically for managing Claude Code resources (agents, snippets, and commands) from Git repositories. The lockfile ensures that all team members and CI/CD systems install identical versions of dependencies.

§Overview

The lockfile (agpm.lock) is automatically generated from the manifest (agpm.toml) during installation and contains exact resolved versions of all dependencies. Unlike the manifest which specifies version constraints, the lockfile pins exact commit hashes and file checksums for reproducibility.

§Key Concepts

  • Version Resolution: Converts version constraints to exact commits
  • Dependency Pinning: Locks all transitive dependencies at specific versions
  • Reproducibility: Guarantees identical installations across environments
  • Integrity Verification: Uses SHA-256 checksums to detect file corruption
  • Atomic Operations: All lockfile updates are atomic to prevent corruption

§Lockfile Format Specification

The lockfile uses TOML format with the following structure:

# Auto-generated lockfile - DO NOT EDIT
version = 1

# Source repositories with resolved commits
[[sources]]
name = "community"                              # Source name from manifest
url = "https://github.com/example/repo.git"     # Repository URL
commit = "a1b2c3d4e5f6..."                      # Resolved commit hash (40 chars)
fetched_at = "2024-01-01T00:00:00Z"             # Last fetch timestamp (RFC 3339)

# Agent resources
[[agents]]
name = "example-agent"                          # Resource name
source = "community"                            # Source name (optional for local)
url = "https://github.com/example/repo.git"     # Source URL (optional for local)
path = "agents/example.md"                      # Path in source repository
version = "v1.0.0"                              # Requested version constraint
resolved_commit = "a1b2c3d4e5f6..."             # Resolved commit for this resource
checksum = "sha256:abcdef123456..."             # SHA-256 checksum of installed file
installed_at = "agents/example-agent.md"        # Installation path (relative to project)

# Snippet resources (same structure as agents)
[[snippets]]
name = "example-snippet"
source = "community"
path = "snippets/example.md"
version = "^1.0"
resolved_commit = "a1b2c3d4e5f6..."
checksum = "sha256:fedcba654321..."
installed_at = "snippets/example-snippet.md"

# Command resources (same structure as agents)
[[commands]]
name = "build-command"
source = "community"
path = "commands/build.md"
version = "v1.0.0"
resolved_commit = "a1b2c3d4e5f6..."
checksum = "sha256:123456abcdef..."
installed_at = ".claude/commands/build-command.md"

§Field Details

§Version Field

  • Type: Integer
  • Purpose: Lockfile format version for future compatibility
  • Current: 1

§Sources Array

  • name: Unique identifier for the source repository
  • url: Full Git repository URL (HTTP/HTTPS/SSH)
  • commit: 40-character SHA-1 commit hash at time of resolution
  • fetched_at: ISO 8601 timestamp of last successful fetch

§Resources Arrays (agents/snippets/commands)

  • name: Unique resource identifier within its type
  • source: Source name (omitted for local resources)
  • url: Repository URL (omitted for local resources)
  • path: Relative path within source repository or filesystem
  • version: Original version constraint from manifest (omitted for local)
  • resolved_commit: Exact commit containing this resource (omitted for local)
  • checksum: SHA-256 hash prefixed with “sha256:” for integrity verification
  • installed_at: Relative path where resource is installed in project

§Relationship to Manifest

The lockfile is generated from the manifest (agpm.toml) through dependency resolution:

# agpm.toml (manifest)
[sources]
community = "https://github.com/example/repo.git"

[agents]
example-agent = { source = "community", path = "agents/example.md", version = "^1.0" }
local-agent = { path = "../local/helper.md" }

During agpm install, this becomes:

# agpm.lock (lockfile)
version = 1

[[sources]]
name = "community"
url = "https://github.com/example/repo.git"
commit = "a1b2c3d4e5f6..."
fetched_at = "2024-01-01T00:00:00Z"

[[agents]]
name = "example-agent"
source = "community"
url = "https://github.com/example/repo.git"
path = "agents/example.md"
version = "^1.0"
resolved_commit = "a1b2c3d4e5f6..."
checksum = "sha256:abcdef..."
installed_at = "agents/example-agent.md"

[[agents]]
name = "local-agent"
path = "../local/helper.md"
checksum = "sha256:123abc..."
installed_at = "agents/local-agent.md"

§Version Resolution and Pinning

AGPM resolves version constraints to exact commits using Git tags and branches:

§Version Constraint Resolution

  1. Exact versions ("v1.2.3"): Match exact Git tag
  2. Semantic ranges ("^1.0", "~1.2"): Find latest compatible tag
  3. Branch names ("main", "develop"): Use latest commit on branch
  4. Commit hashes ("a1b2c3d"): Use exact commit (must be full 40-char hash)

§Resolution Process

  1. Fetch Repository: Clone or update source repository cache
  2. Enumerate Tags: List all Git tags matching semantic version pattern
  3. Apply Constraints: Filter tags that satisfy version constraint
  4. Select Latest: Choose highest version within constraint
  5. Resolve Commit: Map tag to commit hash
  6. Verify Resource: Ensure resource exists at that commit
  7. Calculate Checksum: Generate SHA-256 hash of resource content
  8. Record Entry: Add resolved information to lockfile

§Install vs Update Semantics

§Install Behavior

  • Uses existing lockfile if present (respects pinned versions)
  • Only resolves dependencies not in lockfile
  • Preserves existing pins even if newer versions available
  • Ensures reproducible installations

§Update Behavior

  • Ignores existing lockfile constraints
  • Re-resolves all dependencies against current manifest constraints
  • Updates to latest compatible versions within constraints
  • Regenerates entire lockfile
# Install exact versions from lockfile (if available)
agpm install

# Update to latest within manifest constraints
agpm update

# Update specific resource
agpm update example-agent

§Checksum Verification

AGPM uses SHA-256 checksums to ensure file integrity:

§Checksum Format

  • Algorithm: SHA-256
  • Encoding: Hexadecimal
  • Prefix: “sha256:”
  • Example: “sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3”

§Verification Process

  1. During Installation: Calculate checksum of installed file
  2. During Validation: Compare stored checksum with file content
  3. On Mismatch: Report corruption and suggest re-installation

§Best Practices

§Commit Lockfile to Version Control

The lockfile should always be committed to version control:

# Commit both manifest and lockfile together
git add agpm.toml agpm.lock
git commit -m "Add new agent dependency"

This ensures all team members get identical dependency versions.

§Don’t Edit Lockfile Manually

The lockfile is auto-generated and should not be edited manually:

  • Use agpm install to update lockfile from manifest changes
  • Use agpm update to update dependency versions
  • Delete lockfile and run agpm install to regenerate from scratch

§Lockfile Conflicts

During Git merges, lockfile conflicts may occur:

# Resolve by regenerating lockfile
rm agpm.lock
agpm install
git add agpm.lock
git commit -m "Resolve lockfile conflict"

§Migration and Upgrades

§Format Version Compatibility

AGPM checks lockfile format version and provides clear error messages:

Error: Lockfile version 2 is newer than supported version 1.
This lockfile was created by a newer version of agpm.
Please update agpm to the latest version to use this lockfile.

§Upgrading Lockfiles

Future format versions will include automatic migration:

# Future: Migrate lockfile to newer format
agpm install --migrate-lockfile

§Comparison with Cargo.lock

AGPM’s lockfile design is inspired by Cargo but adapted for Git-based resources:

FeatureCargo.lockagpm.lock
FormatTOMLTOML
VersioningSemanticGit tags/branches/commits
IntegrityChecksumsSHA-256 checksums
Sourcescrates.io + gitGit repositories only
ResourcesCratesAgents + Snippets
ResolutionDependency graphFlat dependency list

§Error Handling

The lockfile module provides detailed error messages with actionable suggestions:

  • Parse Errors: TOML syntax issues with fix suggestions
  • Version Errors: Incompatible format versions with upgrade instructions
  • IO Errors: File system issues with permission/space guidance
  • Corruption: Checksum mismatches with re-installation steps

§Cross-Platform Considerations

Lockfiles are fully cross-platform compatible:

  • Path Separators: Always use forward slashes in lockfile paths
  • Line Endings: Normalize to LF for consistent checksums
  • File Permissions: Not stored in lockfile (Git handles this)
  • Case Sensitivity: Preserve case from source repositories

§Performance Characteristics

  • Parsing: O(n) where n is number of locked resources
  • Checksum Calculation: O(m) where m is total file size
  • Lookups: O(n) linear search (suitable for typical dependency counts)
  • Atomic Writes: Single fsync per lockfile update

§Thread Safety

The LockFile struct is not thread-safe by itself, but the module provides atomic operations for concurrent access:

  • File Locking: Uses OS file locking during atomic writes
  • Process Safety: Multiple agpm instances coordinate via lockfile
  • Concurrent Reads: Safe to read lockfile from multiple threads

Re-exports§

pub use private_lock::PrivateLockFile;

Modules§

patch_display
Helper functions for displaying patch information with original and overridden values.
private_lock
Private lockfile management for user-level patches.

Structs§

LockFile
The main lockfile structure representing a complete agpm.lock file.
LockedResource
A locked resource (agent or snippet) with resolved version and integrity information.
LockedSource
A locked source repository with resolved commit information.

Enums§

StalenessReason
Reasons why a lockfile might be considered stale.

Functions§

find_lockfile
Find the lockfile in the current or parent directories.