# Пакеты и их виды {#root}

@status:doc/work @audience:user,author

[p01] Всё, что устанавливает vibe, — пакет: папка с небольшим файлом описания и тем текстом или инструментами, которые она приносит. Пакеты бывают восьми видов, и вид говорит, для чего пакет нужен, ещё до того, как вы его откроете: способ работать, фича, технология, инструмент, языковой гайд, сервер для агента, документация или приложение.

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

## Что такое пакет {#a-package}

[p03] Пакет — это проект, который сделали устанавливаемым. У него та же раскладка, что у проекта: собственный `vibe.toml` и собственный `vibevm/vibespecs/`, и рядом может лежать код. Когда проект его ставит, опубликованное дерево пакета копируется в дерево зависимостей проекта дословно; ничего не извлекается, не переписывается и не сливается.

> [p04] **L4 — packages too.** Every package root mirrors the same
> layout (`vibevm/vibespecs` inside the package instead of `spec/`);
> materialisation mirrors package layout into the slots, boot-snippet
> paths and INDEX targets follow.
>
> <spec://org.vibevm.core/vibevm/common/PROP-052#PACKAGES-CARRY-THE-LAYOUT-TOO>

[p05] Пакет называется *[координатой](../glossary/index.xml#coordinate)*: группа, косая черта и имя, как в `org.vibevm.world/wal`. Группа похожа на перевёрнутое доменное имя и говорит, кто публикует; имя уникально внутри группы. Версия дополняет адрес, когда она нужна: `org.vibevm.world/wal@1.0.0`. Вид в имя не входит. Его можно написать префиксом в командной строке, `flow:org.vibevm.world/wal`, и тогда vibe проверит, что пакет действительно этого вида.

> [p06] **Decision.** Package identity becomes `(group, name, version, content_hash)`. `kind` **leaves the identity tuple**.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#IDENTITY-TUPLE>

[p07] Группа — заявление, а не удостоверение: никто не проверяет, владеет ли издатель `com.google/x` этим доменом, и никогда не проверит, потому что у vibe нет центрального проверяющего, которого можно спросить. Имя уникально внутри своей группы, так что координата сама по себе и есть идентичность. В командной строке префикс вида и группа необязательны; в [манифесте](../glossary/index.xml#manifest) координата всегда пишется полностью. В [реестре](../glossary/index.xml#registry) репозиторий называется группой и именем через точку, `org.vibevm.world.wal`, что само по себе корректное перевёрнутое доменное имя.

> [p08] **Decision (owner ruling, 2026-08-13).** A `group` is a **claim, not a credential**. Nothing verifies that the author of `com.google/x` owns `google.com` — and nothing ever will: vibevm is decentralised and has no central verifier to delegate to (Maven's central domain verification is the model we deliberately do not inherit). The claim's grammar is domain-shaped (§2.1); its **semantics carry no domain-ownership assertion**.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#GROUP-IS-A-CLAIM>

> [p09] `name` becomes unique **within a `group`** (was: within a `kind`, `VIBEVM-SPEC.md` §7.1). `(group, name)` is therefore unique on its own — `kind` is no longer needed to disambiguate.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#NAME-UNIQUE-IN-GROUP>

> [p10] **Decision.** The pkgref grammar gains an optional `group` segment and makes the `kind` prefix optional:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#PKGREF-GRAMMAR>

> [p11] **The short form is CLI-only sugar.** It is never written to a manifest (§2.6).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#SHORT-CLI-ONLY>

> [p12] **Decision:** `[<kind>:]<group>/<name>@<version>` — identity is **qualified** since M1.19 ([PROP-008 §2.2](../modules/vibe-registry/PROP-008-qualified-naming.xml#identity)); the unqualified `<kind>:<name>@<version>` of `VIBEVM-SPEC.md` §7.1 is CLI sugar that resolves once, at the human boundary.
>
> <spec://org.vibevm.core/vibevm/common/PROP-000#IDENTITY-FORM>

> [p13] `naming = "fqdn"` maps a pkgref to the repository name `<group>.<name>` (`org.vibevm.world/wal` → `org.vibevm.world.wal`) — the composite is itself a valid reversed FQDN, and that is the point of the ruling. **Owner ruling 2026-08-13** («убери подчёркивания везде, чтобы получились настоящие FQDN с доменными правилами»), superseding the 2026-05 `_`-joiner decision recorded in this unit's earlier text. The split stays deterministic without a charset-excluded joiner: the name is a **single dot-free LDH label** (`validate_package_name`), so the **last dot** is always the boundary — parse back by taking the last label as `name`, the rest as `group`. The old rationale's premises are both gone: `_` was then legal inside groups (no longer — §2.1 LDH), and the composite was not required to be a domain (now it is). *Considered and rejected:* keeping `_` (the composite is not even formally a domain; and a `_`-joined name contradicts the LDH ruling the halves now obey). *Migration:* live `_`-joined repositories in `vibespecs` (M0/M1 scale) rename to the dot form as a follow-up of the 2026-08-13 landing — pre-public and cheap, and GitHub redirects renamed repositories; the §3 history below records the `_`-era as it happened and is not rewritten. *Revisit:* a hosting provider that forbids `.` in repository names appears in the registry set — then that provider's adapter gets its own naming value, never a silent re-join.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#JOINER-UNDERSCORE>

[p14] Где бы пакет ни назывался в проекте, стоит полная координата: `group/name` в требовании, `group.name` как имя репозитория, `group/name` как первый сегмент адреса `spec://`. Короткие имена живут только там, где человек один раз набирает их в командной строке.

> [p15] A package address MUST carry its full coordinate — `group` **and** `name` — in **every** occurrence across the project:
>
> <spec://org.vibevm.core/vibevm/common/PROP-029#ADDR-LAW>

> [p16] `[<kind>:]<group>/<name>`
>
> <spec://org.vibevm.core/vibevm/common/PROP-029#CARRIER-PKGREF-FORM>

> [p17] `<group>.<name>` — `/` is illegal in a repo name; the name is the last label
>
> <spec://org.vibevm.core/vibevm/common/PROP-029#CARRIER-REPO-NAME-FORM>

> [p18] `<group>/<name>` — the name is the first path segment
>
> <spec://org.vibevm.core/vibevm/common/PROP-029#CARRIER-SPEC-URI-FORM>

> [p19] Short or bare names survive only as a one-time human CLI input, resolved to the qualified form at the boundary (PROP-008 §2.6).
>
> <spec://org.vibevm.core/vibevm/common/PROP-029#ADDR-SHORT-NAMES>

## Восемь видов {#the-kinds}

[p20]
| Вид | Что приносит | Пример |
| --- | --- | --- |
| `flow` | способ работать: правила коммитов, заметки сессий, соглашения о ревью; обычно [стартовый фрагмент](../glossary/index.xml#boot-snippet), который агент читает каждую сессию | `org.vibevm.world/wal` |
| `feat` | описание того, что построить, без слова о том, как | страница приветствия, вход по электронной почте |
| `stack` | технологический контекст, который говорит, как с ним строится фича, или бандл членов семейства одной версии | `org.vibevm.ai-native/rust-ai-native` |
| `tool` | скрипт или утилита, которую может вызвать шаг сборки | обёртка над форматтером |
| `lang` | руководство о том, как писать на языке или в нотации | `org.vibevm.ai-native/rust-ai-native-lang` |
| `mcp` | сервер, с которым разговаривает агент, собранный из кода самого пакета | `org.vibevm.ai-native/rust-ai-native-mcp` |
| `doc` | документация других пакетов: читается, не устанавливается | `org.vibevm.core/vibevm-docs` |
| `app` | самостоятельный продукт со своей выкладкой | `org.vibevm.doc/web` |

[p21] Набор закрыт и растёт только поправкой к [спецификации](../glossary/index.xml#specification); [манифест](../glossary/index.xml#manifest) с неизвестным видом отвергается, а не угадывается.

> [p22] `kind ∈ {flow, feat, stack, tool, mcp, lang, doc, app}` — eight kinds; `mcp` shipped with [PROP-027](../modules/vibe-mcp/PROP-027-mcp-packages.xml); `doc` and `app` admitted by [PROP-057](PROP-057-documentation-packages-and-site.xml) through the `VIBEVM-SPEC.md` §4.1 amendment of 2026-09-12 (pending the owner's ratification at the merge of the docs-2026-09 branch; the code learns the two kinds in that campaign's phase 2). (§Invariants `INV-VOCABULARY` in this file carries the same list.)
>
> <spec://org.vibevm.core/vibevm/common/PROP-000#KIND-SET>

[p23] Вид — метаданные пакета, а не часть его идентичности: он решает, куда кладётся содержимое, что показывает фильтр `--kind` у `vibe list` и `vibe search` и принимается ли имя с префиксом вида. Два пакета разных видов не могут делить координату, потому что координата сама по себе и есть идентичность.

> [p24] **Decision.** `kind` (`flow` / `feat` / `stack` / `tool`) stays a **mandatory `[package]` field** but is now a pure attribute — it identifies nothing and names nothing.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#KIND-METADATA>

[p25] `app` отличается от `tool` механически: инструмент живёт в проекте и запускается через `vibe bin exec` по [лок-файлу](../glossary/index.xml#lock-file), а приложение не живёт ни в каком проекте-потребителе и собирается и выкладывается само по себе.

> [p26] The boundary with `tool` is mechanical: a `tool` lives in a project and runs through `vibe bin exec` by the lock file; an `app` runs nowhere in a consumer project and is built and deployed on its own.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#KIND-APP-VS-TOOL>

## Семейства и компаньоны {#families}

[p27] Некоторые [возможности](../glossary/index.xml#capability) приходят несколькими пакетами с общей основой имени: языковой гайд, сервер, который отдаёт его инструменты, и маленький бандл, который закрепляет оба на одной версии. Это *семейство*. Потребовать бандл — значит поставить семейство, а изменение любого члена поднимает всех до одной общей версии, так что части никогда не разъедутся.

> [p28] Within a family the members move in **unison**: a content change to any member
>   bumps EVERY member of that family to one shared version, and the aggregator's
>   version IS that family version.
>
> <spec://org.vibevm.core/vibevm/common/PROP-028#UNISON-LAW>

[p29] Сам бандл — самый маленький пакет из возможных: манифест и README, ни кода, ни [стартового фрагмента](../glossary/index.xml#boot-snippet). Его единственная работа — назвать членов семейства одной версии.

> [p30] **`<family>`** — the *aggregator*. `kind = "stack"`, content-minimal: a
>   `vibe.toml` and a `README.md`, and nothing else — no code, no boot snippet,
>   no `specmap.toml` / `conform.toml`. Its whole job is to name the family's
>   members at one resolved version set through exact `=X.Y.Z` pins in
>   `[requires]`. Requiring the aggregator installs the family.
>
> <spec://org.vibevm.core/vibevm/common/PROP-028#ROLE-AGGREGATOR>

[p31] Документация — исключение. Руководство пакета — его *[компаньон](../glossary/index.xml#companion)* с суффиксом `-docs` в той же группе, и оно держит собственную линию версий. Исправленная опечатка в руководстве не выпускает инструменты, а новая версия инструмента не требует нового руководства. Руководство говорит, какие версии своего [предмета](../glossary/index.xml#subject) оно описывает, а сайт берёт самое новое руководство, которое подходит.

> [p32] **`<family>-docs`** — the *documentation companion* (`kind = "doc"`,
>   [PROP-057 §3](PROP-057-documentation-packages-and-site.xml)): the
>   official-by-default documentation of the family's subject, in the subject's
>   group. Unlike the three code roles it is a **companion, not a member**: it
>   is never pinned by the aggregator, it does not take part in the family's
>   unison (§2.2), it keeps its own version line, and it states compatibility
>   with its subject through the version constraint of its `[[documents]]`
>   table. Its translations follow the same companion form, one package per
>   language, named `<family>-docs-<lang>` with a lower-case BCP-47 tag
>   (`rust-ai-native-docs-ru`). Amended 2026-09-11.
>
> <spec://org.vibevm.core/vibevm/common/PROP-028#ROLE-DOCS>

## Как пакет ложится на диск {#on-disk}

[p33] `[package].materialization` говорит, как пакет попадает в дерево потребителя. `copy` — умолчание и всё, что нужно обычному пакету; `hardlink` — то же содержимое, делящее байты с [хранилищем](../glossary/index.xml#store). Оба вендорятся: папка коммитится вместе с проектом и восстанавливается из него без сети. `in-place` держит живой git-чекаут с собственным `.git`, который git игнорирует и который свежий клон восстанавливает на закреплённом коммите, поэтому ему нужны сеть и [git-источник](../glossary/index.xml#git-source). Всё разрушительное над таким слотом — удаление, принудительная переустановка, смена версии — сначала спрашивает, а когда ответить некому, требует `--force`.

> [p34] `[package].materialization` selects how the package lands on disk:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-022#MODE-FIELD>

> [p35] `copy` is the default and the only mode an ordinary package needs. (It was named `snapshot` until the owner's 2026-08-13 terminology ruling reserved that word for the unfrozen version — PROP-044 §2b; the legacy spelling is refused with the rename recipe, never aliased.)
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-022#SNAPSHOT-DEFAULT>

> [p36] **`copy` / `hardlink`** are vendored — the slot is committed into the
>   project's git and is offline-reproducible from it (a `hardlink` slot's bytes
>   are materialised into git on `git add` like any file); a `copy` slot trivially so.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-022#VENDORED-COPY-MODES>

> [p37] **`in-place`** is **not** vendored — the slot (a nested `.git` plus possibly
>   millions of files) is `.gitignore`d in the project; restoration is a re-clone
>   at the lockfile's `resolved_commit`. The honest trade: `in-place` packages
>   need the network to restore, where `snapshot` packages do not.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-022#IN-PLACE-NOT-VENDORED>

> [p38] **Requires a git source.** Incremental update and `git clean` reset both need
>   git; a non-git source has no `in-place` story (§4).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-022#IP-REQUIRES-GIT>

> [p39] An `in-place` slot may be a multi-hour download. Any **destructive** operation
>   on it — `uninstall`, `reinstall --force`, a version switch that requires a
>   re-clone, or slot removal — must be confirmed: interactively a `y/n`, and in a
>   non-interactive run it requires an explicit flag (`--force`) or it **aborts**
>   rather than silently deleting an expensive resource.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-022#DESTRUCTIVE-CONFIRM>

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

[p40] Смена группы или имени пакета создаёт новый пакет, а не переименовывает старый: версии не переносятся, а старые координаты никогда не используются повторно для другого содержимого.

> [p41] Changing a package's `group` is a new package, not a rename — same discipline as changing `name`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#GROUP-CHANGE-NEW-PACKAGE>

[p42] Пакет документации нельзя установить в проект. `vibe install` отказывает и называет команду, которая вместо этого скачивает его для чтения.

> [p43] `vibe install` MUST refuse a `doc` package with a hint naming the warm-up command; documentation is warmed into the machine store with `vibe cache add` (§11), and the local reader and `vibe explain` read the store.
>
> <spec://org.vibevm.core/vibevm/common/PROP-057#KIND-DOC-NOT-INSTALLED>

[p44] Короткое имя без группы, например `wal`, принимается в командной строке и разрешается через [индекс](../glossary/index.xml#index-registry) [реестра](../glossary/index.xml#registry); это удобство, а манифест всегда записывает полную координату.

> [p45] resolved via the index (§2.6)
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#ROW-SHORT-BEHAVIOUR>

> [p46] `vibe install wal` resolves the collision once, at the top level, and writes `org.vibevm.world/wal` into `[requires]`. Manifests are therefore always qualified — exactly the cargo/npm pattern (`cargo add serde` on the CLI, `serde = "1"` in `Cargo.toml`).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#RESOLVE-ONCE-WRITE-QUALIFIED>

[p47] Разрешить короткое имя можно только через индекс, по одному запросу на реестр; реестр без индекса коротких имён не предлагает, и нужна полная координата. Если лок-файл уже закрепил пакет с таким именем, короткое имя означает закреплённый. Когда два реестра предлагают под одним именем разные пакеты, vibe останавливается с кодом выхода 7 и перечисляет кандидатов, а вы повторяете команду с группой. Префикс вида проверяет результат и никогда не снимает неоднозначность, потому что два пакета разных видов не могут делить координату.

> [p48] **Index dependency.** Resolving a short name requires enumerating candidates `(*, name)` across registries. The host cannot list an org cheaply ([PROP-005 §1](../vibe-index/PROP-005-package-index.xml) — GitVerse exposes no org listing, GitHub is rate-limited). Therefore short-name resolution **requires [PROP-005](../vibe-index/PROP-005-package-index.xml)**: one HTTP GET of `by-name/<name>.json` per registry yields the candidate set. Without an index, a registry's short names are unavailable and the qualified form is required.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#INDEX-DEPENDENCY>

> [p49] **Lockfile is authoritative.** If `vibe.lock` already pins `org.vibevm.world/wal`, a later `vibe install wal` resolves to the locked entry — the short name prefers what is already locked.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#LOCKFILE-AUTHORITATIVE>

> [p50] One candidate → resolve. Multiple candidates with different identity → **collision**:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#COLLISION-BEHAVIOR>

> [p51] A new exit code **`7`** ("ambiguous package") is assigned, distinct from `3` ("package conflict", `VIBEVM-SPEC.md` §9.4).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#EXIT-CODE-7>

> [p52] **kind validation.** If the `kind` prefix is present, after resolution the resolver asserts `resolved.kind == prefix`; mismatch is a `KindMismatch` error. A kind prefix is validation + a UX signal — it does **not** disambiguate, because by §2.2 `name` is unique within a `group`, so `flow:org.vibevm.world/wal` and `feat:org.vibevm.world/wal` cannot co-exist. A short-name collision is always a *group* collision (§2.7), resolved by group-qualification, never by kind.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-registry/PROP-008#KIND-VALIDATION>

