Lock file — .agent/agent.lock.hcl#
Kernel-written, not operator-authored — mirrors .terraform.lock.hcl. Lives at the project-local .agent/ path in the XDG-adjacent layout; see ../architecture.md#xdg-layout.
lock_file_version = 1 // MUST — format version of this file itself, independent of
// any individual provider's version; lets a future kernel
// detect and migrate an old-format lock file the same way
// the state backend migrates session files
provider "anthropic" {
source = "github.com/agentco/provider-anthropic"
version = "1.2.4"
resolved_at = "2026-07-22T18:04:00Z" // MUST — when this entry was last resolved,
// for audit/debugging drift over time
checksums = {
"linux_amd64" = "sha256:1a2b3c..."
"linux_arm64" = "sha256:4d5e6f..."
"darwin_amd64" = "sha256:7a8b9c..."
"darwin_arm64" = "sha256:0d1e2f..."
}
}
Shape#
lock_file_versionMUST be present and MUST be checked by the kernel before reading the rest of the file, mirroring the same "refuse to open something newer than understood" posture../state-backend.mdapplies to session files.- Each
provider "<name>" { ... }block records the resolvedsource, the exact resolvedversion(not a constraint),resolved_at(an RFC 3339 timestamp), andchecksums. checksumsMUST include an entry for every(os, arch)platform pair the kernel actually installs a binary for, not just the invoking machine's own platform — a lock file is meant to be committed and shared across a team on mixed platforms, so a checksum missing for a teammate's platform would silently break reproducibility for them specifically.
The kernel checks lock_file_version in an isolated pass, before the rest of the file's schema is decoded at all — this ensures a lock file written by a future, newer kernel version is refused outright rather than partially misread, mirroring ../state-backend.md's own migration-safety posture. A version the kernel doesn't understand MUST be a hard error.
Native HCL { "key" = "value" } object-constructor syntax evaluates to an Object type, not necessarily a Map — decoding checksums accounts for both.
Loading the lock file logs only the file path, at DEBUG level — never a decoded checksum or source value.
Checksum verification#
- The kernel MUST verify a downloaded binary's checksum against the matching platform entry before executing it, on every install — not just the first time a version is resolved — consistent with treating the lock file as the actual source of truth for "what's allowed to run," not merely a cache hint.
Checksum verification computes the installed binary's SHA-256 digest and compares it against the recorded checksum for that platform (keyed "<os>_<arch>", e.g. "linux_amd64"). A platform with no recorded checksum, or a digest that doesn't match, MUST both be treated as verification failures.
Checksum comparison uses plain equality rather than a timing-safe comparison, since it verifies a published binary's hash against a known-good value, not a secret token — there is no timing side-channel to defend against: an attacker who can observe comparison timing learns nothing they couldn't already get by reading the (public) lock file or the (public) release artifact. This MUST NOT be changed to a constant-time comparison; doing so would defend against a threat that doesn't apply here.
Checksum verification logs only the binary path and platform, at DEBUG level.
dev_overrides and identity without a lock entry#
A binary resolved via settings-and-global.md#dev_overrides has no provider "<name>" { ... } entry in this file at all — dev_overrides exists precisely to bypass the registry/lock-file resolution path, so there is no source/version/checksums for the kernel to read identity from the way it would for a normally-resolved plugin. The kernel instead obtains that plugin build's identity directly from the process itself, via that category's own Describe RPC — a Describe(DescribeRequest) -> DescribeResponse { producer: common.v1.ProducerRef } call every one of the seven category protocols gains in this same protocol revision. The plugin reports its own {name, version, source, category, protocol_version} at connection time, rather than the kernel inferring it from a lock-file row that in this case doesn't exist. This is the canonical explanation for the general "how does the kernel know what it's actually running" question wherever a dev_overrides binary is in play; other specs needing to address plugin identity resolution without a lock entry should point here rather than re-deriving it.