# Design rationale: Loading & boot composition model

@status:doc/done

[p01] @fact:companion-line **Companion to:** [PROP-009](../modules/vibe-workspace/PROP-009-loading-model.xml) (the loading model — **shipped**, M1.18 phases 1–7, 2026-05-22). @status:doc/done

[p02] @fact:rename-note **Terminology (2026-07-16 rename — read this before the body).** This record captures the 2026-05-21 session and keeps that session's three names; the shipped grammar has two. Read `inline` as **`link = "static"`** (the verbatim `STATIC.md` lane), the design's `static` as **`link = "dynamic"`** (the default, a by-reference `INDEX.md` read), and the design's `dynamic` as a **`dynamic` entry carrying a `when`**. The default moved with the names: design-`static` was the default and its shipped counterpart `dynamic` is. See [PROP-009 §2.4](../modules/vibe-workspace/PROP-009-loading-model.xml#inclusion-types), which is normative. @status:doc/done

[p03] @fact:status-line **Status:** non-normative design record. Captured 2026-05-21 in an owner design session. @status:doc/done

[p04] @fact:authority-line **Authority:** the PROP is the contract. If this document and PROP-009 disagree, the PROP wins. @status:doc/done

## 1. What this document is

[p05] @fact:origin-question PROP-007 shipped the workspace data model (M1.17) but deliberately left one question
open — [PROP-007 §6 question 3](../modules/vibe-workspace/PROP-007-workspace.xml#open),
the *per-member materialisation target*: when a dependency is resolved for member M,
into which member's `spec/` does its content land? @status:doc/done

[p06] @fact:scope-of-answer This session answered it. The answer turned out to be far larger than picking a
directory: it is a redesign of vibevm's entire **loading model** — how a dependency's
content is materialised, how the boot sequence is composed across a workspace
hierarchy, and how an AI agent consumes it at session start. This document records
the *why* and the fork-by-fork reasoning; **PROP-009** is the contract, and it shipped. @status:doc/done

[p07] @fact:workspace-arc-continuity It belongs to the workspace arc and continues
[`workspace-and-qualified-naming.xml`](workspace-and-qualified-naming.xml). @status:doc/done

## 2. The problem the deferred question was hiding

[p08] @fact:narrow-question-illusion PROP-007 §6 q3 reads as a narrow placement question. It is not. @status:doc/done

[p09] @fact:flat-model-shape vibevm's boot model ([`VIBEVM-SPEC.md` §6](../../VIBEVM-SPEC.md)) is a **flat, single,
shared, mutable namespace** — `spec/boot/NN-*.md`, read in filename order, one
sequence, one entry point. It is correct for exactly one project shape: one project →
one boot sequence → one entry point. @status:doc/done

[p10] @fact:workspace-breaks-lead A workspace breaks every one of those assumptions at once: @status:doc/done

- [p11] @fact:break-n-nodes **N nodes** — the root plus every member. @status:doc/done
- @fact:break-n-entry-points **N entry points** — a developer `cd`s into any member and opens an agent there.
  This is PROP-007's load-bearing principle: "the user works in a sub-project and
  doesn't notice it is part of something bigger." @status:doc/done
- @fact:break-n-boot-sequences **N boot sequences** — each entry point needs a sequence coherent *for that node*. @status:doc/done
- @fact:break-shared-deps **One shared dependency set** — unified resolution (PROP-007 §2.4) means one version
  of each external dependency across the whole workspace. @status:doc/done

[p12] @fact:flat-model-verdict The flat model cannot be stretched over this. It must be replaced. @status:doc/done

[p13] @fact:OWNER-CONSTRAINT-NO-REWRITE The owner's hard constraint, stated at the outset: **installing a dependency must
never modify anyone's authored spec.** The owner's analogy is C++ — you do not rewrite
your `#include` directives into the literal text of the dependency's headers. Merging
a dependency's spec into the consuming spec is the broken option, and it is what a
naïve "bubble everything into the root `vibevm/vibespecs/boot/`" would amount to. @status:doc/done

## 3. The owner's mental model — boot as linking

[p14] @fact:linking-frame The owner framed the loading mechanism directly as **static vs dynamic linking**, and
that framing became the spine of the design. @status:doc/done

[p15]
| C++ / the linker | vibevm |
| --- | --- |
| @fact:ROW-LINK-COMPILE Compile + link time @status:doc/done | @fact:ROW-LINK-COMPILE-VIBEVM `vibe install` @status:doc/done |
| @fact:ROW-LINK-LOAD Load + run time @status:doc/done | @fact:ROW-LINK-LOAD-VIBEVM start of an AI session @status:doc/done |
| @fact:ROW-LINK-OBJECT Object file / library @status:doc/done | @fact:ROW-LINK-OBJECT-VIBEVM a package (flow / feat / stack / tool) @status:doc/done |
| @fact:ROW-LINK-EXECUTABLE The executable @status:doc/done | @fact:ROW-LINK-EXECUTABLE-VIBEVM a node's effective boot sequence @status:doc/done |
| @fact:ROW-LINK-LOADER The dynamic loader (`ld.so`) @status:doc/done | @fact:ROW-LINK-LOADER-VIBEVM the AI agent following INCLUDE pointers @status:doc/done |
| @fact:ROW-LINK-DT-NEEDED `DT_NEEDED` entry @status:doc/done | @fact:ROW-LINK-DT-NEEDED-VIBEVM an INCLUDE pointer (a `spec://` reference) @status:doc/done |
| @fact:ROW-LINK-STATIC Static linking (`.a` copied into the binary) @status:doc/done | @fact:ROW-LINK-STATIC-VIBEVM `vibe install` inlines a dependency's boot @status:doc/done |
| @fact:ROW-LINK-DYNAMIC Dynamic linking (`.so` referenced, resolved at load) @status:doc/done | @fact:ROW-LINK-DYNAMIC-VIBEVM the INCLUDE pointer stays; the agent resolves it @status:doc/done |
| @fact:ROW-LINK-VENDOR `vendor/` / `~/.cargo/registry` @status:doc/done | @fact:ROW-LINK-VENDOR-VIBEVM the materialised-dependency tree @status:doc/done |

[p16] @fact:AGENT-IS-THE-LOADER The load-bearing consequence: **at session start, the AI agent is the loader.** Every
reference the agent resolves itself costs tool calls, and tool calls are — the owner's
words — *безумно дорого*. Static linking moves resolution to `vibe install` time (done
once, by the machine); dynamic linking leaves it to the agent (every session, by the
LLM). Exactly the C++ tradeoff: a statically-linked binary loads with no help; a
dynamically-linked one needs the loader to find and map every `.so`. @status:doc/done

## 4. The model — four principles

[p17] @fact:P1-TWO-TREES **P1 — Two trees.** A node's authored `spec/` (only the node's author writes it) and
the materialised dependencies (a separate tree, only `vibe` writes it) are physically
separate and never intermixed. Installing a dependency never touches authored `spec/`.
This is "your code vs `vendor/`". Under unified resolution a dependency is materialised
**once** for the whole workspace. @status:doc/done

