Format identifier:
https://getgat.dev/spec/lock-v1.Conformance language
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY in this document are normative when written in uppercase. This specification separates the from its . Readers MAY accept the compatibility forms listed in Line endings and canonical output. Writers SHOULD emit the canonical form.Semantic model
A lock-v1 document represents a finite map:- A path MUST occur at most once in the logical lock.
- Two or more paths MAY reference the same content ID.
- Directories are not entries. A tracked directory is represented by the file entries beneath that path prefix.
- Entry order is not semantically significant.
- Flat and sharded representations of the same path-to-OID map are semantically equivalent.
An entry has exactly two fields:
path and oid. File size, timestamps, permissions,
and storage locations are not part of lock-v1.Canonical flat format
The default representation is a UTF-8 file namedgat.lock at the repository root.
Example, with illustrative digest values:
gat.lock is not a lock-v1 document.
Grammar
Canonical record grammar:quoted-path uses the encoding and decoded-path constraints in Paths.
and
denote single characters.
Version line
The first line MUST be exactly:Entry rows
Every non-empty entry row has exactly two fields separated by one horizontal TAB (U+0009):
- has no TAB-separated OID field,
- has more than two fields,
- has an invalid path,
- has an invalid OID, or
- duplicates a path already present in the logical lock.
Line endings and canonical output
Canonical lock-v1 output:- is UTF-8,
- uses LF (
U+000A) line endings, - terminates the version line and every entry row with LF,
- contains no blank lines, and
- sorts entry rows by
pathin ascending lexical order.
Paths
Thepath field encodes the canonical repository-relative path of the tracked file.
Every path MUST be encoded as a canonical JSON string following
RFC 8785 §3.2.2.2,
including the enclosing double quotes ("):
- U+0008, U+0009, U+000A, U+000C, and U+000D MUST use
\b,\t,\n,\f, and\r, respectively. - All other U+0000–U+001F controls MUST use
\u00hhwith lowercase hexadecimal digits. - Double quote and backslash MUST use
\"and\\, respectively. - All other Unicode scalar values MUST be written literally as UTF-8, including
/, U+007F, U+2028, and U+2029, without Unicode normalization.
/, unescaped quotes, raw U+0000–U+001F
controls, and unquoted paths. Invalid Unicode, including lone surrogates, MUST
be rejected. The decoded path MUST also satisfy the path rules below; in
particular, backslash remains invalid in a decoded canonical path.
For example, "data/fi\tle.bin" encodes a path with an actual TAB inside its filename;
"data/fi\nle.bin" encodes a path with an actual LF. Each remains one physical row.
The following rules apply to the decoded path.
A valid lock-v1 path MUST:
- be valid UTF-8,
- be non-empty,
- be relative to the repository root,
- use
/as its separator, - contain no empty path segments,
- contain no
.path segments, - contain no
..path segments, - not begin with
./, - not begin with
/, - not end with
/, - contain no backslash (
\).
C:foo.
Format validity is independent of filesystem support. For example,
C:foo and
dir/a:b.txt are valid lock paths even on systems that prohibit these filenames.
ASCII controls are valid decoded path characters and MUST be escaped in the quoted field.
The stored UTF-8 path is the logical map key. No
or applies.
Content IDs
The second field is a BLAKE3 content identifier:<digest> MUST be exactly 64 lowercase hexadecimal characters (0-9, a-f),
representing the 32-byte BLAKE3 digest of the file’s raw content bytes.
The blake3: algorithm prefix is mandatory in the lock document.
For the semantic map, the content ID is the digest value. The prefix is part of the
serialized field, not a separate lock property.
The digest:
- is content-addressed,
- does not include the file path,
- does not include the file size,
- does not include timestamps or filesystem metadata, and
- may therefore be shared by multiple paths containing identical bytes.
Canonical ordering
For a flatgat.lock, writers MUST sort rows by decoded path UTF-8 bytes.
Quotes and escape sequences do not participate in ordering.
Ordering does not change lock semantics. Consumers SHOULD treat the document as
a map keyed by path; row position has no semantic meaning.
For a sharded lock, rows MUST be sorted by path within each shard. The order in which
shard files are traversed has no semantic meaning.
Sharded representation
A sharded representation stores the lock-v1 map in agat.lock/ directory.
changes only the container layout. Every shard file is independently a
lock-v1 document and MUST use the same version line and two-column TSV row format
defined above.
Flat and sharded representations use the same format identifier.
Shard assignment
For a canonical sharded lock at depthN, where N >= 1:
- Encode the decoded canonical
pathas its exact UTF-8 byte sequence, without quotes or escaping. - Compute
BLAKE3(path_bytes). - Take the first
Ndigest bytes. - Encode each selected byte as exactly two lowercase hexadecimal characters.
- Use the first
N - 1values as nested directories. - Use the final value as the shard filename with a
.tsvsuffix.
12 34,
that path belongs to:
N = 2.
The shard hash is a hash of the path, not the file content OID.
Because BLAKE3 digests are 32 bytes, this mapping is defined for depths up to 32.
Implementations MAY expose a smaller configurable maximum.
Shard invariants
A canonical sharded lock MUST satisfy all of the following:- every shard is a valid lock-v1 document,
- all entry paths remain globally unique across all shards,
- each entry is placed in the shard determined by the algorithm above,
- every shard uses the same shard depth for a given lock tree,
- shard directory/file names use lowercase two-digit hexadecimal components,
- rows within each shard are sorted by path, and
- empty/stale shard files SHOULD NOT be emitted.
Shape detection
Consumers MUST determine whether a revision contains:- a flat
gat.lockfile, or - a sharded
gat.lock/tree
Semantic equivalence
Two lock-v1 representations are semantically equivalent when they define the same path-to-OID map, even if:- their rows appear in a different order,
- one is flat and the other is sharded, or
- they use a different valid shard depth.
Three-way merge
A semantic three-way merge operates independently for each path in the union of the maps. Let the value for a path be its OID, orNone when the path is absent.
For each path:
Invalid examples
- Extra field
- Uppercase OID
- Non-canonical path
- Duplicate path

