# Реестры и индекс {#root}

@status:doc/work @audience:user

[p01] Пакеты публикуются в место, которое vibe умеет читать: по умолчанию это публичная организация на GitHub, по репозиторию на пакет. Проект перечисляет такие места в том порядке, в каком им доверяет. Каталог рядом с каждым из них отвечает на поиск, ничего не клонируя.

[p02] Example `registry-list` is copied from the source page at projection time.

## Что такое реестр {#what-a-registry-is}

[p03] [Реестр](../glossary/index.xml#registry) — не сервер, который запускает vibe. Это хостинг-организация вроде `https://github.com/vibespecs`, где каждый пакет — собственный git-репозиторий, названный по [координате](../glossary/index.xml#coordinate) пакета. Опубликовать — значит запушить репозиторий и поставить тег версии; установить — значит клонировать по тегу. Кому можно публиковать, решают права самого хостинга, так что у vibe нет собственных аккаунтов.

> [p04] Each package is its **own** git repository — no monorepo. Per-package maintainer permissions are hosting-native (a package repo's owner controls access); no central merge queue.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#SHAPE-OWN-REPO>

[p05] Проект объявляет свои реестры в [манифесте](../glossary/index.xml#manifest) упорядоченным списком. У каждой записи есть локальное имя, корневой адрес организации и соглашение об именовании, которое превращает координату в имя репозитория. Когда просят пакет, vibe идёт по списку по порядку, и первый реестр, где есть подходящая версия, выигрывает.

> [p06] Resolution: the solver iterates registries in array order; the first that has a satisfying match for a pkgref wins. Versions of the same pkgref are **not** unioned across registries — this prevents a lower-trust registry from influencing resolve when a higher-trust one already has a valid answer.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#REGISTRY-WALK-ORDER>

[p07] Список — массив в порядке приоритета; рядом с ним [зеркало](../glossary/index.xml#mirror) — второй адрес того же реестра, а [переопределение](../glossary/index.xml#override) обходит обход списка для одной координаты. `url` записи — корень организации, никогда не репозиторий пакета, и это обычный git-адрес: `https://`, `ssh://`, `git@host:` или `file://`, без сокращений под какой-либо хост. Его `naming` говорит, как координата становится именем репозитория; умолчание соединяет группу и имя точкой.

> [p08] `[[registry]]` is an **array**, priority-ordered. `[[mirror]]` is a first-class fallback layer, transparent to the lockfile. `[[override]]` bypasses the resolver for pins. Schema and code path support all three from day one.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#SHAPE-REGISTRY-ARRAY>

> [p09] `url` — **organization root URL**, not a package repo URL. A registry is a hosting-org; packages are children of it.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#REG-FIELD-URL>

> [p10] URL syntax is **just git URL** — `git@host:…`, `ssh://`, `https://`, `file://`. No `github:` / `gitverse:` shorthands. New hosts "just work" as long as `git` speaks to them.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#SHAPE-PLAIN-GIT-URL>

> [p11] `naming` — convention for mapping a pkgref to a package repo name under this org. Values: `"fqdn"` (**default** — `org.vibevm.world/wal` → `<org>/org.vibevm.world.wal`; introduced and made the default by [PROP-008 §2.5](PROP-008-qualified-naming.xml#repo-naming), shipped M1.19 as a `_`-joined form and re-ruled to the dot join 2026-08-13), `"kind-name"` (legacy — `flow:wal` → `<org>/flow-wal`; the default this section originally declared, superseded by PROP-008), `"name"` (if name collisions are impossible in a given registry), `"kind/name"` (for hosts supporting nested repos). Other registries may ship with different conventions; the setting is per-registry, not global.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#REG-FIELD-NAMING>

[p12] К следующему реестру обход переходит, только когда один ответил, что пакета у него нет. Сбой соединения, ошибка сервера или испорченный манифест останавливают установку с этой ошибкой, потому что о простое или опечатке вы хотите знать. В реестре, объявленном публичным, требование учётных данных считается за «здесь нет», и обход продолжается; в реестре, который объявил режим аутентификации, это настоящий сбой.

> [p13] A `[[registry]]` is a **distinct package source** — its own naming convention, its own publishing identity, its own trust scope. The priority-ordered registry walk falls through on **`UnknownPackage` only**: a registry that confidently answers "I don't have this package" is free to defer to the next one. Any other primary failure — connect-failure (DNS / TCP), auth-failure on a registry that explicitly requires authentication, server error, malformed manifest — halts the install with an actionable error. This is the same policy Cargo and npm apply to a registry that errors out: the operator wants to know about a typo or an outage, not paper over it with a different registry that may carry a different version.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#REGISTRY-WALK-SEMANTICS>

> [p14] **`auth`-aware 401 classification (§2.2.1).** On `auth = "none"` a 401 / 403 response is an `UnknownPackage` signal, not an auth-failure: the registry is declared public, anything that responds with "you cannot read this without credentials" is — from this consumer's standpoint — equivalent to "this package does not have a public answer here." The walk falls through to the next registry, exactly like a 404. This is what unblocks the common case where one host (GitVerse) returns 401 for a missing repo while another (GitHub) returns 404 — the resolver treats both uniformly. On `auth = "token-env"` or `"credential-helper"` a 401 is a real `AuthFailed` and halts: the registry was declared as authenticated, the credentials presented were rejected, this is information the operator must see.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#AUTH-AWARE-401>

[p15] Запись можно выключить, не удаляя: `enabled = false` заставляет каждую команду пропускать этот реестр, пока вы не включите его обратно.

> [p16] **Decision.** Every `[[registry]]` carries an `enabled` flag, default `true`. Setting `enabled = false` switches a registry off **without deleting its entry** — it is skipped by **every** resolution path (`install` / `outdated` / `search` / `registry sync` / `vendor`), because the filter lives at the one resolver-construction point (`MultiRegistryResolver::from_manifest`): a disabled registry is never built, so nothing downstream can consult it. Re-enable by flipping the flag back; no re-add. The default `true` is skipped on serialize, so only an explicit `enabled = false` appears in a written `vibe.toml`. The flag applies uniformly to a project `vibe.toml` and the machine-global `~/.vibe/registry.toml`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#ENABLED-FLAG>

[p17] Машина может добавить собственные реестры в `~/.vibe/registry.toml`; они подмешиваются после проектных, и список проекта всегда сильнее машинного. Так компания нацеливает каждый проект на ноутбуке на свой приватный реестр, не правя каждый проект. Файл несёт те же секции `[[registry]]`, `[[mirror]]` и `[[override]]`, что и манифест проекта, для любого реестра, удалённого или локального; имя, объявленное в обоих местах, принадлежит проекту.

> [p18] Project-level `[[registry]]` always overrides the user-level default — the same precedence the `UserConfig` `[env]` layer already follows (the project / live value wins).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-010#PROJECT-OVERRIDES>

> [p19] **Decision.** Registry settings may also live in a per-user file resolved through the settings chokepoint (`vibe_core::settings::registry_config_path` → `~/.vibe/registry.toml`, or `$VIBE_SETTINGS/registry.toml`). It carries the same `[[registry]]` / `[[mirror]]` / `[[override]]` sections as a project `vibe.toml` — **any** registry, not only local ones: a remote `https://` / `ssh://` / `git@` org (with `auth`) is merged and searched exactly like a `file://` / path repo. A common motivation is keeping **machine-local** registries (a `file://` checkout, a path repo) out of a team-shared `vibe.toml`, where a hard-coded local path would differ per teammate; but a whole extra remote registry can be added machine-wide the same way. (Locality matters only to `--offline`, §2.2.2.1.)
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GLOBAL-REGISTRY-FILE>

> [p20] **Merge — project first, dedupe by name.** The effective registry list is the project's `[[registry]]` entries followed by the global file's, with a `name` collision resolved in the **project's** favour (the project entry wins; the global one is dropped). Mirrors are concatenated (project first). Overrides are project-first, deduped by `pkgref` (project wins). The merge is a pure function (`vibe_core::merge_effective`), verified in isolation. A project's explicit declaration always outranks a machine default, so a shared `vibe.toml` stays authoritative for the team while each machine supplements it with its own local repositories.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#MERGE-PROJECT-FIRST>

[p21] Набор доверия по умолчанию, который называет [спецификация](../glossary/index.xml#specification), — ровно два корня: `https://github.com/vibespecs` и `https://gitverse.ru/vibespecs`. Проект, который сегодня создаёт `vibe init`, не несёт блока реестров вовсе, так что перед первой установкой добавьте его через `vibe registry add` или дайте машинному файлу его подставить. Любому другому реестру доверяют только потому, что вы его добавили.

> [p22] **The default trust set is exactly two roots** — `https://github.com/vibespecs` and `https://gitverse.ru/vibespecs` — trusted by default as the registries `vibe init` writes. Every other registry is trusted **only** by the user's own act of adding it to their configuration (owner ruling, 2026-08-13).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#DEFAULT-TRUSTED-REGISTRIES>

> [p23] **Default in new projects.** `vibe init` writes the default registry URL (`DEFAULT_REGISTRY_URL` in [`vibe_core::manifest`](../../crates/vibe-core/src/manifest/project.rs)) into every new `vibe.toml`'s `[[registry]]` entry unless the operator passes `--no-registry` or overrides with `--registry-url <URL>` / `--registry-ref <REF>`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-000#INIT-DEFAULT-REGISTRY>

## Индекс {#the-index}

[p24] Клонировать репозиторий, чтобы узнать, что в нём, — медленно, а перечислить организацию для поиска без аккаунта невозможно. Поэтому реестр может держать *[индекс](../glossary/index.xml#index-registry)*: отдельный репозиторий рядом с пакетами, где для каждой опубликованной версии записаны сводка манифеста и [отпечаток](../glossary/index.xml#fingerprint) содержимого. `vibe search` читает индекс; свежая установка читает его, чтобы пропустить круг клонов.

> [p25] **Decision.** The index layer is **strictly additive**. Every existing vibevm code path keeps working exactly as today when no index is present. No registry is required to have an index. No project is required to consume one; a consumer that finds none falls back to the live `git ls-remote` path that exists today.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#INDEX-OPTIONAL>

[p26] Индекс — кэш, никогда не истина. Если он расходится с репозиторием пакета, побеждает репозиторий, а пакет, разрешённый через индекс, всё равно сверяется с отпечатком содержимого, когда приходит. Реестр без индекса работает ровно как раньше, только медленнее; отсутствие индекса — не ошибка.

> [p27] **Decision.** Package repositories are the **source of truth** for content (manifests, files, tags). The index is a **derived hot cache**, regeneratable from the authoritative package state.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#REPOS-AUTHORITATIVE>

> [p28] This matters because it disambiguates the failure mode: if the index disagrees with reality, **reality wins**.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#REALITY-WINS>

[p29] Адрес индекса выводится из адреса реестра, и его можно переопределить для каждого реестра переменной окружения, названной по имени реестра, `VIBEVM_INDEX_URL_<NAME>`; буквальное значение `none` выключает обращения к индексу для этого реестра.

> [p30] **The environment variable `VIBEVM_INDEX_URL_<REGISTRY>` is the ladder's top rung — the operator's per-run re-point, no longer the only source.** Until 2026-08-20 it was the sole locator, deliberately weaker than the manifest field it stood in for (per-shell, per-run, travelling with neither project nor lockfile) — which is why it never closed the requirement above. Now it *overrides* the key: env beats `index_url` beats the default, and `none` at either explicit rung disables the index. The name normalization (`ASCII alphanumerics upper-cased, the rest to `_``) is unchanged.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#INDEX-URL-TODAY-IS-AN-ENVIRONMENT-VARIABLE>

[p31] Запись реестра может закрепить свой индекс через `index_url`; без него публичная организация на GitHub отображается в свой репозиторий `index` на хосте сырого содержимого, а любой другой хост — в `<registry-url>/index`. У пробы индекса три исхода: найден, отсутствует, отказано. Только «отсутствует» тихо проваливается к живому перечислению, потому что индекса никто не обещал; индекс, который есть, но не читается, — это сообщение об ошибке. `vibe search` задаёт вопрос каждому настроенному индексу напрямую, а не скачивает весь каталог.

> [p32] **Configurable but defaulted.** A `[[registry]]` block pins a custom index location — the key exists in `RegistrySection` (one type serving both the project `vibe.toml` and the machine-global `~/.vibe/registry.toml`, so the columns share one vocabulary), and this exact block parses (pinned by test `prop005_index_url_example_parses`, which carries it verbatim):
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#INDEX-URL-CONFIG>

> [p33] The bottom rung is host-aware. Canonical public `https://github.com/<org>`
> maps to `https://raw.githubusercontent.com/<org>/index/<registry-ref>`;
> other hosts retain `<registry-url>/index`. This makes both fresh and already-
> seeded GitHub configurations whose `index_url` field is absent consume the static
> repository rather than its HTML page. The full ladder remains env override →
> manifest key → host-aware default; exact `none` on either explicit rung
> disables lookup. Lookalike hosts, nested paths, userinfo, unsafe owners/refs,
> queries and fragments are never rewritten.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#INDEX-URL-DEFAULT>

> [p34] **A probe answers `found`, `absent`, or `refused`, and the third is what keeps this section honest.** «Absent» is the only outcome that falls through quietly, because it is the one that means what the fall-through assumes: nothing is published here. An index that IS there and cannot serve this consumer — it refused us (401/403), its body does not parse as a handshake, its handshake format is one this build does not read, or it publishes no world of this build's epoch — answers **`refused`**, carrying the offered epochs, this build's epoch, a recipe, and whatever the document said in `min_client` / `notice` / `successor`. Collapsing that into «absent» would make a private, broken or newer-than-us index indistinguishable from a missing one, which is the silence [PROP-044 §2](../../common/PROP-044-change-native-formats.xml#laws) forbids: a break that announces itself is normal life, a riddle is what strands users.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#A-PROBE-HAS-THREE-OUTCOMES-NOT-TWO>

> [p35] 404 / connect-failure on the index → **silent** fallback to live `ls-remote`: no error message, because the operator never promised an index. This half is built, and it is the `absent` outcome of [`##A-PROBE-HAS-THREE-OUTCOMES-NOT-TWO`](#optional) — the other two outcomes are never silent.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#AN-ABSENT-INDEX-FALLS-BACK-WITHOUT-A-WORD>

> [p36] Walks every configured registry's index through the same client the resolver uses — probe, then query — rather than downloading `primary.jsonl.gz` and scanning it locally. The whole-file scan was the shape this document first imagined and is not what shipped: asking the index a question keeps the bandwidth proportional to the answer instead of to the catalog, and it puts one discovery ladder ([§2.1](#optional)) under every consumer instead of two. Index is the enabling layer for M2.10; `vibe search` is the headline consumer of this PROP.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-index/PROP-005#INT-SEARCH>

## Зеркала, переопределения и git-источники {#mirrors-and-overrides}

[p37] *Зеркало* — другой адрес того же реестра, к которому обращаются первым ради доступности и который сверяют по тем же отпечаткам; зеркало, отдающее под известной версией другие байты, отвергается, а не получает доверие. Зеркала никогда не попадают в [лок-файл](../glossary/index.xml#lock-file): записывается канонический адрес, так что смена зеркала ничего не меняет для ваших коллег.

> [p38] Mirror integrity verification is **mandatory**, not optional. A mirror whose `content_hash` for `(kind, name, version)` differs from the lockfile pin fails the install with an actionable error. This closes the supply-chain hole where a hijacked mirror could substitute content.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#MIRROR-INTEGRITY-MANDATORY>

[p39] *Переопределение* заменяет один пакет копией из другого места — ради хотфикса или патча, который ждёт своей очереди наверху; оно обходит обход реестров для этой одной координаты и помечено в лок-файле, чтобы никто не принял его за опубликованную версию.

> [p40] **Decision.** `[[override]]` bypasses the registry layer for a named pkgref:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#OVERRIDE-SHORT-CIRCUIT>

[p41] Переопределение ничего не ослабляет: отпечаток копии по-прежнему закреплён в лок-файле и сверяется при каждой установке, а запись несёт `overridden = true`.

> [p42] The resolver short-circuits: it does not consult `[[registry]]` for this pkgref at all; it fetches directly from the given URL at the given ref. Content hash is still pinned in the lockfile and verified on each install — an override does not relax integrity. The lockfile records `overridden = true` on that entry. A `vibe list --overrides` flag is specified here and **not shipped** — the lockfile field is the only surface today.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#OVERRIDE-SEMANTICS>

[p43] Зависимость может указывать и прямо на git-репозиторий — на тег, коммит или ветку. Тег и коммит закреплены; ветка при обновлении проходится заново, а лок-файл записывает коммит, который был установлен на самом деле.

> [p44] Mutable branch. Lockfile records the resolved commit at install time; subsequent `vibe update` re-walks branch HEAD. **Mutable** — see "Mutability and `vibe update`" below.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#ROW-GS-BRANCH-MEANING>

> [p45] **Decision.** A dependency may be declared as a first-class git-source in `[requires.packages]` — fetching the package from an arbitrary git repository instead of resolving it through `[[registry]]`. This is the vibevm analogue of Cargo's `[dependencies] foo = { git = "..." }`, npm's `"foo": "git+https://..."`, Poetry's `foo = { git = "..." }`, Bundler's `gem 'foo', git: '...'`, Go modules' baseline behaviour. The use cases are:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GIT-SOURCE-DECL>

[p46] [Git-источник](../glossary/index.xml#git-source) записывается инлайновой таблицей на требовании: адрес `git` и ровно одно из `tag`, `rev` или `branch`; ни одного или два — отказ, потому что угадывать ветку по умолчанию недопустимо там, где решается, какой код входит в ваш проект. `auth` источника объявляется на самом источнике и никогда не заимствуется у реестра на том же хосте. Когда репозиторий приходит, vibe читает собственный манифест пакета и отвергает тот, чьи вид и имя расходятся с тем, что вы потребовали.

> [p47] **Wire form.** `[requires.packages]` becomes a TOML table whose values are either a version-constraint **string** (registry-resolved, the M1.13 shape) or an inline-table (registry-resolved with options, or git-source). The legacy array-of-strings shape (`packages = ["flow:wal@^0.3"]`) parses transparently into table-form on read; on round-trip the manifest writes table-form.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GS-WIRE-FORM>

> [p48] **Exactly one** of `tag` / `rev` / `branch` must be present in a git-source declaration. Zero is rejected at parse time with `MissingRef`. Two or more rejected with `ConflictingRefs`. There is no "default branch HEAD" fall-back — too magical for a security-sensitive surface; explicit > implicit.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GS-EXACTLY-ONE-REF>

> [p49] **Auth.** Per-source `auth` is **explicit, not host-derived**. The resolver does not look at `[[registry]] auth` for the same host and apply it transitively to a git-source pointing at that host — too magical, creates implicit ordering dependencies between sections of the manifest. If a project has multiple packages from the same private host, the operator can either:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GS-AUTH-EXPLICIT>

> [p50] The pkgref `<kind>:<name>` is read from the package's `vibe-package.toml` `[package]` section on the resolved git ref (same path as registry-resolved manifest fetch via `git archive`). The resolver verifies that the `(kind, name)` declared in `[requires.packages]` matches what the repo actually carries; mismatch = `PackageIdentityMismatch`. This means a malicious git-source cannot impersonate `flow:wal` if its `vibe-package.toml` declares it as `feat:auth`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GS-IDENTITY-VERIFICATION>

[p51] Источник требования выбирается в фиксированном порядке: сначала переопределение, затем git-источник, объявленный на требовании, затем обход реестров. За веткой идёт только `vibe update`; `vibe install` держит коммит, который записал лок.

> [p52] **Resolution order.** When the resolver looks up a pkgref, the source is decided in this order:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GS-RESOLUTION-ORDER>

> [p53] **Mutability and `vibe update`.** Tags and revs are immutable by definition; force-push is detected via content-hash. Branches are explicitly mutable: `vibe install` against a branch resolves to the current branch HEAD and pins that commit in the lockfile. `vibe update` re-walks each branch-declared git-source, and if HEAD has moved, re-resolves and re-locks. `vibe install` (no flag) **does not** chase a branch's HEAD on subsequent runs — the lockfile's `resolved_commit` is authoritative until `update` is called. This matches Cargo's behaviour (`cargo build` does not bump branch deps; `cargo update` does).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#GS-MUTABILITY>

## Аутентификация {#authentication}

[p54] Публичному реестру учётные данные не нужны, и vibe их не посылает: он глушит помощники учётных данных git, чтобы установка в скрипте никогда не зависла на запросе пароля. Приватный реестр объявляет свой режим в манифесте: токен из переменной окружения, системный помощник учётных данных или SSH-ключи. Токен приходит из вашего окружения и никогда не попадает в файл, который пишет vibe.

> [p55] **Token never lands on disk via vibevm.** The token comes from the operator's environment. Vibe reads it, builds the credentialed URL in memory, hands it to the spawned git process, and discards. The lockfile's `source_url` field always carries the **canonical** URL (no embedded credentials) — symmetric with the `[[mirror]]` invariant in §2.3. Token discipline (PROP-000 §20) applies: the value is treated as surface-secret; it does not appear in any vibevm-emitted output. Modern git (≥2.31) auto-redacts passwords from its own stderr, so even on errors the token is not echoed.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#TOKEN-NEVER-ON-DISK>

## Пакеты на этой машине {#local-sources}

[p56] vibe, собранный из чекаута исходников, считает пакеты из дерева этого чекаута [встроенным реестром](../glossary/index.xml#embedded-registry): у такой сборки он включён по умолчанию, у распространяемой выключен, а на одну команду выключается через `--no-default-registry`. Перечисление версий всё равно объединяет встроенный и объявленные реестры, так что более новая опубликованная версия видна; переопределение или git-источник на требовании остаются выше встроенного реестра. `--embedded-short-circuit` останавливает перечисление на встроенном реестре для пакетов, которые он отдаёт, так что полностью встроенный граф разрешается вообще без сети.

> [p57] Its **default follows the install origin**: on for `origin = "external"`, off for
>   a distribution.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#KNOB-DEFAULT>

> [p58] `--no-default-registry` (env `VIBE_NO_DEFAULT_REGISTRY=1`)
>   suppresses the embedded registry entirely for a command.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#KNOB-SUPPRESS>

> [p59] But **version enumeration** (the candidate set the solver picks
>   from) **unions across embedded *and* declared** by default, so the solver can
>   see a newer published version even for a package the embedded registry already
>   carries.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#ENUM-UNION>

> [p60] Resolution keeps PROP-002's explicit-source short-circuits **above** the
> embedded registry — an explicit per-dependency source or pin is always
> deliberate and always wins:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#EXPLICIT-ABOVE>

> [p61] **`--embedded-short-circuit`** — keep the declared walk available, but
>   short-circuit version enumeration at the embedded registry for any coordinate
>   it serves: the network is reached **only** for packages the embedded registry
>   lacks. A fully-embedded dependency graph resolves with zero network access
>   (no enumeration round-trip, no credential prompt), while a genuinely missing
>   package is still fetched from the network. Implies embedded-first precedence;
>   mutually exclusive with `--no-prefer-embedded`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#FLAG-EMBEDDED-SHORT-CIRCUIT>

[p62] Пакет, разрешённый таким путём, записывается с `source_kind = "embedded"`, и `vibe check` предупреждает, что такой лок непереносим. В `--frozen` и других неинтерактивных запусках встроенный реестр выключен, так что лок, который работает только на машине одного разработчика, не пройдёт на сборочном сервере.

> [p63] A package resolved from the embedded registry records `source_kind = "embedded"`
> in `vibe.lock` (a [PROP-002](PROP-002-decentralized-registry.xml) `SourceKind`
> variant beside `registry` / `git` / `override` / `path`). Its `source_url` is the
> `file://` path into `<source_path>/packages`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#LOCK-EMBEDDED>

> [p64] **Warn.** `vibe check` **warns** (does not fail) when the lock carries any
>   `source_kind = "embedded"` entry: "this lockfile depends on the embedded
>   registry of a source install and is not portable; publish or vendor these
>   packages before sharing the lock." A `source_kind = "local"` entry is
>   portable and does NOT warn.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#GUARD-WARN>

> [p65] **CI-off.** In `--frozen` (and any non-interactive CI resolution), the
>   vibe-embedded registry is **disabled by default** — CI must resolve from
>   declared registries (and, since §3.3, project-local), so a machine-local lock
>   cannot silently pass there. Project-local is NOT suppressed by this gate — it
>   is per-project and portable.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#GUARD-CI-OFF>

[p66] Проект, у которого рядом с манифестом лежит папка `packages/`, получает эту папку открытой как локальный реестр вообще без объявления. Пакеты, разрешённые из неё, записываются с `source_kind = "local"`, и это переносимо, потому что каждый чекаут разрешает ту же папку в то же содержимое. `--no-prefer-local` обходит папку на одну команду.

> [p67] REQ. A project carrying `<project_root>/packages/` (where `project_root` is
>   the directory holding the project's `vibe.toml`, resolved by
>   `resolve_project_root`) gets that directory auto-opened as a `LocalRegistry`
>   and composed into the local-registry family alongside the vibe-embedded
>   registry. No `[[registry]]` block, no `--registry <path>`, no
>   `~/.vibe/registry.toml` machine entry needed.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#LOCAL-AUTO-OPEN>

> [p68] REQ. A package resolved from project-local records `source_kind = "local"`
>   in `vibe.lock` (§4) — distinct from `embedded`. Unlike `embedded`, it is
>   **portable** and the reproducibility guard (§5) does NOT warn on it: every
>   checkout of the project resolves the same `packages/` to the same content.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#LOCAL-SOURCE-KIND>

> [p69] REQ. `--no-prefer-local` suppresses project-packages discovery for one
>   command (use when a project's `packages/` is stale, broken, or deliberately
>   bypassed). It does NOT suppress vibe-embedded — `--no-default-registry`
>   remains the knob for that. `--prefer-local` is the explicit affirmation of
>   the default (project-local wins the local family); mutually exclusive with
>   `--no-prefer-local`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#LOCAL-NO-PREFER-FLAG>

## Особые случаи и правила {#edge-cases}

[p70] vibe, собранный из чекаута исходников, считает пакеты из дерева этого чекаута окружающим реестром, к которому обращается первым: разработчик vibe ставит разрабатываемые пакеты, не публикуя их. У распространяемого vibe такого реестра нет.

> [p71] This PROP makes the in-tree `packages/` of a source-installed `vibe` an
> **ambient default registry** — resolved automatically, with zero configuration
> in the consuming project.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-030#AMBIENT-DEFAULT>

[p72] Репозиторий с исходниками самого vibe зеркалится на двух хостах, но это другое дело, чем реестр пакетов: зеркала несут исходники программы, реестр несёт пакеты, и учётные данные для них никогда не делятся.

> [p73] This PROP governs the **source repository**; it is orthogonal to the **package registry**, and the two must not be conflated.
>
> <spec://org.vibevm.core/vibevm/common/PROP-016#ORTHOGONALITY-LAW>

[p74] С реестрами vibe работает через программу `git` в вашем `PATH` и проверяет её наличие до начала; `VIBE_GIT_BINARY` указывает ему на другую копию. Клон реестра старше часа обновляется перед установкой, моложе — берётся как есть, а `vibe registry sync` обновляет независимо от возраста.

> [p75] **Runtime dependency on `git` in `PATH`.** Acceptable: our target
>   audience is developers who already have git installed. We perform a
>   preflight `git --version` check and emit an actionable error (with
>   a pointer to `https://git-scm.com/downloads`) if it is missing.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-001#RISK-GIT-IN-PATH>

> [p76] **Resolved — shipped as proposed.** The `VIBE_GIT_BINARY`
>   PATH override lives in `git_backend/shell.rs` and its comment cites §6 of this
>   PROP; the env-var form was chosen over a CLI flag exactly to keep the CLI
>   surface stable.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-001#OPEN-GIT-BINARY-PATH>

> [p77] **Decision:** the default freshness TTL is **1 hour**, checked against
> `meta.toml.last_pulled_at`. An install whose registry cache is older
> than the TTL triggers an implicit `update`. An install whose cache is
> younger skips the pull. `vibe registry sync` forces an update
> regardless of age.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-001#FRESHNESS-TTL>

[p78] Файл, который нужен резолверу, манифест или заглушка перенаправления, читается прямо с хоста по HTTPS, когда хост — GitHub или GitVerse, с учётными данными в заголовке и никогда в адресе; промах решает вопрос только для тега или коммита, чьё содержимое неизменно, а на ветке следующим спрашивают git. Хост, которого нет в таблице, на этот путь не попадает никогда.

> [p79] Before a single file is asked of git, the backend reads it over HTTPS from the host's own raw endpoint when the host is one it knows — `github.com` through `raw.githubusercontent.com`, `gitverse.ru` through its contents API — with any credential sent only as a bearer header, never in the address. A hit is the file. A miss is authoritative only for a tag or a commit SHA, whose content is fixed; on a branch, or for a manifest, the read falls through to git, whose answer stands as it always did. A host the table does not name never enters this path.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#RAW-READ-FAST-PATH>

[p80] Чтение, которое хост отверг на минуту, из-за лимита частоты или ошибки сервера, повторяется несколько раз с короткой паузой, прежде чем читатель откатится к git; обычное «не найдено» не повторяется никогда.

> [p81] A raw read that the host refuses with `429` or a `5xx` is retried a small, bounded number of times with a short pause, honouring `Retry-After` within that bound, before the read falls through to git as any other unexpected answer does. A `404` is never retried: on a tag or a commit it is authoritative, and on a branch it is what git will be asked about next.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-002#RAW-READ-BACKOFF>

