<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">PROP-023 — Bridge packages</title>
  <status stage="impl" state="done" comment="C 2026-09-11: three source forms ship; owner corrected identity/storage law so third-party products default to their product coordinate and an independent source repository outside VibeVM"/>
  <p p="1"><fact id="status-line" status="impl/done">**Status: IMPLEMENTED** (specified 2026-06-24 in an owner-requested design
session; verified against the tree 2026-07-25 by the spec-actualization
campaign). The umbrella's own addition — `[package].bridge`, defaulting to
false — parses in `vibe-core` with a doctest, and the mechanisms it
composes all ship: [PROP-020](../vibe-workspace/PROP-020-install-hooks.xml)
install hooks, [PROP-021](PROP-021-submodule-sources.xml) submodule sources,
[PROP-022](../vibe-workspace/PROP-022-materialization-modes.xml) materialization
modes, plus [PROP-021 §2.2](PROP-021-submodule-sources.xml#source-abstraction)
dependency-declared embedded sources — so every bridge class recorded here has
live machinery. The umbrella adds a flag and packaging/provenance conventions;
each underlying mechanism remains independently usable.</fact></p>
  <p p="2"><fact id="related" status="spec/done">**Related:** [PROP-002](PROP-002-decentralized-registry.xml) (a bridge is an
ordinary package + identity), [PROP-008](PROP-008-qualified-naming.xml) (the
consumer-facing qualified product coordinate),
[PROP-015 §2.6](../vibe-mcp/PROP-015-mcp-integration.xml#skill) +
[PROP-015 #skill-include](../vibe-mcp/PROP-015-mcp-integration.xml#skill-include)
(projecting a skill out of the bridged subtree, selectively),
[PROP-000 §16](../../common/PROP-000.xml) (the installable kinds a bridge
still belongs to).</fact></p>
  <section id="motivation" title="1. Motivation">
    <section id="problem" title="1.1 The problem — good work that nobody packaged">
      <list ordered="false" p="3">
        <item><fact id="unpackaged-work" status="spec/done">People publish skills and projects to GitHub / GitVerse without ever making a
  vibevm package — out of disinterest, or because their repo's layout has nothing
  to do with vibevm conventions.</fact></item>
        <item><fact id="unreachable" status="spec/done">That work is then unreachable through
  `vibe install`, and the original author has no incentive to change.</fact></item>
      </list>
      <list ordered="false" p="4">
        <item><fact id="BRIDGE-DEF" status="impl/done" action="continue" actionstage="doc" audience="user,author">A **bridge package** closes the gap without the author's involvement: a
  *maintainer* volunteers to steward someone else's repository and publishes an
  ordinary vibevm package that **wraps** it.</fact></item>
        <item><fact id="BRIDGE-MEANS" status="impl/done">The bridge makes the foreign repo
  consumable by vendoring it, carrying a git-native submodule, or declaring an
  immutable external embedded source. The reference-backed form keeps upstream
  bytes out of the bridge repository and fetches them directly from the author.</fact></item>
      </list>
    </section>
    <section id="what" title="1.2 What this is — a thin convention over three mechanisms">
      <p p="5"><fact id="thin-convention" status="impl/done">A bridge is not a new kind of package or a new subsystem. It is:</fact></p>
      <list ordered="false" p="6">
        <item><fact id="conv-ordinary-package" status="impl/done">an ordinary package (still one of `flow` / `feat` / `stack` / `tool`),</fact></item>
        <item><fact id="conv-embedded-content" status="impl/done">carrying the foreign repo as **vendored** content, a git-native **submodule**,
  or a manifest-declared immutable **external embedded source**
  ([PROP-021](PROP-021-submodule-sources.xml)),</fact></item>
        <item><fact id="conv-hooks" status="impl/done">optionally **prepared** by install hooks ([PROP-020](../vibe-workspace/PROP-020-install-hooks.xml)),</fact></item>
        <item><fact id="conv-in-place" status="impl/done">optionally **materialised** as `in-place` when the upstream is a giant
  ([PROP-022](../vibe-workspace/PROP-022-materialization-modes.xml)),</fact></item>
        <item><fact id="conv-skill-projection" status="impl/done">with any skill projected selectively from the bridged subtree
  ([PROP-015 #skill-include](../vibe-mcp/PROP-015-mcp-integration.xml#skill-include)).</fact></item>
      </list>
      <p p="7"><fact id="plus-flag" status="impl/done">…plus one flag that says "this is a bridge."</fact></p>
    </section>
  </section>
  <section id="decisions" title="2. Decisions">
    <section id="flag" title="2.1 A bridge is marked by a flag, not a kind">
      <p p="8"><fact id="req-flag" status="impl/done">`req r1`</fact></p>
      <list ordered="false" p="9">
        <item><fact id="BRIDGE-FLAG" status="impl/done" action="continue" actionstage="doc" audience="author">`[package].bridge = true` marks a package as a bridge.</fact></item>
        <item><fact id="FLAG-NOT-KIND" status="impl/done">It does **not** change
  the package's `kind` (a bridged skill is still a `feat`/`tool` as appropriate)
  or its identity.</fact></item>
        <item><fact id="FLAG-JOBS" status="impl/done">The flag is metadata with two jobs: it documents that the
  package's substantive content is *foreign* (stewarded, not authored, by the
  maintainer), and it is the hook the registry/UI uses to surface provenance
  (§2.4).</fact></item>
        <item><fact id="FLAG-DEFAULT" status="impl/done">Default `false`; the overwhelming majority of packages are not bridges.</fact></item>
      </list>
    </section>
    <section id="classes" title="2.2 Three classes — vendored, submodule-backed, and reference-backed">
      <p p="10"><fact id="req-classes" status="impl/done">`req r1`</fact></p>
      <p p="11"><fact id="TWO-CLASSES" status="impl/done">A bridge obtains the upstream repo in one of three ways:</fact></p>
      <list ordered="false" p="12">
        <item><fact id="CLASS-VENDORED" status="impl/done" action="continue" actionstage="doc" audience="author">**Vendored ("git in git")** — the maintainer copied the upstream tree into
  the package and committed it. This needs **none** of PROP-021/022 machinery:
  it is plain files in a `snapshot` package. A vendored bridge is therefore the
  cheapest case — the flag (§2.1) plus, if the layout needs shaping, hooks.</fact></item>
        <item><fact id="CLASS-SUBMODULE" status="impl/done" action="continue" actionstage="doc" audience="author">**Submodule-backed authoring** — the maintainer workspace references upstream
  through a Git submodule ([PROP-021](PROP-021-submodule-sources.xml)). A direct
  Git-source install preserves that live Git composition. Registry publication
  deliberately flattens a clean populated gitlink into ordinary package files,
  removes `.gitmodules`, and reports `submodule &lt;path&gt; vendored at &lt;sha&gt;`;
  the published package is therefore a truthful vendored snapshot, not a
  dangling promise that consumers will recurse into the maintainer's repo.</fact></item>
        <item><fact id="CLASS-REFERENCE" status="impl/done" action="continue" actionstage="doc" audience="author">**Reference-backed** — the package repository contains only maintainer-authored
  metadata and adapters. `[[embedded_source]]` declares the original public Git
  URL, an immutable full commit, an independently verified source-tree hash and
  upstream licence provenance. Installation fetches that exact source directly
  into the consumer's machine cache; selected `[[skill]]` content or
  `[[skill.resource]]` files are projected from the authenticated cached tree.
  The upstream is not copied into the bridge repository, is not resolved as a
  vibevm dependency node, and its own `vibe.toml`, hooks and submodules are never
  executed implicitly. The installed bridge itself remains a normal physical
  `vibedeps` slot; source-aware loaders combine that owner root with named,
  separately authenticated external roots without pretending the latter are
  UPL package payload.</fact></item>
      </list>
      <p p="13"><fact id="CLASS-TRADEOFF" status="spec/done">The maintainer chooses per trade-off: vendored is self-contained; submodule-backed
uses Git's native composition; reference-backed preserves repository and licence
boundaries but needs the pinned upstream once per machine-cache miss.</fact></p>
    </section>
    <section id="composition" title="2.3 Composition — every mechanism is optional">
      <p p="14"><fact id="req-composition" status="impl/done">`req r1`</fact></p>
      <p p="15"><fact id="COMPOSE-OPTIONAL" status="impl/done">A bridge is the point where the three orthogonal mechanisms compose, but it
mandates none of them:</fact></p>
      <list ordered="false" p="16">
        <item><fact id="OPT-NO-HOOKS" status="impl/done">a bridge **without hooks** is valid (the upstream layout already fits);</fact></item>
        <item><fact id="OPT-NO-SUBMODULE" status="impl/done">a bridge **without a submodule** is valid (vendored);</fact></item>
        <item><fact id="OPT-NO-IN-PLACE" status="impl/done">a bridge **without `in-place`** is the norm (`in-place` is only for giant
  upstreams).</fact></item>
      </list>
      <list ordered="false" p="17">
        <item><fact id="CANONICAL-FULL-CASE" status="impl/done">The canonical full case — submodule-backed + `pre-install` hook to shape the
  tree + selective skill projection — is the union of the four specs, but each
  piece is independently usable outside any bridge.</fact></item>
        <item><fact id="FOUR-SPECS-WHY" status="spec/done">This is why they are four
  specs and four test sets, not one (the owner's orthogonality requirement).</fact></item>
      </list>
    </section>
    <section id="maintainer-model" title="2.4 The maintainer model">
      <p p="18"><fact id="req-maintainer" status="impl/done">`req r1`</fact></p>
      <list ordered="false" p="19">
        <item><fact id="MAINTAINER-VS-AUTHOR" status="impl/done">The bridge's **maintainer** is distinct from the upstream **author**.</fact></item>
        <item><fact id="AUTHORSHIP-SEPARATION" status="impl/done" action="continue" actionstage="doc" audience="author">`[package].authors` names only the people or organisations that authored
  the package's own metadata, adapters and other maintainer-owned payload. It
  never absorbs the authors of referenced bytes. Every `[[embedded_source]]`
  records those separately as a non-empty `upstream_authors` list. Listings,
  locks and indexes preserve both lists under their own labels; they never
  concatenate them into one ambiguous authorship claim.</fact></item>
        <item><fact id="GROUP-PROVENANCE" status="impl/done" action="continue" actionstage="doc" audience="author">The package's qualified coordinate
  ([PROP-008](PROP-008-qualified-naming.xml)) names the **product a consumer
  installs**, not the codebase in which its packaging machinery happened to be
  written. Packaging Spec Kit does not make it `org.vibevm/*`; its product
  coordinate may be `org.speckit/speckit`. Packaging Matt Pocock's collection
  may be `com.mattpocock/skills`. The distinct steward remains visible through
  `[package].authors`, the package distribution `source_url`, `bridge = true`,
  and the upstream repository/PURL recorded by `[[embedded_source]]` and
  `describes`.</fact></item>
        <item><fact id="PROVENANCE-VISIBLE" status="impl/done">A consumer can therefore see three separate answers: *what product is this*
  (coordinate), *who maintains this packaging* (authors + distribution source),
  and *what original bytes does it wrap* (upstream provenance).</fact></item>
        <item><fact id="INDEPENDENT-REPOSITORY-DEFAULT" status="spec/done">**Not everything we package belongs to VibeVM.** A third-party product's
  package source defaults to its own Git repository outside the VibeVM
  monorepository and outside `org.vibevm/*`. Before scaffolding a bridge, the
  maintainer must explicitly ask the owner whether the package belongs in an
  existing product workspace or should be an independent repository. Silence
  never authorises absorbing a foreign product into the VibeVM namespace.
  Locally, independent package repositories may live under a neutral collection
  such as `~/git/v/packages/`; publication still maps one package repository to
  one registry repository.</fact></item>
        <item><fact id="LICENSE-BOUNDARY" status="impl/done" action="continue" actionstage="doc" audience="author">A bridge records two distinct legal surfaces: `[package].license` describes
  only the maintainer-authored bridge package, while every external embedded
  source records its upstream licence and an immutable licence URL. A bridge
  never presents upstream bytes as relicensed by the bridge maintainer.</fact></item>
        <item><fact id="SKILL-VIA-INCLUDE" status="impl/done">A skill that
  lives inside the bridged subtree is projected through the normal skill
  machinery, using the `include` selector
  ([PROP-015 #skill-include](../vibe-mcp/PROP-015-mcp-integration.xml#skill-include))
  to pick the relevant files out of an upstream tree full of unrelated content.</fact></item>
      </list>
    </section>
  </section>
  <section id="rejected" title="3. Rejected alternatives">
    <list ordered="false" p="20">
      <item><fact id="REJ-BRIDGE-KIND" status="spec/done">**A `bridge` package kind** (a kind of its own beside the §4.1 register) —
  rejected: the kinds describe *what the package is for*; "bridge"
  describes *where its content came from*. They are orthogonal axes, so bridge
  is a flag, not a kind. (The reasoning survives the register later growing
  `mcp` — that kind, too, says what a package is FOR.)</fact></item>
      <item><fact id="REJ-AUTO-IMPORT" status="spec/done">**Auto-importing a foreign repo with no maintainer** — rejected: someone must
  take responsibility for shaping, updating, and vouching for the wrapped code;
  an unowned auto-bridge has no one to fix it when upstream moves or breaks.</fact></item>
    </list>
  </section>
  <section id="out-of-scope" title="4. Out of scope">
    <list ordered="false" p="21">
      <item><fact id="OOS-AUTO-CONVERSION" status="spec/done">**Automatic conversion of foreign layouts** into vibevm conventions — bridges
  shape upstream with explicit, maintainer-written hooks, not inferred magic.</fact></item>
      <item><fact id="OOS-SECURITY-SCAN" status="spec/done">**Security scanning of wrapped third-party code** — the LLM "antivirus" is
  the same far-backlog item as for hooks
  ([PROP-020 §4](../vibe-workspace/PROP-020-install-hooks.xml#out-of-scope)); a
  bridge's trust posture is dependency selection plus the installed extension
  observability defined by PROP-054, an explicitly accepted risk for now.</fact></item>
      <item><fact id="OOS-LICENSE-TRACKING" status="spec/done">**Automated legal interpretation or compatibility adjudication** remains out
  of scope. Mechanical provenance is in scope: the bridge licence and each
  external source's upstream licence/immutable licence URL are recorded and
  displayed as separate facts.</fact></item>
    </list>
  </section>
  <section id="acceptance" title="5. Acceptance">
    <list ordered="false" p="22">
      <item><fact id="ACC-FLAG-PARSES" status="impl/done">`[package].bridge` parses as a boolean, defaults `false`, and does not alter
  `kind` or identity.</fact></item>
      <item><fact id="ACC-VENDORED-PLAIN" status="impl/done">A vendored bridge installs as a plain `snapshot` package (flag + optional
  hooks), with no submodule/materialization machinery engaged.</fact></item>
      <item><fact id="ACC-SUBMODULE-FULL" status="impl/done">A Git-source submodule-backed bridge fetches upstream recursively
  ([PROP-021](PROP-021-submodule-sources.xml)). Registry publication instead
  verifies and flattens each clean populated gitlink, omits Git metadata,
  reports the exact vendored commit, then ordinary install/hooks/skill
  projection consume that plain snapshot.</fact></item>
      <item><fact id="ACC-REFERENCE" status="impl/done">A reference-backed bridge repository contains no upstream files or gitlinks;
  install authenticates the declared immutable source into a machine-local
  cache, records the pin in `vibe.lock`, and projects only the declared skill
  paths/resources without executing upstream package machinery. Its normal
  bridge payload is still materialised in `vibedeps`, and an operator can ask
  for either the package root or an authenticated named source root.</fact></item>
      <item><fact id="ACC-PROVENANCE" status="impl/done">Product identity, packaging stewardship and upstream URL/PURL are separately
  recoverable for a bridge package; none is inferred from another.</fact></item>
      <item><fact id="ACC-AUTHORSHIP-SEPARATE" status="impl/done">Package authors and upstream authors are required, stored and displayed as
  separate provenance fields.</fact></item>
      <item><fact id="ACC-INDEPENDENT-SOURCE" status="spec/done">A third-party package is not placed below `org.vibevm` or in VibeVM's
  monorepository without an explicit owner decision; the scaffolding workflow
  asks this boundary question before choosing its coordinate or repository.</fact></item>
      <item><fact id="ACC-FLOOR-GREEN" status="spec/done">Full `self-check.sh` green; conform 0/0/0; specmap clean.</fact></item>
    </list>
  </section>
</spec>
