Reference
Packages and distribution
Two machines that feed the same source into the same compiler version produce the same bytes and the same certificates. A consumer recomputes every hash and re-runs every certificate locally, so a package is trusted because it checks out, not because of who published it.
Content addressing
Every content-addressed identity in edda is a BLAKE3 hash, and no other hash function is used anywhere in the language. Inputs are canonicalized before hashing: map order, field order, whitespace, line endings, and integer endianness are fixed by the schema rather than left to the producer. Every hash call routes through one function, so checking that builds are deterministic comes down to auditing that function.
The .rune pack
A package version ships as one .rune, a reproducible tar.zst holding a canonical manifest, the public surface of each module, verified MIR, pre-compiled objects per target, the structure map, the hashes, and an ed25519 signature. Source, tests, and docs are left out. Nothing in a pack runs at install time.
Three hashes, three questions
The pack carries three hashes computed from separate inputs, so a real patch changes exactly one of them and a release that claims to be a patch but changes another is caught.
| Hash | Over | Answers |
|---|---|---|
rune_hash | the archive bytes | are the bytes identical? |
surface_hash | the public, stable surface | did the API change? |
effect_hash | effects reachable from public items | did the capability surface grow? |
edda update enforces semantic versioning from these: a change to rune_hash alone is a patch; an addition to the surface or effects is a minor; a removal, a signature change, or a relaxed bound requires a major. A version claiming less than the hashes show is rejected.
Pins and the lockfile
A dependency pins its version, its surface_hash, a max_effects ceiling, and whether it accepts unstable items. The ceiling is checked at update time: the effects reachable through the functions you call must stay within it, or the update is rejected. The publisher key is pinned on first add, and a later key change is rejected until you accept it, so a maintainer handoff shows up as a diff in version control.
[[dependencies]]
name = "regex"
version = "^1.2"
surface_hash = "blake3:204bd8aa..."
max_effects = ["err: alloc.AllocError"]
accept_unstable = falseThe lockfile is generated, and a hash trailer makes a hand-edit fail the next build. Transitive dependencies are each pinned to their own hashes, flat, so trust never collapses through an intermediate package.
The Mímir registry
Mímir is where packages are found, fetched, and verified. It is named for the Norse well of knowledge. A lockfile that pins a rune_hash refuses any other bytes regardless of which registry serves them, so a private mirror is interchangeable with the public one, and a compromised registry cannot substitute a package. The trust chain has four steps, the key fingerprint, the signature over the hashes, the per-file hashes, and the archive hash, and a mismatch at any step rejects the package with no fallback.
The package commands
edda add resolves, fetches, verifies the chain, and pins. edda update, edda audit, edda publish, edda contract-diff, and edda why complete the set. audit runs entirely against cached bytes.
What the design buys
Not unbreakability, but a default where the common failures are caught: no install-time code, no silent growth in the capability surface, the lockfile overriding a bad registry, and per-dependency key pinning against typosquatting.