# Поставляйте инструменты и MCP-серверы {#root}

@status:doc/work @audience:author

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

[p02]
```prompt
В текущем проекте VibeVM создай пакет инструментов org.acme/notes-tools как пакет в дереве с маленьким Rust-крейтом crates/notes-check внутри, объяви крейт бинарником с именем notes-check, установи пакет в проект, собери инструмент через vibe и запусти его через vibe bin exec с --help, чтобы доказать, что диспетчеризация работает.
```

- needs: навык vibevm, установленный у вашего агента; пакет с Cargo-workspace в корне и бинарным крейтом; тулчейн Rust в `PATH`

outcome: манифест несёт таблицу `[[binary]]`; `vibe bin list` показывает инструмент; `vibe bin build` произвёл его в собственной папке target пакета; `vibe bin exec notes-check -- --help` печатает справку инструмента

- assert: `vibe bin list`
- assert: `vibe bin exec notes-check -- --help`

## Что происходит {#what-happens}

[p03] Агент размечает слот пакета через `vibe init package`, кладёт внутрь крейт, добавляет таблицу `[[binary]]` с именем инструмента и папкой крейта и ставит пакет в проект из собственного [реестра](../glossary/index.xml#registry) проекта. Он выполняет `vibe bin build`: команда спрашивает согласия и делает release-сборку внутри собственного workspace пакета. Затем он выполняет `vibe bin exec`: команда разрешает инструмент через [лок-файл](../glossary/index.xml#lock-file) проекта до артефакта ровно той версии, что установлена, и запускает его. Потребители получают то же: установка пакета материализует его исходник, сборка при первом использовании производит инструмент рядом с ним, и артефакт никогда не попадает в [отпечаток](../glossary/index.xml#fingerprint) пакета.

> [p04] MUST: a package declares its binaries; vibe builds and
>   dispatches them.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#BINARY-MUST>

> [p05] Build output sits outside the shippable tree (PROP-024 §2.2), so content
>   hashes never move.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#HASHES-STABLE>

## Код в пакете {#code-in-a-package}

[p06] Пакет — это проект, который сделали устанавливаемым, поэтому он может нести произвольный код в корне рядом с `vibevm/vibespecs/`: Cargo-workspace, крейты, тесты. Поставляемое дерево — исходник минус результаты сборки; `target/`, `node_modules/` и всё из `.vibeignore` никуда не едут. Потребители получают исходник и собирают его сами, и потому идентичность остаётся свойством того, что закоммитил автор.

> [p07] **The package root holds arbitrary code** (e.g. `Cargo.toml` + `crates/`) and
>   `vibe.toml`, exactly as a project root does. Code is optional — a prompt-only
>   package (e.g. `discipline-core`) simply has no code at its root.
>
> <spec://org.vibevm.core/vibevm/common/PROP-024#ROOT-CODE>

> [p08] **Why.** Identity is the *source*, never build artifacts: build output is
>   non-deterministic (timestamps, host paths, incremental state) and may be
>   gigabytes — hashing or copying it would make identity unstable and
>   materialisation ruinous, the exact failure PROP-022 §1.1 names for "big in file
>   count".
>
> <spec://org.vibevm.core/vibevm/common/PROP-024#WHY-SOURCE-IDENTITY>

[p09] Пакет с кодом держит собственный [манифест](../glossary/index.xml#manifest) workspace, а потребитель, который сам Rust-проект, исключает дерево зависимостей из своего workspace, чтобы две сборки никогда не столкнулись.

> [p10] **Decision.** A code-bearing package carries its **own** workspace manifest
>   (for Rust, a root `Cargo.toml` with `[workspace]`) — it is a standalone,
>   independently-buildable project.
>
> <spec://org.vibevm.core/vibevm/common/PROP-024#OWN-WORKSPACE>

## Бинарники {#binaries}

[p11] Каждый инструмент — одна запись `[[binary]]`: `name`, уникальное в пакете, и `crate`, папка внутри поставляемого дерева с `Cargo.toml`. `vibe bin list` показывает, что объявляют установленные пакеты, `vibe bin build` собирает названные инструменты или все, `vibe bin path` печатает расположение артефакта, а `vibe bin exec <name> -- <args>` запускает его через лок-файл. Сборка выполняет скрипты сборки пакета, поэтому в первый раз она спрашивает согласия, как установка.

> [p12] A code-bearing package declares each shipped tool in its `vibe.toml`:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#BINARY-TABLE>

> [p13] **Successor to the historical first-build prompt.** Building executes package build scripts and proc-macros, so installation plus explicit target/route selection is the authorisation and the engine narrates the exact provider and target before execution. Lifecycle build does not add an allow-list, first-run prompt or `--allow-hooks` analogue; provider identity, artifact records and outcomes supply the audit trail. Existing direct `vibe bin` compatibility remains routed through its declared package rather than silently choosing ambient code.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#BUILD-CONSENT>

[p14] `name` уникально внутри пакета и должно быть защищено от столкновений между пакетами, что бесплатно даёт префикс [семейства](../glossary/index.xml#family). `crate` называет папку внутри поставляемого дерева с Cargo-пакетом, чей бинарник называется ровно `name`.

> [p15] Constraints: `name` MUST be unique within the package and SHOULD be
>   globally collision-safe (the family-prefix convention, PROP-028 §2.4).
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#NAME-CONSTRAINTS>

> [p16] `crate` MUST name a directory inside the shippable tree carrying a
>   `[[bin]]`-bearing (or default-bin) Cargo package whose bin name equals
>   `name`.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#CRATE-CONSTRAINT>

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

## MCP-серверы {#servers}

[p18] Пакет вида `mcp` доставляет сервер, с которым говорит агент: одну или несколько таблиц `[[mcp_server]]`, каждая называет бинарник, который его обслуживает, и его аргументы. Сервер собирается как любой бинарник и регистрируется в конфигурациях агентов командой `vibe mcp install` рядом с собственным сервером vibe. Собранный, он работает без vibe: агент запускает артефакт напрямую.

> [p19] An **`mcp` package** is one whose primary deliverable is one or more
> Model Context Protocol servers.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#MCP-KIND-DEF>

> [p20] An mcp package's servers run without vibe: the artifact is launched by
>   the agent host directly from the slot path, links its vendored engines,
>   and speaks stdio MCP.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#VIBE-FREE-SERVING>

[p21] Сервер, который обслуживает тулчейн другого пакета, например ворота языковой дисциплины, обязан требовать этот пакет точным пином, `=X.Y.Z`. Движки за инструментами агента и ворота, которые запускает потребитель, должны разрешаться в один набор версий: один движок, одна истина, и обеспечивает это резолвер, а не протокол.

> [p22] The pin closes it: **every
>   `[requires.packages]` entry of an `mcp`-kind package MUST be an exact
>   `=X.Y.Z` requirement** — the resolver holds the served engines and the
>   consumer's gates to ONE version set; no runtime handshake exists or is
>   needed.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#EXACT-PIN-LAW>

[p23] Вид обещает сервер: манифест `mcp` без таблицы `[[mcp_server]]` отвергается. Сервер — один из собственных бинарников пакета, поэтому `binary` обязан назвать `[[binary]]` того же манифеста, а его доставка, согласие и устаревание следуют механике бинарников. В `args` единственная подстановка — `{project_root}`, разрешаемая при регистрации; неизвестный токен отвергается.

> [p24] An
>   `mcp`-kind manifest that declares NO `[[mcp_server]]` is refused: the
>   kind promises a server.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#KIND-PROMISES-SERVER>

> [p25] The server IS a [PROP-025](../vibe-workspace/PROP-025-binary-delivery.xml)
>   binary: delivery, consent, staleness, and slot residence come from that
>   machinery wholesale — `binary` must resolve to a `[[binary]]` declared
>   in the same manifest.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#SERVER-IS-BINARY>

> [p26] `args` may carry
>   substitution tokens ONLY from the closed set `{project_root}` (the
>   absolute, verbatim-free root of the consuming project, resolved at
>   registration time); unknown `{…}` tokens are refused at validation.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#ARGS-CLOSED-SET>

## Установочные хуки {#hooks}

[p27] Пакет может выполнить скрипт при установке. `[hooks]` называет базовый путь без расширения, а пакет поставляет `<base>.sh`, `<base>.ps1` или оба; раннер выбирает подходящий хосту. `pre-install` выполняется, как только папка пакета готова, и до того, как vibe ею воспользуется; `post-install` выполняется после того, как установка стала долговечной, с записанным локом и перегенерированными стартовыми файлами. Рабочая папка — собственная папка пакета в дереве зависимостей, а окружение называет группу, имя, версию, вид и папку пакета и который из двух моментов сейчас. Правки [хука](../glossary/index.xml#hook) в файлах, которыми владеет vibe, эфемерны: переустановка или обновление восстанавливает эти байты и выполняет хук снова.

> [p28] The value is a **base path without extension**; the runner resolves `.sh` /
>   `.ps1` beside it per §2.2.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#BASE-PATH-VALUE>

> [p29] A package ships a phase script as `<base>.sh` (portable, POSIX shell) and/or
> `<base>.ps1` (PowerShell). The runner picks per host:
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#SCRIPT-FORMS>

> [p30] **`pre-install`** — runs immediately after the package's slot is fully
>   populated (content materialised, submodules fetched per
>   [PROP-021](../vibe-registry/PROP-021-submodule-sources.xml)) and **before**
>   vibevm uses the slot (before boot regeneration, before any later
>   `vibe skill` projection reads it). This is the "bring the tree into order"
>   hook.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#PHASE-PRE-INSTALL>

> [p31] **`post-install`** — runs after the install run is durable for that package
>   (lockfile written, boot artefacts regenerated). For finalisation that needs
>   the package already registered.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#PHASE-POST-INSTALL>

> [p32] The hook's **working directory is the package's materialised slot**; it sees
> exactly the tree vibevm will use.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#CWD-IS-SLOT>

> [p33] The runner passes a documented environment: `VIBE_PACKAGE_GROUP`,
>   `VIBE_PACKAGE_NAME`, `VIBE_PACKAGE_VERSION`, `VIBE_PACKAGE_KIND`,
>   `VIBE_PACKAGE_DIR` (the slot, also CWD), `VIBE_HOOK_PHASE`.
>   ([PROP-024 §2.3](../../common/PROP-024-code-bearing-packages.xml#build) adds
>   `VIBE_PROJECT_ROOT`, the workspace absolute root, so a build hook can target a
>   gitignored build dir *outside* the slot; it lands with that work.)
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#HOOK-ENV>

> [p34] Only a hook's edits
>   to materialiser-owned recorded payload are ephemeral: reinstall, update or
>   integrity repair restores those bytes per
>   [PROP-022](PROP-022-materialization-modes.xml), then reruns hooks exactly
>   when that payload diff is nonempty. Hook-created unrecorded state is outside
>   `.vibe-slot.toml` ownership and survives by design; a rerun may compound it,
>   so hooks must be idempotent until a separate hook-output ownership contract
>   exists.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-020#EFFECTS-EPHEMERAL>

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

[p35] Артефакт инструмента принадлежит ровно той версии, что установлена; после обновления старому артефакту не доверяют, и следующий `vibe bin exec` сначала собирает новую версию.

> [p36] Current-slot existence alone is not trust. The selected artifact must belong to the current resolved provider root and pass the shared record's exact source/config/platform/provider/output-path/digest revalidation. A same-slot refresh preserves unrecorded build output; a version change moves current-root identity and cannot reuse the old slot's record.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#TRUST-CURRENT-SLOT>

[p37] Для сборки нужны собственные источники пакетов языка, для Rust — crates.io, если они не вендорены; офлайн-сборка говорит об этом, а не притворяется.

> [p38] Cargo needs crates.io for third-party deps unless the
>   local cargo cache is warm: offline boxes get the same honest failure
>   cargo gives, plus the hint that `cargo install --path <slot>/crates/…`
>   (the documented degraded path, which stays valid indefinitely) has the
>   same network shape — there is no offline shortcut to a first build.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-workspace/PROP-025#OFFLINE-HONESTY>

[p39] Таблица `[[mcp_server]]` законна только в пакетах вида `mcp`; пакет `tool` поставляет бинарники, но не серверы.

> [p40] The
>   `[[mcp_server]]` table (§2.2) is **legal only in this kind** — the kind
>   IS the taxonomy, enforced by `Manifest::validate`, not advisory.
>
> <spec://org.vibevm.core/vibevm/modules/vibe-mcp/PROP-027#TABLE-ONLY-IN-KIND>

[p41] `.vibeignore` в корне пакета добавляет глобы к списку результатов сборки, которые никогда не попадают в поставляемое дерево.

> [p42] **Optional `.vibeignore`** at the package root — newline-delimited globs added
>   to the §2.2 build-output denylist.
>
> <spec://org.vibevm.core/vibevm/common/PROP-024#SURF-VIBEIGNORE>