[p18] @fact:P2-COMPUTED-SEQUENCE **P2 — The boot sequence is computed, not assembled by hand.** Each node has an
*effective boot sequence* = inherited foundation (from ancestors, flowing down) + the
node's own authored boot + the boot of its transitive dependencies (flowing up) + user
overrides. `vibe` computes it from the unified resolution. This is the owner's
"matryoshka" — but computed directly per level from the resolution graph, not
physically copied leaf-to-root (copying drifts; computation does not). Every level is
self-contained: a session opened at any node gets a sequence coherent for that node's
subtree. The root's sequence is the union of everything; a small member's is small —
the hierarchy gives cost-scoping for free. @status:doc/done

[p19] @fact:P3-INDEX-PER-ENTRY-POINT **P3 — One generated index per entry point; the agent never walks the graph.**
`vibe install` generates, for each entry-point node, the boot artifacts (§6). The
agent reads them in a flat, predictable loop — reads parallelise, collapsing latency.
No recursion, no discovery, no cycle-detection on the agent's side: `vibe` did that
once. Boot stays **pure file-reading** — the `CLAUDE.md` / `AGENTS.md` / `GEMINI.md`
redirect points at generated files; it does *not* become "run `vibe`". This preserves
the zero-dependency cross-agent property that is the whole point of VIBEVM-SPEC §6.1. @status:doc/done

[p20] @fact:P4-THREE-INCLUSION-TYPES **P4 — Three inclusion types: `inline`, `static`, `dynamic`.** Declared per dependency
in the consumer's `vibe.toml`; default `static`. They are the points on the linker
spectrum (§6). *(As shipped after the 2026-07-16 rename: two types, `link = "static" | "dynamic"`,
default `dynamic`, with the third case expressed as a `dynamic` entry carrying a `when` — see the
rename note above.)* @status:doc/done

## 5. The fork-by-fork record

[p21] @fact:forks-lead Four forks were put to the owner. The options, the resolution, the reasoning. @status:doc/done

### Fork 1 — the form of static boot delivery

[p22] @fact:fork1-options Options offered: a single inlined aggregate (cheapest at boot, but duplication and
the lost-in-the-middle risk §6.4 already rejected); a resolved path index (clean, but
1 + N reads); a hybrid. @status:doc/done

