# Расширения и провайдеры {#root}

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

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

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

## Точки и вклады {#points-and-contributions}

[p03] [Жизненный цикл](../glossary/index.xml#lifecycle) открывает именованные *[точки расширения](../glossary/index.xml#extension-point)*, строки вида `family:name`. Семейство `phase:`, группа точек с общим префиксом, — это девять [фаз](../glossary/index.xml#phase). Семейство `slot:` называет места внутри фазы, куда стек или дисциплина ожидает что-то встроить. Семейство `compile:` — собственный конвейер компилятора стартовой полосы, где пакет может преобразовать текст, который прочитает агент. *[Вклад](../glossary/index.xml#contribution)* привязывает [обработчик](../glossary/index.xml#handler) к точке и объявляется в [манифесте](../glossary/index.xml#manifest) таблицей `[[extension]]`, в пакете или в самом проекте.

> [p04] An **extension point** is a string `<family>:<name>`. Three families: **`phase:`** — the default-lifecycle phases and `clean` (project-scoped moments: `phase:build`, `phase:create`, …); **`compile:`** — the compiler's two tiers: the §7.2 staged positions (`compile:source`, `compile:document`, `compile:lane`, `compile:emitted`) and the §7.4 pass tier's single point `compile:pass`, whose position inside the pipeline is carried by the contribution's `pass = { … }` declaration; **`slot:`** — the per-package materialisation moments that already exist as PROP-020 (`slot:pre-install`, `slot:post-install`), re-stated in this vocabulary without changing their semantics, timing, or manifest spelling ([`[hooks]`](../modules/vibe-workspace/PROP-020-install-hooks.xml#manifest) keeps working verbatim; it is now sugar for two `slot:` contributions).
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#POINT-GRAMMAR>

> [p05] A **contribution** binds a handler to a point. It is declared as an `[[extension]]` table — in a **package** manifest (the package ships and offers the behaviour) or in the **project** manifest (the host adds its own). The shape is one grammar for every family:
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#CONTRIB-GRAMMAR>

[p06] У вклада есть идентификатор, он же ключ, по которому проект выключает или заменяет вклад; один обработчик можно привязать несколько раз под разными идентификаторами с разной конфигурацией.

> [p07] Fields: `id` (execution identity — Maven's execution id; also the disable/override key), `point`, `handler` (§6), `config` (free TOML delivered to the handler verbatim — Babel's plugin options), `auto` (§3.3), and optionally `when` (a guard: `kind = "rust-stack"`-style applicability conditions, future work behind this anchor).
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#CONTRIB-FIELDS>

## Пять видов обработчиков {#handlers}

[p08]
| Вид | Что выполняется |
| --- | --- |
| `builtin` | обработчик, вкомпилированный в vibe, например журнал |
| `script` | скрипт оболочки или PowerShell, который поставляет пакет; выбирается по платформе |
| `binary` | программа, которую доставляет пакет и собирает vibe при установке |
| `native` | динамическая библиотека, загружаемая в процесс через C ABI, из точной готовой сборки для платформы |
| `agent` | промпт: работа, переданная агенту-хозяину, или настроенному провайдеру модели, когда vibe запускает человек за терминалом |

> [p09] A contribution's `handler.kind` is one of five. Two wrap machinery that exists; three are new. All five are legal at every `phase:`/`slot:` point; the `compile:` family accepts `builtin` and `native` only (§8.5 explains why).
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#HANDLER-KINDS>

[p10] Каждый обработчик получает один конверт контекста, версионированный JSON-документ, который называет проект, фазу, произведённые к этому моменту артефакты и конфигурацию вклада, и отвечает конвертом ответа, который может объявить новые артефакты. Конверт — это то, как фазы говорят друг с другом.

> [p11] Every handler, in every family, receives one **context envelope** — a versioned JSON document (the wire form for `script`/`binary`/`native` handlers; builtin handlers get the same data as a Rust struct; agent handlers get its prose projection). Modelled on what Maven hands a Mojo — MavenProject, MavenSession, MojoExecution, per-parameter configuration — translated to our world and extended with what the owner predicted: «в стадии будет попадать много больше, чем их просто название».
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#ENVELOPE-LAW>

[p12] Нативный обработчик — динамическая библиотека ровно с четырьмя символами C; запрос и ответ пересекают эту границу как версионированный JSON, по одному семейству на библиотеку, а крейт `vibe-ext` даёт автору безопасные макросы, чтобы ни один `unsafe` не писался руками. Обработчик с закрытым исходным кодом поставляется готовой сборкой для каждой платформы; точная готовая сборка побеждает, объявленный исходник может собраться вместо неё, а отсутствие — отказ, а не пропуск. Преобразование `compile:` выполняется внутри регенерации полосы, поэтому им может быть только builtin или допущенный нативный обработчик, никогда скрипт, бинарник или агент. Вклад, которому нужен низкоуровневый ярус проходов, говорит об этом флагом `compiler_internals = true`, и ему всё равно нужна активация со стороны хозяина.

> [p13] A native handler is a **cdylib** exposing exactly four ABI-1 C symbols: `vibe_ext_abi`, `vibe_ext_manifest`, `vibe_ext_invoke`, and `vibe_ext_free`. The Rust ABI is never the wire; versioned JSON request/reply roots carry lifecycle, compiler or mechanism-family values, one family per image. ABI/manifest admission precedes invoke, replies are bounded, plugin panic is contained, and the host frees owned reply memory exactly once. Evidence: `fd81a003`, `bfaea140`, `9f7b8854`, `ed6e7c2a`, `9465291e`, `24b1fe4a`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#C-ABI-LAW>

> [p14] `vibe-ext` publishes safe lifecycle, compiler and mechanism-family author macros over the same four ABI-1 symbols; one cdylib belongs to one family. Authors never touch `unsafe`. Evidence begins at `bfaea140` and extends through `24b1fe4a`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#ABI-CRATE>

> [p15] **Closed-source plugins ship prebuilt.** The exact current-platform prebuilt wins; otherwise declared source may build under the provider root, and absence refuses rather than skipping. Prebuilt bytes are ordinary package content and both paths enter the same record, immutable-image, ABI/schema and loader admission laws. Platform projection occurs before build/load. Evidence: `1baac652`, `269bec0d`, `bb50aeab`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#PREBUILT-CLOSED>

> [p16] A `compile:` transform runs inside lane regeneration, potentially per document. Script/binary spawn and agent nondeterminism are therefore forbidden: compiler contributions execute only as `builtin` or admitted `native` handlers. R5/R6 retain this closed production dispatch.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#COMPILE-NATIVE-ONLY>

> [p17] A contribution enters the pass tier by declaring **`compiler_internals = true`** on its `[[extension]]` table — the owner-mandated flag, a single conspicuous boolean whose presence means "this plugin asked for the low-level API". Without it, `pass = …` is a validation error. With it: **host activation is always required**; the activated pass list and positions bind the generated artifact header and freshness; and narration names each internals plugin. Grammar and refusal landed in `b2a6efb5`; retained owner-plan carriage landed through `cf51582a`.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#COMPILER-INTERNALS-FLAG>

## Как включить вклады {#activation}

[p18] Установить пакет — значит согласиться на выполнение его вкладов: вклады зависимости в фазы и слоты активны, как только пакет установлен. Манифест потребителя может активировать вклад, который не включается сам, выключить вклад по идентификатору или [переопределить](../glossary/index.xml#override) его конфигурацию. Диалогов согласия во время выполнения нет; вместо них полная прозрачность.

> [p19] **Host activation and override.** The consuming manifest activates a dependency's non-auto contribution, or re-configures an auto one, by reference: `[[extensions.use]] ref = "org.vibevm.x/y#xml-squeeze"` with optional `config` override; `[extensions] disable = ["org.vibevm.x/y#announce"]` turns any contribution off. The plural `extensions` namespace is the host-control surface; singular `[[extension]]` remains only the declaration table nested in the manifest that provides the contribution. The reference key is `<group>/<name>#<id>` — stable, printable, greppable.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#HOST-ACTIVATION>

> [p20] **The owner's trade (2026-08-25): no consent dialogs, total transparency instead** — debuggers, scanners, and internals specialists must be able to see instantly what the extension machine is doing. Observability is therefore a REQUIREMENT of the machine, specified with it, not a later courtesy:
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#OBS-LAW>

[p21] Внутри одной точки вклады выполняются в фиксированном порядке: сначала встроенные привязки действующего пресета, затем вклады пакетов в порядке зависимостей, затем собственные вклады проекта; порядок выводится, а не обсуждается.

> [p22] Within one extension point, contributions run in this order: **(1)** built-in bindings of the effective kind-preset (§4.5) — Maven's «packaging first»; **(2)** dependency-declared contributions, in lockfile package order (deterministic, no filesystem enumeration), then declaration order within a package; **(3)** host-manifest contributions and `[[extensions.use]]` activations, in declaration order. First-to-last, no reversals anywhere — one rule a user can hold in their head, against Babel's plugins-vs-presets special case (`##NOT-FROM-BABEL`).
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#ORDER-LAW>

## Как увидеть, что выполнилось {#seeing}

[p23] `vibe extensions` перечисляет каждый объявленный вклад в установленном мире с его точкой, обработчиком и происхождением; `--json` отдаёт то же сканеру. Всё, что вклад может сделать, объявлено, так что сканеру не нужно ничего выполнять, чтобы проверить проект. Каждый прогон перед стартом печатает вклады, которые выполнит, а сам прогон можно проследить проход за проходом флагом `--trace-compile` в `.vibe/trace/`.

> [p24] **The extension registry is a query surface:** `vibe extensions` (with `--json`) lists every declared contribution in the installed world — id, point, handler kind, providing package and version, config, `compiler_internals` flag, auto/host-activated state, disabled state, and for natives the artifact path + build state + content hash. One command answers "what runs on my project and who brought it". `vibe list`/`show` mark internals-bearing packages, as §7.4.3 already requires.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#OBS-REGISTRY>

> [p25] **Lifecycle-owned compilation is traceable, LLVM-style:** the landed R3.4 surface is direct `install`, every default phase/chain, `update` and `reinstall`; compile sites owned by `init`, publish staging and uninstall remain explicitly outside this epoch until they gain their own command-owned JTD report boundary. On the landed surface, `--trace-compile` (or selected-manifest `[compile] trace = true`) attempts to certify the compiler's generated JTD IR after every successful pass while the run budget and writer permit, the `-print-after-all` genre, and aggregates every pass outcome/timing, the `-time-passes` genre. The index records why a snapshot is absent (`snapshot-skipped-budget`, `snapshot-failed`, or pass/verifier failure), so observer refusal never becomes compiler failure. One project run lives under `.vibe/trace/<run>/`: `index.json` is the generated authority, while certified snapshots use a reversible Windows-safe name carrying the global sequence, encoded pass, scope kind, encoded scope label, encoded artifact id and occurrence ordinal; exact scope/attempt identity remains in the event→scope relation in the index. A name beyond the physical cap uses a digest suffix whose full identity remains in the index. Thus two parse documents, package units and node artifacts cannot collide, and adjacent certified snapshots answer “what did THIS pass change?” without a trace-only IR dialect.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#OBS-TRACE>

[p26] `vibe tools` перечисляет бинарники и серверы, которые принесли установленные пакеты; это [реестр](../glossary/index.xml#registry) того, что может назвать вклад вида `binary`.

[p27] Example `tools` is copied from the source page at projection time.

## Провайдеры {#providers}

[p28] Вкладу вида `agent` нужен кто-то, кто выполнит его промпт. Под агентом-хозяином vibe откладывает задачу для этого агента и продолжает, когда объявленные результаты появились. За терминалом vibe может вызвать настроенного провайдера модели, и первый из них — любая конечная точка, совместимая с OpenAI; учётные данные провайдера он читает только тогда, когда несвежий агентный шаг действительно доходит до вызова. Каждая функция, которую улучшает модель, объявляет, выключена ли она, помогает или обязательна, и по умолчанию она выключена.

> [p29] The first provider id is exactly `openai-compatible`: synchronous object-safe `LLMProvider::chat`, generated epoch-1 Chat request/response, blocking bounded transport and provider-independent usage. User config owns provider/model/endpoint/token-file; selected project `[llm]` owns default provider/model and an optional credential env source. Project provider/model win independently; endpoint remains operator-owned. A nonempty project env source wins over a token file and fails honestly when absent. Keyed traffic requires HTTPS; keyless HTTP is literal loopback only; redirects are disabled, loopback bypasses ambient proxies, response bodies/timeouts are bounded, and keys/query/body/raw provider responses never enter diagnostics.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#AGENT-PROVIDER-SEAM>

> [p30] Each genuinely LLM-enhanceable feature declares `off | assist | required`; an undeclared enhancement mode is `off`. `off` runs only the algorithmic implementation. `assist` may call the configured provider and falls back to the algorithmic result with a visible degradation record on unavailable/failure. `required` is an explicit operator choice and fails with remediation when the paid enhancement cannot run. The existence of `required` never permits removal of the subsystem's algorithmic mode. A pure `handler = { kind = "agent" }` contribution is a separately declared agent workload, not an enhancement mode: once activated, its absence would be a silent skip and `##AGENT-CLI`/`##AGENT-HANDSHAKE` govern it.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#LLM-ENHANCEMENT-MODES>

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

[p31] Вклад может нести селектор, который ограничивает его подходящими файлами или целями, так что форматер привязывается к исходникам одного языка, а не ко всему дереву.

> [p32] **Selectors** (the Webpack loader `test`-rule genre, 2026-08-25 audit): a contribution may carry `applies_to = { packages = ["org.x/*"], paths = ["vibevm/vibespecs/prompts/**"] }` — declarative include/exclude scoping evaluated by the ENGINE, so a per-document transform (tier-1 `compile:source`/`document`) or a per-slot moment runs only where declared, visible to §3.5's registry, instead of every plugin re-implementing filtering privately in `config`. Absent selector = applies everywhere its point fires, today's behaviour.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#CONTRIB-SELECTOR>

[p33] Нативный обработчик пересекает границу из C и JSON, а не Rust ABI, так что библиотека, собранная другой версией тулчейна, всё равно загружается.

> [p34] 8.1 The ABI is C + JSON, never the Rust ABI
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#why-c-abi>

[p35] У включённой работы модели есть потолки на прогон по числу вызовов и токенов; шаг, который их превысил бы, останавливается, а не тратит.

> [p36] Each enabled enhancement or explicit agent workload carries per-run call, input-token and output-token ceilings. Narration names feature/contribution, mode, provider/model, reason, cache posture and ceilings before spend without exposing secrets. Completed state records provider-reported usage. Exceeding a ceiling follows the selected contract: `assist` falls back; `required` or an explicit agent workload fails. Exact default ceilings and manifest grammar land with the first enhancement that consumes them; no global create budget exists.
>
> <spec://org.vibevm.core/vibevm/common/PROP-054#LLM-BUDGET>

