<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">Extensions and providers</title>
  <status stage="doc" state="work" audience="user,author"/>
  <p p="1">A package can plug into the build: run a step, transform a stage, or hand a task to an agent. This page explains how such plug-ins are declared, how a project turns them on, and how to see which ones ran and why.</p>
  <example id="extensions" fixture="hello-vibe" p="2">
    <run>vibe extensions --path hello-vibe</run>
    <expect>Extensions
  → [0] @vibe/package/skill/org.vibevm.world/wal/wal-status — point=phase:package handler=builtin provider=org.vibevm.world/wal@1.0.0 tier=preset state=effective
1 extension declaration(s), 1 effective</expect>
  </example>
  <section id="points-and-contributions" title="Points and contributions">
    <p p="3">The [lifecycle](../glossary/index.xml#lifecycle) exposes named *[extension points](../glossary/index.xml#extension-point)*, strings of the form `family:name`. The `phase:` family, the group of points that share one prefix, is the nine [phases](../glossary/index.xml#phase). The `slot:` family names places inside a phase where a stack or a discipline expects to plug something. The `compile:` family is the boot compiler's own pipeline, where a package may transform the text an agent will read. A *[contribution](../glossary/index.xml#contribution)* binds a [handler](../glossary/index.xml#handler) to a point and is declared in a [manifest](../glossary/index.xml#manifest) as an `[[extension]]` table, in a package or in the project itself.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#POINT-GRAMMAR" p="4"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#CONTRIB-GRAMMAR" p="5"/>
    <p p="6">A contribution carries an id, which is also the key a project uses to disable or replace it; the same handler may be bound several times under different ids with different configuration.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#CONTRIB-FIELDS" p="7"/>
  </section>
  <section id="handlers" title="Five kinds of handler">
    <table p="8">
      <tr>
        <td>Kind</td>
        <td>What runs</td>
      </tr>
      <tr>
        <td>`builtin`</td>
        <td>a handler compiled into vibe, such as a logger</td>
      </tr>
      <tr>
        <td>`script`</td>
        <td>a shell or PowerShell script shipped by the package, resolved by platform</td>
      </tr>
      <tr>
        <td>`binary`</td>
        <td>a program the package delivers and vibe builds on install</td>
      </tr>
      <tr>
        <td>`native`</td>
        <td>a dynamic library loaded in process through a C ABI, from an exact prebuilt for the platform</td>
      </tr>
      <tr>
        <td>`agent`</td>
        <td>a prompt: work handed to the hosting agent, or to a configured model provider when a person runs vibe at a terminal</td>
      </tr>
    </table>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#HANDLER-KINDS" p="9"/>
    <p p="10">Every handler receives one context envelope, a versioned JSON document that names the project, the phase, the artifacts produced so far and the configuration of the contribution, and answers with a reply envelope that may declare new artifacts. The envelope is how phases talk to each other.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#ENVELOPE-LAW" p="11"/>
    <p p="12">A native handler is a dynamic library with exactly four C symbols; the request and the reply cross that boundary as versioned JSON, one family per library, and the `vibe-ext` crate gives an author safe macros so that no `unsafe` is ever written by hand. A closed-source handler ships prebuilt for each platform; the exact prebuilt wins, declared source may build instead, and absence refuses rather than skips. A `compile:` transform runs inside lane regeneration, so it may only be a builtin or an admitted native handler, never a script, a binary or an agent. A contribution that wants the low-level pass tier says so with `compiler_internals = true`, and then still needs the host's activation.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#C-ABI-LAW" p="13"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#ABI-CRATE" p="14"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#PREBUILT-CLOSED" p="15"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#COMPILE-NATIVE-ONLY" p="16"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#COMPILER-INTERNALS-FLAG" p="17"/>
  </section>
  <section id="activation" title="Switching contributions on">
    <p p="18">Installing a package is the consent to run its contributions: a dependency's phase and slot contributions are active as soon as the package is installed. The consuming manifest can activate a contribution that is not automatic, disable one by its id, or [override](../glossary/index.xml#override) its configuration. There are no consent dialogs at run time; there is total transparency instead.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#HOST-ACTIVATION" p="19"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#OBS-LAW" p="20"/>
    <p p="21">Within one point, contributions run in a fixed order: the built-in bindings of the effective preset first, then the packages' contributions in dependency order, then the project's own; the order is derived, never negotiated.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#ORDER-LAW" p="22"/>
  </section>
  <section id="seeing" title="Seeing what ran">
    <p p="23">`vibe extensions` lists every declared contribution in the installed world with its point, handler and origin; `--json` gives the same to a scanner. Everything a contribution can do is declared, so a scanner needs no execution to audit a project. Every run prints the contributions it will execute before it starts, and a run can be traced pass by pass with `--trace-compile` into `.vibe/trace/`.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#OBS-REGISTRY" p="24"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#OBS-TRACE" p="25"/>
    <p p="26">`vibe tools` lists the binaries and servers the installed packages brought, which is the [registry](../glossary/index.xml#registry) of what a contribution of kind `binary` may name.</p>
    <example id="tools" fixture="hello-vibe-cwd" p="27">
      <run>vibe tools</run>
      <expect>vibe tools: nothing installed declares a binary or an MCP server</expect>
    </example>
  </section>
  <section id="providers" title="Providers">
    <p p="28">A contribution of kind `agent` needs someone to run its prompt. Under an agent host, vibe parks the task for that agent and resumes when the declared outputs exist. At a terminal, vibe can call a configured model provider, the first one being any OpenAI-compatible endpoint, and it reads the provider's credentials only when a non-fresh agent step actually reaches the point of calling it. Every model-enhanced feature declares whether it is off, assisting or required, and off is the default.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#AGENT-PROVIDER-SEAM" p="29"/>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#LLM-ENHANCEMENT-MODES" p="30"/>
  </section>
  <section id="edge-cases" title="Edge cases and rules">
    <p p="31">A contribution may carry a selector that limits it to matching files or targets, so a formatter binds to one language's sources and not to the rest of the tree.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#CONTRIB-SELECTOR" p="32"/>
    <p p="33">A native handler crosses a C-and-JSON boundary, never the Rust ABI, so a library built by another toolchain version still loads.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#why-c-abi" p="34"/>
    <p p="35">Enabled model work carries per-run ceilings on calls and tokens; a step that would exceed them stops rather than spends.</p>
    <rule ref="spec://org.vibevm.core/vibevm/common/PROP-054#LLM-BUDGET" p="36"/>
  </section>
</spec>