[p23] @fact:FORK1-REFINED-HYBRID **Resolution — a refined hybrid.** Not one of the three: a model where `inline`,
`static`, and `dynamic` *all coexist* as per-dependency inclusion types (§6), plus a
dedicated generated `STATIC.md`. The owner's reasoning: `STATIC.md` is an *emergency
priority lane*. For the highest-importance content — top-level skills, critical
disciplines — the boot text is concatenated verbatim into one file read first, so its
priority is guaranteed by *position* and does not depend on the agent performing
resolution correctly. This is the honest answer to lost-in-the-middle (§6.5): you do
not fix attention degradation by being clever about file counts; you fix it by putting
the must-not-be-missed content physically first. @status:doc/done

### Fork 2 — where materialised dependencies live

[p24] @fact:FORK2-COMMITTED-TREE **Resolution — a committed dependency tree.** A fresh clone is bootable with no
`vibe install`; the dependencies are visible and diffable; it is consistent with the
spec-driven ethos — the spec corpus *is* the product. Plus: a `vibe` command to
regenerate a subtree of the materialised state on demand — for when dependencies are
believed stale or a previous index pass was wrong. @status:doc/done

### Fork 3 — uniform vs workspace-only

[p25] @fact:FORK3-UNIFORM **Resolution — uniform.** A single-package project is a degenerate (zero-member)
workspace; one loading model everywhere. Consistent with `Workspace::discover`, which
already degenerates cleanly to "just this one node". The cost — every existing
project's layout migrates — is acceptable: vibevm is pre-release, and M1.17's
no-legacy hard break already set the precedent. @status:doc/done

### Fork 4 — milestone scope

[p26] @fact:FORK4-UNIFIED-VIEWS **Resolution — boot + effective spec, unified.** The boot index and the `vibe build`
effective spec (VIBEVM-SPEC §4.6) are the same idea: a computed, layered, materialised
view of the workspace. PROP-009 specifies one *computed-view engine*; the boot index
("what to read at session start") and the effective spec ("the full merged corpus for
build") are two views it emits. @status:doc/done

## 6. The three inclusion types — the refined Fork-1 answer in detail

[p27] @fact:inclusion-types-lead Each dependency in a consumer's `vibe.toml` carries an inclusion type (working syntax
of this session: `link = "inline" | "static" | "dynamic"`); the default was `static`. At `vibe install`
time, for each entry-point node `vibe` generates: @status:doc/done

- [p28] @fact:GEN-STATIC-MD **`STATIC.md`** — the verbatim concatenation of every `static`-typed contribution in
  the node's effective boot, in priority order. Read first; one read; maximum attention
  weight. The emergency lane — used sparingly, for top-level skills and critical
  disciplines. Generated only when the node has inline contributions (shipped name:
  `static` contributions, carried by the `vibe:static` markers inside `STATIC.md`). @status:doc/done
- @fact:GEN-INDEX-MD **`INDEX.md`** — the ordered, resolved manifest of the rest of the boot sequence.
  `static` entries appear as resolved file paths the agent reads directly (a flat,
  parallelisable loop). `dynamic` entries appear as INCLUDE pointers the agent resolves
  at boot. @status:doc/done
- @fact:SESSION-START-ORDER Session-start order: `CLAUDE.md` → `STATIC.md` → `INDEX.md` and the files it names. @status:doc/done

[p29] @fact:cost-profile-lead Cost profile: @status:doc/done

[p30]
| Type | Reads at boot | Content on disk | Use |
| --- | --- | --- | --- |
| @fact:ROW-COST-INLINE `inline` (ships as `link = "static"`) @status:doc/done | @fact:ROW-COST-INLINE-READS-AT-BOOT ~1 (already in `STATIC.md`) @status:doc/done | @fact:ROW-COST-INLINE-CONTENT-ON-DISK duplicated (bounded — few items) @status:doc/done | @fact:ROW-COST-INLINE-USE critical disciplines, top-level skills @status:doc/done |
| @fact:ROW-COST-STATIC `static` (ships as `link = "dynamic"`) @status:doc/done | @fact:ROW-COST-STATIC-READS-AT-BOOT 1 + N (N parallelisable) @status:doc/done | @fact:ROW-COST-STATIC-CONTENT-ON-DISK lives once @status:doc/done | @fact:ROW-COST-STATIC-USE the default — ordinary dependencies @status:doc/done |
| @fact:ROW-COST-DYNAMIC `dynamic` @status:doc/done | @fact:ROW-COST-DYNAMIC-READS-AT-BOOT 1 + N + graph-walk @status:doc/done | @fact:ROW-COST-DYNAMIC-CONTENT-ON-DISK lives once @status:doc/done | @fact:ROW-COST-DYNAMIC-USE conditional / context-gated boot @status:doc/done |

