What is a Pack?¶
A pack is a single-file binary archive that bundles a Kotlin library — manifest, parsed AST, symbol index, optional native binding manifest — into a format the klio interpreter can install without re-running the parser or typechecker.
+---------------------------+
| KPK\0 magic + version | header (verified + hashed)
|--------|------------------|
| manifest PackManifest | always present
| symbols SymbolIndex | for imports / tooling
| bindings BindingManifest | native intrinsics
| ast AstBundle | frozen front-end output
| sources SourceBundle | raw .kt fallback
| debug … | optional source bytes for IDE
+---------------------------+
Why a pack instead of a zip / jar?¶
- Deterministic. Sections are sorted by name and
blake3-hashed so the same source tree always produces the same bytes. - Section-addressable. Readers walk a small directory and decode
only the sections they care about. The LSP can load just
symbolsanddebug; the interpreter addsast+bindings. - Schema-driven. Each section is
postcard-encoded against a schema inpack.schema. - Compressible. Sections can be uncompressed or zstd-compressed individually.
Kinds of packs¶
| Kind | Example | Loaded by |
|---|---|---|
| Embedded stdlib | stdlib.klio-pack |
Built into the klio binary; always active. |
| Bundled libs | kotlinx.io.klio-pack |
Built from kotlin-klio/; klio pack install. |
| Feature-gated | io.ktor.klio-pack |
Same flow; gated surfaces load per run via --feature. |
| Third-party | Anything you build | klio pack install <file>. |
The same format, the same loader, the same dispatch path — only the content and the install flow differ.
What goes in a pack¶
- Kotlin source. Everything under the library's
source_rootsis parsed at pack-build time. The resulting AST goes into theastsection. Bytes go intosourcesas a fallback. - Binding manifest.
klio.toml's[bindings]table is serialised into thebindingssection so the loader can resolve each FQN against a host'sHostBindingsregistry. - Manifest. Library id, version, ABI version, dependencies,
implicit packages, and any feature definitions (named source
subsets a consumer opts into with
--feature <id>/<name>; see Using packs).
What does not go in a pack¶
- The Zig module that provides the native bindings — function
pointers can't travel through the wire format. Hosts register them
once at startup; the pack only carries the
host_symbolname to join against. - Build artefacts (
target/), test fixtures, CI configs, anything outside the declaredsource_roots.
Loader behaviour¶
When klio starts:
- The embedded stdlib pack is decoded and installed.
- Every file matching
~/.klio/packs/*.klio-packand$KLIO_PACKSis enumerated. - Packs are topologically sorted by
[[deps]]and installed in order. - For each pack:
manifest.abi_versionis checked againstpack.SUPPORTED_ABI_VERSION.implicit_packagesand packages in the symbol index are registered as known (so imports resolve).- Bindings whose
host_symbolresolves in the host registry are collected and handed to the Vm viasetInstalledBindings. - The pack's parsed AST is merged into the IR module alongside the user's files, so its declarations are lowered and available to the program.