Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

12. Packages

A package is a git repository containing Korrin source that another program can import. This section is the normative description of the manifest, the lockfile, how a bare import specifier resolves once packages exist, and the korrin pkg command that manages them (ADR 0031, ADR 0032).

Packages, in the sense this section describes, are pure Korrin source. A dependency written in Rust and compiled in — a native module — is a related but distinct kind of dependency, covered separately in §13.

12.1 The manifest: korrin.toml

A directory with a korrin.toml and a src/lib.kor is a package.

[package]
name = "requests"
version = "0.3.0"

[dependencies]
json = { git = "https://github.com/alice/korrin-json", tag = "v1.2.0" }
  • [package].name and [package].version are the package's own declared identity. They play no role in how a dependent resolves import — see §12.3.
  • [dependencies] is a table of local name → source. Each entry needs a git URL and exactly one of tag, branch, or rev. A package's own [dependencies] table must be empty — see §12.4.
  • The entry file is always src/lib.kor, regardless of [package].name.
  • An entry may also set native = true, marking it as a native module (§13) rather than .kor source. Everything in this section (name resolution, the lockfile, the collision rule) applies to a native dependency exactly as it does to a plain one; only what happens after fetching it differs.

12.2 The lockfile: korrin.lock

# @generated by `korrin pkg` — do not edit by hand.
version = 1

[[package]]
name = "json"
git = "https://github.com/alice/korrin-json"
rev = "a1b2c3d4e5f6..."
path = ".korrin/packages/json"

korrin.lock pins the exact commit resolved for every dependency, even one specified in korrin.toml by tag or branch. korrin pkg install writes it; korrin pkg update is the only command that moves an existing pin. An application commits korrin.lock; a package intended to be depended on does not.

Fetched packages are checked out locally at .korrin/packages/<name>/, next to the korrin.toml that declares them.

12.3 Resolution: one merged namespace

import_statement = "import" , STRING , [ "as" , NAME ] ;

Extends §11.1's resolution rule with a third outcome for a bare (non-./) specifier:

  • ./… or ../… — a file, as §11.1 describes. Unchanged.
  • anything else — checked against the built-in module table (§11.4, §11.5) first, then against the current package's installed dependencies. No new syntax distinguishes the two — import "math" and import "requests" are written identically. A name cannot appear in both tables: korrin pkg add/install refuses to add a dependency whose local name collides with a built-in module's name (ADR 0032). A name in neither table is E0314.
import "not_a_real_package"
# error: E0314

A package's own bare imports resolve against that package's installed dependencies (from its own korrin.toml/korrin.lock), not the top-level program's — but since packages are leaf-only (§12.4), a package's own [dependencies] table is always empty, so in practice a package's bare imports can only ever reach built-in modules. A package's relative (./) imports resolve against its own directory, exactly like any other file's.

12.4 Leaf-only packages

A package's own korrin.toml must declare an empty (or absent) [dependencies] table. korrin pkg add/install rejects a package that declares one:

korrin pkg: "json" (https://github.com/alice/korrin-json) declares
dependencies of its own — packages with dependencies are not supported
in Milestone 5

A package may depend on nothing. Depending on another package is not yet possible for a package itself, only for a top-level program.

12.5 The korrin pkg command

CommandEffect
korrin pkg add <git-url> [--tag T | --branch B | --rev R] [--name NAME] [--native]Adds a dependency to korrin.toml and resolves it into korrin.lock. NAME defaults to the repository's basename. --native marks it a native module — see §13.
korrin pkg remove <name>Removes a dependency and re-resolves korrin.lock.
korrin pkg installFetches everything korrin.toml declares that isn't already checked out at its pinned commit; writes or refreshes korrin.lock.
korrin pkg update [name]Re-resolves a tag- or branch-pinned dependency to its current tip commit. Updates every dependency if name is omitted.
korrin pkg listPrints each resolved dependency: name, git URL, pinned commit, local path.
korrin pkg buildRegenerates and compiles this project's native-module runner — see §13.4.

add/install/remove/update run korrin pkg build automatically whenever they change the set of native dependencies; see §13.4 for exactly when.

korrin pkg operations that fail (an unreachable git URL, a malformed manifest, a rejected leaf-only or name-collision dependency) print a message to standard error and exit non-zero. They are not Korrin diagnostics — there is no source span to point at, since nothing runs a Korrin program during korrin pkg add/install/update.

12.6 Errors

An installed-package import that cannot be resolved — no such name in the lockfile, the checkout is missing on disk, or the package's src/lib.kor fails to compile — is E0314, the same code a bad ./ or built-in specifier already raises: all three are the same category of problem ("this import could not be resolved, read, or compiled"), not three different ones. A cycle that crosses from a program into a package and back is E0315, exactly as for files (§11.6).