The Pipeline

One artifact chain stands between a source file and a machine running it. Each form is defined precisely in Artifact Formats; this page is the story that joins them, and the one thing to hold on to is where the chain stops being portable.

source                     bytes, content-hashed

  pit.mcode.unit@3         one unit per source file      ─┐
  pit.executable.manifest@1  the logical program          ├─ PORTABLE
  pit.mcode.program@1      explicit semantic link plan    │
  ─────────────────────── the press ───────────────────────

  pit.mach.fragment@1      one unit, lowered             ─┐
  pit.mach.pool@1          N fragments, linked            ├─ TARGET-FINAL
  pit.target.realization@1 what starting follows          ┘

  pit.cart@2               a sealed store a machine boots
  pit.bundle@2             a snapshot a store ingests

Above the press, nothing knows what machine it is for. Below it, everything is for exactly one — one numeric representation, one byte order, one object header width, one text layout, one Mach ABI. The press is the border, and it is crossed deliberately: a desktop presses a console’s pools by being handed the console’s profile.

Every arrow is a pure derivation. The derivation key hashes the semantic inputs, the output is content-addressed, and the store’s catalog maps one to the other. Editing the compiler changes the compiler identity that every key folds in, so a stale cache hit has no key to arrive under.

The portable half

pit.mcode.unit@3 is what the compiler emits: one source file, lowered to register-machine instructions, as JSON. It carries the source hash, the compiler identity, the imports the programmer requested (as unresolved claims), the durable optimizer facts, the source spans, and stable function and site IDs. It carries no target fact at all — no layout, no opcode selection, no link grouping. Constants ride inline through every compiler pass and are interned into a literals[] pool on the way out, which is what lets N units’ identical texts collapse to one object later.

The stable IDs are the load-bearing part. A function is "main" or its dense index; a site is an opcode plus its ordinal within the function. Because those identities derive from the source rather than from any output position, they survive recompilation — which is what makes the origin map and profile data possible at all.

pit.executable.manifest@1 resolves a root program and its transitive module requests into the logical program: one row per package-file binding, one selected version per package, every resolved import edge, a deterministic initialization order, and the aggregate claims. It is still target-free — its content hash is the exact identity of the program, and one manifest can have many realizations.

The manifest is also the border table between names and hashes. Locators live here, because this is where humans and resolution meet. Below it, artifacts are named by content hash, and inside an artifact there are only dense indices and self-relative offsets.

pit.mcode.program@1 is the portable semantic link. Its required pit.mcode.link-plan@1 says both grouping and stripping flags explicitly: dev/module keeps one cacheable unit per group, while ship/program and boot/program form one group. A program link resolves only already-final exact stone-export edges, pools literals at the selected granularity, and applies name and per-channel log stripping. It does not run streamline again, inline across units, remove guards, or learn a target representation.

Pressing

Pressing is two target-final stages, after the semantic link has decided portable meaning: the lowering selects representation, and the Mach link decides placement.

The lowering takes one unit and a complete target profile and produces a pit.mach.fragment@1: final u32 instruction words with fusion applied, the exact bit pattern of every number, target-layout stone object bytes, and the two things a linker could not know — where the pool-global shape operands sit, and which mcode instruction produced each final word. A fragment is an internal handoff. It has no content hash, never leaves the process, and the linker is its only reader.

The link takes N fragments to one pit.mach.pool@1 — magic pmp1, ten sections. It lays out the sections, deduplicates stone objects by byte equality, interns finalized VALUES pool-wide, rewrites the recorded constant operands, inserts WIDE where a global index exceeds u16, and rebases branches and PC metadata. It also patches shape operands, lowers finalized same-program semantic references to direct indices, and writes rows for edges that stay cross-image. The linker never decodes an instruction: the fragment supplies every relocation site and the WIDE opcode.

A pool has one writer, in pit, and every target fact it writes it reads from the profile record it was handed — so the same emitter presses for this machine, for a console, or for the next Mach ABI. C reads pools and does not write them. C’s side is the lowering primitive the press drives, the validator that checks a pool at open, and the VM that runs it. The reader is the authority on correctness, and the gate is behavioral: every profile arm the build knows presses a fixture pool and boots it under that arm’s C.

A pool is mapped and read where it lies. Its sections are already the target’s layout, so there is no ingestion pass, no materialized constant tree, and no intern table — execute-in-place from ROM is the ordinary case rather than a special one.

Beside each pool the press writes pit.mach.origin@2, a canonical binary sidecar keyed by the pool’s content hash. It carries one compact mcode-PC integer per target-final PC plus the function’s mcode hash. At first symbolication the reader joins that column to the unit’s function, site, and span rows, yielding the same {mcode hash, function ID, site ID, source hash, span} answer without storing the expanded objects. That is what closes the loop: freeze an actor, read its PC, resolve through the map, and look at the mcode the compiler emitted for that source line. Legacy expanded pit.mach.origin@1 sidecars remain readable. Profile observations are recorded against the same mcode identities, which is why a profile outlives the pool it was gathered from.

Startable, then shipped

pit.target.realization@1 joins one manifest to one complete profile and one ordered set of pools, with the entry rows, the instance slots, the binding rows, and the start plan spelled out. It is explicit on purpose: starting is following rows, not working anything out. The binding rows are also the authority for what code can reach what — two pools sharing a mapping are merely near each other.

A realization’s module rows may carry pressed pools, portable units, or both. There is one execution lane either way: an actor runs a pool. A row carrying a portable unit is pressed on the way to running, which is exactly how a generation with no cart it can mount gets back on its feet.

pit.cart@2 is the sealed store a machine boots: a 256-byte fixed header compared before anything is parsed, one nota metadata value carrying the catalog and the section directory, pmp1 sections at aligned offsets mapped in place, and a 16-byte trailer for the appended-binary lane. Every section is a pool, so a cart is stamped for one profile and mounts on the generation that pressed it. pit.bundle@2 is the portable form: a signed store manifest plus content objects, sliced so a player takes realizations and assets while a development or debug slice adds sources, mcode, and origin maps.

Where the chain crosses a generation

The root cart is pools, so it is generation- and target-locked. The mcode snapshot is portable input, neutral about profile and ABI, but the engine which opens it is itself a pressed pool; no binary can cross an ABI move by booting the snapshot alone. Forge runs the predecessor’s Pit lowering for the next profile and lands the resulting cart beside the new binary. See Booting.

Where to read further