[p31] @fact:dynamic-is-lazy-pull `dynamic` is, mechanically, the subskill `lazy-pull` delivery mode (PROP-003 §2.5) —
the loading model generalises subskill delivery rather than inventing a parallel axis. @status:doc/done

## 7. Consequences and findings

- [p32] @fact:FINDING-NUMBERING **Numbering.** The `NN-` prefix namespace (10–89, author-chosen) cannot survive a
  workspace and is already admitted provisional (§6.5). In the computed model `vibe`
  owns the order in the generated artifacts; a package author declares only a
  *category* (the existing range bands — foundation / flow / stack / user-override —
  become categories) and optionally a coarse early/late hint. Prefix collisions become
  impossible by construction. @status:doc/done
- @fact:FINDING-MIRROR-BREAKAGE **Mirror-layout breakage.** VIBEVM-SPEC §13.1's mirror layout — source path = target
  path — works today only because a dependency always lands at the same path in every
  project. Moving dependency content into a separate tree breaks that; a package's
  internal cross-references (a boot snippet pointing at its own protocol document) must
  become package-relative or `spec://` URIs, rewritten by `vibe` at materialisation. @status:doc/done
- @fact:FINDING-PUBLISH-REGEN **Published-copy regeneration.** A package published by `vibe workspace publish` is
  consumed standalone — its boot index must be regenerated for the published shape,
  where dependencies are registry-resolved and version-pinned rather than path-sourced.
  This is exactly PROP-007 §2.5's dual-form `{ path, version }`; publish staging gains
  an index-regeneration step. @status:doc/done
- @fact:FINDING-DOGFOOD **vibevm dogfoods itself.** The vibevm repository is itself a vibevm project;
  PROP-009 changes how *this* repository boots. `vibevm/vibespecs/boot/00-core.xml` and
  `vibevm/vibespecs/boot/90-user.xml` stay user-owned authored boot; the generated `STATIC.md` /
  `INDEX.md` join them. The migration is part of the milestone. @status:doc/done

## 8. What this supersedes and parks

- [p33] @fact:SUBSUMES-INSTALL-BUILD **Workspace-aware `vibe install` / `vibe build`** (PROP-007 §9.3, §6 q3) is no longer
  a separate deferred item — it is *subsumed*: it becomes the install/build half of
  PROP-009. @status:doc/done
- @fact:parks-version-workspace **`version = { workspace = true }`** (PROP-007 §6 q4) and the **publish-signalling
  polish** (`--archive` etc., PROP-007 §9.3) are parked behind PROP-009 — recorded, not
  dropped. @status:doc/done
- @fact:prop-008-unaffected **PROP-008** (qualified naming) is unaffected; it still follows PROP-005 (index). @status:doc/done

## 9. Session log

- [p34] @fact:session-log-2026-05-21 **2026-05-21.** Session restored from `CONTINUE.md` + `vibevm/vibespecs/WAL.xml`. The owner
  reopened PROP-007 §6 q3 (the materialisation target). The discussion established
  that the question is a loading-model redesign, not a directory choice; produced the
  linker-model spine (§3), the four principles (§4), and the four-fork resolution
  recorded in §5. PROP-009 and its implementation milestone (M1.18) deferred to the
  contract-writing step. Out of band, a standing test-environment misdiagnosis was
  corrected — `os error 740` on `cargo test -p vibe-install` is Windows UAC installer
  detection (the test binary's name contains "install"), not Windows Defender; see the
  WAL. @status:doc/done

## 10. Pointers

- [p35] @fact:ptr-prop-009 [PROP-009](../modules/vibe-workspace/PROP-009-loading-model.xml) — the contract; shipped M1.18. @status:doc/done
- @fact:ptr-prop-007 [PROP-007](../modules/vibe-workspace/PROP-007-workspace.xml) — the workspace data model; §6 q3 is the question this answers. @status:doc/done
- @fact:ptr-workspace-naming [`workspace-and-qualified-naming.xml`](workspace-and-qualified-naming.xml) — the preceding design session. @status:doc/done
- @fact:ptr-vibevm-spec [`VIBEVM-SPEC.md`](../../VIBEVM-SPEC.md) — §6 (boot directory model), §4.2 (layout), §4.6 (effective spec), §13.1 (mirror layout). @status:doc/done
- @fact:ptr-prop-003 [PROP-003 §2.5](../modules/vibe-resolver/PROP-003-dep-evolution.xml) — subskills and delivery modes. @status:doc/done

