# Plugin Component Model migration

Yoi's current Plugin Tool runtime uses a narrow core-WebAssembly ABI. That was the right MVP shape because it made sandboxing, bounded input/output, and fail-closed host imports explicit. It should not become the long-term authoring interface.

The preferred direction is to adopt the WebAssembly Component Model for Plugin Tool authoring and host APIs. Component Model adoption means Plugin interfaces are described as typed WIT worlds and lowered through the canonical ABI, instead of every Plugin author or SDK wrapper hand-writing pointer/length memory plumbing.

## What Component Model changes

A core Wasm module exposes low-level functions and memory. Yoi's current Plugin Tool ABI is shaped like this:

```text
export memory
export yoi_tool_call() -> i32
import yoi:tool/tool_name_len() -> i32
import yoi:tool/tool_name_read(ptr, len) -> i32
import yoi:tool/input_len() -> i32
import yoi:tool/input_read(ptr, len) -> i32
import yoi:tool/output_write(ptr, len) -> i32
```

This is small and auditable, but it makes raw ABI details part of the authoring model. A Component Model world can instead describe a typed contract:

```wit
package yoi:plugin;

interface tool {
  record request {
    tool-name: string,
    input-json: string,
  }

  record response {
    output-json: string,
  }

  variant tool-error {
    invalid-input(string),
    denied(string),
    failed(string),
  }

  run: func(req: request) -> result<response, tool-error>;
}

world tool-plugin {
  export tool;
}
```

The exact WIT is still design work, but the important boundary is fixed: the Plugin author sees typed values and generated bindings; the host sees typed imports/exports; Yoi still enforces package enablement and Plugin grants outside the component.

## External patterns considered

Common Wasm extension systems normally ship more than a runtime:

- Extism-style systems provide host runtimes plus language PDKs. Plugin authors write normal typed functions while the PDK hides the raw ABI and host functions remain explicit.
- Spin-style systems combine a manifest, language SDK/templates, default-deny outbound/file capabilities, and Wasm components.
- wasmCloud-style systems separate components from capability providers and connect them through typed interfaces.
- The Component Model standardizes the interface layer with WIT and canonical ABI so host APIs can be versioned and bindings generated across languages.

The shared lesson is that a usable Wasm Plugin system needs a manifest, explicit capabilities, generated or hand-written SDK bindings, examples/templates, inspection tooling, and a versioned ABI. Yoi already has the manifest/discovery/enablement/grant/runtime foundation; the missing long-term piece is the typed component authoring interface.

## Yoi policy

Adopting the Component Model must not change Yoi's authority model:

- Package discovery is inventory only and does not register or execute a Plugin.
- Explicit enablement is required before any Tool surface is registered.
- Plugin grants are required before runtime execution and before `https` / `fs` / future host API calls.
- Component imports are not authority by themselves; host-side grant checks remain authoritative.
- Tool calls and Tool results continue through the ordinary ToolRegistry and Worker history path.
- No hidden context injection is introduced by component imports, resources, prompts, or SDK helpers.
- Plugin SDKs and templates are authoring aids, not trust boundaries.

## Migration shape

Yoi should support Component Model as an explicit runtime kind rather than silently changing existing raw-ABI packages.

Possible manifest direction:

```toml
[runtime]
kind = "wasm-component"
component = "plugin.component.wasm"
world = "yoi:plugin/tool@1.0.0"
```

The current raw core-Wasm runtime can remain explicit during migration:

```toml
[runtime]
kind = "wasm"
entry = "plugin.wasm"
abi = "yoi-plugin-wasm-1"
```

The migration should be phased:

1. Define WIT packages/worlds for Tool Plugin and initial host APIs.
2. Add manifest/schema support for `runtime.kind = "wasm-component"` without executing it during discovery.
3. Add a component runtime backend and typed host import/export binding.
4. Port `https` and `fs` host API designs to WIT-compatible interfaces.
5. Add a Rust authoring SDK/template around the component world.
6. Decide whether the raw ABI remains supported, becomes legacy-only, or is deprecated after examples and tests move.

## Runtime/backend caution

The current implementation uses `wasmi` for core Wasm. Component Model support will likely require a different backend or a significantly richer component adapter path, such as `wasmtime::component` plus generated bindings. That has consequences for binary size, Nix packaging, build time, runtime limits, and sandbox policy. The migration Ticket must measure and validate those effects explicitly.

If a component backend is added, keep it selected by package runtime metadata and Profile/feature policy. Do not make all Plugin packages depend on component execution during discovery or inspection.

## Relationship to pending host APIs

`https` and `fs` host API Tickets should avoid baking in raw pointer/length interfaces as the long-term authoring contract. If they land before the component runtime, implement them in a way that can be represented as WIT records/results later, and document raw ABI wrappers as transitional.

For example, `https` should be modeled as typed request/response data with explicit grant checks for host/method/path/body bounds. `fs` should be modeled as scoped read/list/write operations with path normalization and root-escape rejection. Those concepts translate well to WIT.

## Non-goals

- Component Model adoption does not imply WASI filesystem/network access.
- It does not replace Plugin grants with WIT imports.
- It does not introduce Service, Ingress, WebSocket, or inbound HTTP by itself.
- It does not merge Plugin and MCP. MCP remains a separate untrusted tool/resource/prompt bridge with its own policy.
