Pack format¶
A .klio-pack file is a single byte stream with the layout below.
All multi-byte integers are little-endian.
+-------------------------+
| magic "KPK\0" | 4 bytes
| version u32 | 4
| flags u32 | 4 (reserved)
| pack_hash [u8; 32] | 32 blake3 over everything that follows
| dir_len u32 | 4
| dir [u8; ...] | postcard-encoded SectionDirectory
| payloads [u8; ...] | concatenated section bodies
+-------------------------+
The pack_hash covers every byte after the hash itself, so a pack
is content-addressable: callers can cache parsed packs keyed by
hash. Tampering anywhere in the body fails the hash check on the
next read.
Section directory¶
Each SectionEntry is
pub const SectionEntry = struct {
name: []const u8,
offset: u64, // into the payload area
stored_len: u64,
uncompressed_len: u64,
compression: Compression, // None | Zstd | ZstdDict
};
Names are case-sensitive. Readers may encounter unknown names and must skip them silently — that is how forward-compatible additions work.
Well-known sections¶
| Name | Required | Contents |
|---|---|---|
manifest |
yes | PackManifest (library id/version, abi, deps, implicit pkgs). |
symbols |
yes | SymbolIndex (FQN → kind, signature, source loc). |
bindings |
no | BindingManifest (FQN → host_symbol, purity, arity). |
ast |
no | AstBundle — pre-parsed KotlinFiles per source file. |
sources |
no | SourceBundle — raw UTF-8 source bytes. |
tests |
no | Companion test pack(s), same format, embedded. |
debug |
no | Source bytes + line tables for go-to-definition. |
All section payloads are postcard-encoded against the schemas in
pack.schema and pinned to FORMAT_VERSION. Bump the version
when a schema changes incompatibly.
Compression¶
Each section opts into compression independently. Today the choices
are None and Zstd at default level 3. The header and directory
are never compressed so readers can enumerate sections without
paying for decompression.
Suggested defaults:
| Section | Compression |
|---|---|
manifest |
None |
bindings |
None |
symbols |
Zstd (heavy repetition in FQN prefixes) |
ast |
Zstd |
sources |
Zstd (essential — raw Kotlin text) |
debug |
Zstd |
Determinism¶
PackWriter.finish sorts every section by name and writes
deterministically, so the same input tree always produces a
byte-identical pack. CI can re-pack every shipped library and diff
against the committed bytes to catch accidental drift.
ABI versioning¶
PackManifest.abi_version declares the runtime ABI the pack was
built against. pack.SUPPORTED_ABI_VERSION is the highest
ABI this build of klio understands. The interpreter rejects any
pack whose abi_version is higher with PackError.AbiMismatch,
prompting the author to rebuild against a matching klio release.