Merge remote-tracking branch 'refs/remotes/origin/develop' into work/T-468-remove-local-workspace-authority
This commit is contained in:
@@ -1,177 +1,29 @@
|
||||
# Plugin Component Model migration
|
||||
# Plugin Component Model boundary
|
||||
|
||||
Yoi's original Plugin Tool runtime used a narrow core-WebAssembly ABI. That was the right MVP shape because it made sandboxing, bounded input/output, and fail-closed host imports explicit, but it is no longer the public authoring interface.
|
||||
Dynamic Worker Plugin execution is not part of the current product. The `.yoi-plugin` component metadata retained in `manifest` is an offline package-format contract only.
|
||||
|
||||
The supported runtime kind is now `wasm-component`, using 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.
|
||||
## Current behavior
|
||||
|
||||
## What Component Model changes
|
||||
- Worker creation and restore install no dynamic Plugin modules.
|
||||
- Manifest/Profile input rejects `plugins` and `feature.plugins`.
|
||||
- Runtime and Server startup perform no repository, ancestor, cwd, or user-data Plugin discovery.
|
||||
- No persisted local `package_path` is execution authority.
|
||||
- Only statically compiled trusted built-in Features contribute Worker capabilities.
|
||||
- `yoi plugin check` parses an explicitly named directory or package without instantiating a component.
|
||||
|
||||
A core Wasm module exposes low-level functions and memory. Yoi's current Plugin Tool ABI is shaped like this:
|
||||
The package validator may reject legacy core-Wasm artifacts and require Component Model metadata, but passing validation does not make an artifact installable or executable.
|
||||
|
||||
```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
|
||||
```
|
||||
## Future platform constraints
|
||||
|
||||
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:
|
||||
A future Server Plugin platform may execute Wasmtime Component Model packages only after the architecture is implemented as a coherent authority boundary:
|
||||
|
||||
```wit
|
||||
package yoi:plugin;
|
||||
1. an operator installs an immutable package into Server-owned artifact authority;
|
||||
2. a Workspace owner selects an installed package through an immutable Addon revision;
|
||||
3. Backend authors a per-Worker execution plan containing exact identities, digests, configuration, and bounded grants;
|
||||
4. Runtime fetches only Server-authorized digests and verifies package bytes and execution-plan identity;
|
||||
5. Runtime instantiates a fresh bounded Wasmtime Store with no ambient WASI authority; and
|
||||
6. restore uses the persisted execution plan and exact artifact rather than current Workspace settings or a filesystem path.
|
||||
|
||||
interface tool {
|
||||
record request {
|
||||
tool-name: string,
|
||||
input-json: string,
|
||||
}
|
||||
Default components receive no filesystem, sockets, environment, clocks, randomness, subprocess, Workdir, broad Workspace client, credential, or network authority. Any host import must be narrow, typed, explicitly granted, live-revalidated where necessary, bounded, and audited.
|
||||
|
||||
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 Engine 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
|
||||
|
||||
`runtime.kind = "wasm-component"` is the sole public Plugin runtime kind. Legacy raw core-Wasm declarations (`kind = "wasm"` / `abi = "yoi-plugin-wasm-1"`) are rejected by manifest validation and are surfaced only as bounded diagnostics; they are not active/eligible Plugins and are not executed.
|
||||
|
||||
The migration is now focused on the component surface:
|
||||
|
||||
1. Keep WIT packages/worlds for Tool Plugin and initial host APIs versioned under `resources/plugin/wit`.
|
||||
2. Keep manifest/schema support centered on `runtime.kind = "wasm-component"`.
|
||||
3. Keep the component runtime backend and typed host import/export binding as the active execution path.
|
||||
4. Port future host API designs to WIT-compatible interfaces.
|
||||
5. Keep the Rust PDK/template aligned with the component world.
|
||||
|
||||
## Runtime/backend caution
|
||||
|
||||
The legacy core-Wasm implementation used `wasmi` as a transitional backend. The active Plugin Tool runtime is now selected by package runtime metadata and executed through `wasmtime::component`; discovery and static inspection must continue to avoid executing package code.
|
||||
|
||||
Keep the component backend 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.
|
||||
|
||||
## Implemented runtime boundary
|
||||
|
||||
Plugin Tool packages now select the runtime explicitly in `plugin.toml`:
|
||||
|
||||
```toml
|
||||
[runtime]
|
||||
kind = "wasm-component"
|
||||
component = "plugin.component.wasm"
|
||||
world = "yoi:plugin/tool@1.0.0"
|
||||
```
|
||||
|
||||
Legacy core-Wasm metadata is accepted only far enough to produce migration diagnostics: package checks and discovery reject `kind = "wasm"` / `abi = "yoi-plugin-wasm-1"`, `list`/`show` report those packages as rejected rather than active/eligible, and the active runtime path does not execute them.
|
||||
|
||||
The component runtime uses `wasmtime::component` and expects the exported world
|
||||
`yoi:plugin/tool@1.0.0` with a `call(tool-name: string, input-json: string) ->
|
||||
string` export. The returned string is the normal ToolOutput JSON, so
|
||||
registration and execution still flow through the existing ToolRegistry and
|
||||
Engine Tool-result history path.
|
||||
|
||||
Host imports are stable names under `yoi:host/*@1.0.0`; the repository WIT files
|
||||
live in `resources/plugin/wit/`. Importing `yoi:host/request@1.0.0` or
|
||||
`yoi:host/fs@1.0.0` is not authority. The runtime checks package grants before
|
||||
component instantiation and checks again on every host call. No WASI filesystem,
|
||||
network, environment, or other ambient imports are linked.
|
||||
|
||||
Static discovery and `yoi plugin list/show` only parse package manifests and
|
||||
reported runtime metadata. They do not instantiate or execute the component.
|
||||
Wrong `world`, missing artifact metadata, missing `call` export, unsupported
|
||||
imports, or core-Wasm bytes in a component package all fail closed with bounded
|
||||
Plugin diagnostics or ordinary Tool errors.
|
||||
|
||||
See `docs/examples/plugin-component-tool/lib.rs` and the embedded
|
||||
`resources/plugin/templates/rust-component-tool/` starter for the preferred
|
||||
Rust PDK authoring path. `yoi-plugin-pdk` is guest-side only: it re-exports
|
||||
`wit-bindgen`, provides typed JSON input/output helpers, renders bounded
|
||||
`ToolError` values as ordinary ToolOutput JSON, and does not depend on host
|
||||
runtime crates or grant authority. Package authors should generate bindings from
|
||||
`resources/plugin/wit`, build a component artifact, and set the component
|
||||
runtime metadata above.
|
||||
|
||||
### v1 request/response shape
|
||||
|
||||
The v1 component world intentionally keeps Tool input, Tool output, and host API
|
||||
payloads as JSON strings. This is a migration bridge that preserves the existing
|
||||
ToolOutput schema, Tool history behavior, grant checks, and raw-Wasm host API
|
||||
semantics while moving package authors onto WIT/canonical ABI bindings.
|
||||
Structured WIT records for Tool requests/responses/errors and host request/FS
|
||||
payloads are deferred to a follow-up API-design step rather than accidentally
|
||||
omitted.
|
||||
|
||||
## Instance lifecycle surface
|
||||
|
||||
The first instance-capable world is `yoi:plugin/instance@1.0.0`. It moves
|
||||
runtime ownership from per-Tool artifact execution to a host-managed
|
||||
`PluginInstance`. The same instance handles Tool, Service, and Ingress surfaces,
|
||||
so Plugin state/config/diagnostics can be shared without bypassing Yoi's normal
|
||||
authority model.
|
||||
|
||||
Important boundaries:
|
||||
|
||||
- Tool calls still enter through `ToolRegistry` and return ordinary `ToolOutput`
|
||||
that is visible in the Engine history path.
|
||||
- Service and Ingress grants are separate from Tool grants. Sharing an instance
|
||||
does not authorize a surface that lacks its own `surface.*` and per-surface
|
||||
permission/grant.
|
||||
- Ingress delivery accepts bounded typed untrusted events and returns explicit
|
||||
JSON to the host. It does not call model Tools or mutate LLM context/history.
|
||||
- Legacy raw-wasm and `yoi:plugin/tool@1.0.0` component packages are adapted
|
||||
behind `PluginInstanceRegistry` for compatibility rather than executed through
|
||||
a separate authority path.
|
||||
- Host APIs such as `https` and `fs` remain independently grant-gated and still
|
||||
reject ambient filesystem/network authority.
|
||||
This future platform must not restore `.yoi/plugins`, user-data catalogs, cwd/ancestor discovery, native dynamic libraries, downloaded Cargo manifests, or local paths as compatibility authority.
|
||||
|
||||
+20
-208
@@ -1,219 +1,31 @@
|
||||
# Plugin packages and discovery
|
||||
# Plugin packages
|
||||
|
||||
Plugin packages are a distribution format, not an authority boundary. A package can be found on disk, inspected, validated, and cached without registering any Hook, exposing any Tool, starting any process, or initializing any WASM module.
|
||||
Yoi retains `.yoi-plugin` as an offline authoring and inspection format. The format is not a Worker capability source.
|
||||
|
||||
The initial goal is a durable `.yoi-plugin` package format that later Tickets can implement in independent layers: discovery, archive validation/cache materialization, manifest/profile enablement, Plugin permission policy, declarative hooks, WASM runtime support, and any future MCP bridge.
|
||||
## Current product boundary
|
||||
|
||||
## Package shape
|
||||
Normal Worker creation, restore, Profile/Manifest resolution, Server/Runtime startup, and CLI execution do not discover Plugin catalogs from:
|
||||
|
||||
A `.yoi-plugin` file is a single-file archive. The archive format is a constrained ZIP profile because it is easy to inspect without executing code and can carry text manifests, WebAssembly Component Model modules, schemas, and license material.
|
||||
- repository or ancestor `.yoi/plugins` directories;
|
||||
- user-data Plugin directories;
|
||||
- the current working directory; or
|
||||
- persisted local `package_path` values.
|
||||
|
||||
The archive root must contain `plugin.toml` directly at the root. Packages should not require a wrapping directory whose name must match the plugin id.
|
||||
`plugins` and `feature.plugins` are rejected in Worker Manifest/Profile input. Dynamic Plugin Tools, Services, Ingress handlers, and WASM components are not installed or executed. Worker capabilities come only from statically compiled trusted built-in Features.
|
||||
|
||||
Recommended root layout:
|
||||
## Offline format operations
|
||||
|
||||
```text
|
||||
plugin.toml # required package manifest
|
||||
plugin.component.wasm # required when plugin.toml declares the component runtime
|
||||
hooks/*.toml # optional declarative hook definitions
|
||||
schemas/*.schema.json # optional JSON schemas for configuration or tool input/output
|
||||
README.md # recommended human description
|
||||
LICENSE* # recommended license text
|
||||
assets/** # optional non-executable data assets
|
||||
The CLI keeps only operations whose input or destination is explicit:
|
||||
|
||||
```sh
|
||||
yoi plugin new rust-component-tool ./example-plugin
|
||||
yoi plugin check ./example-plugin
|
||||
yoi plugin pack ./example-plugin --output ./example-plugin.yoi-plugin
|
||||
yoi plugin check ./example-plugin.yoi-plugin
|
||||
```
|
||||
|
||||
The package layout is intentionally data-first. Placing a package in a store must never execute `module.wasm`, register hook metadata, or scan assets as prompts. Those steps happen only after explicit enablement and policy resolution.
|
||||
These commands parse, validate, or write the named local artifact. They do not scan a Workspace, mutate Profile/Manifest configuration, install a package, register Worker Tools, or execute Plugin code. `plugin list` and `plugin show` were removed because their catalog semantics depended on ambient repository and user-data stores.
|
||||
|
||||
## `plugin.toml`
|
||||
## Future installation authority
|
||||
|
||||
`plugin.toml` is the package authority for package identity and declared needs. It is not the authority for runtime grants.
|
||||
|
||||
Currently implemented strict `plugin.toml` shape:
|
||||
|
||||
```toml
|
||||
schema_version = 1
|
||||
id = "example.summarizer"
|
||||
name = "Example Summarizer"
|
||||
version = "0.1.0"
|
||||
description = "Adds a custom summary command."
|
||||
surfaces = ["hook"]
|
||||
|
||||
[[hooks]]
|
||||
id = "summary"
|
||||
file = "hooks/summary.md"
|
||||
```
|
||||
|
||||
The package archive must contain both root `plugin.toml` and referenced runtime/content entries. Component runtime metadata is explicit and static inspection never executes the artifact:
|
||||
|
||||
```toml
|
||||
[runtime]
|
||||
kind = "wasm-component"
|
||||
component = "plugin.component.wasm"
|
||||
world = "yoi:plugin/tool@1.0.0"
|
||||
```
|
||||
|
||||
`wasm-component` is the public/recommended runtime kind, recorded in [Plugin Component Model migration](plugin-component-model.md). Legacy raw core-Wasm declarations (`kind = "wasm"` / `abi = "yoi-plugin-wasm-1"`) are retired: manifest validation rejects them and CLI inspection reports the package as rejected rather than active/eligible.
|
||||
|
||||
First-pass fields accepted by the parser:
|
||||
|
||||
- `schema_version`: required integer; unsupported versions fail closed.
|
||||
- `id`: required unqualified local id. It is scoped by the source that discovered the package; it is not globally unique by itself.
|
||||
- `name`, `version`, `description`: human metadata used in listings and diagnostics.
|
||||
- `surfaces`: optional declared contribution surface names.
|
||||
- `runtime`: optional component runtime metadata. Discovery records metadata and never executes it; unsupported/retired runtime kinds fail closed.
|
||||
- `hooks`: optional hook metadata. Discovery records metadata and does not register hooks.
|
||||
|
||||
Future descriptor sections such as `[package]`, `[permissions]`, richer `contributions`, or `runtime.kind = "declarative"` are aspirational and are intentionally rejected by the current strict parser until implemented safely.
|
||||
|
||||
The `source` is not read from `plugin.toml`. It is assigned by the store that discovered the package.
|
||||
|
||||
## Stores, sources, and trust
|
||||
|
||||
Discovery should scan explicit stores and attach a source kind to each package:
|
||||
|
||||
- `builtin:<id>`: packages shipped with Yoi or installed as part of the binary distribution.
|
||||
- `user:<id>`: packages discovered under `${XDG_DATA_HOME:-~/.local/share}/yoi/plugins/`.
|
||||
- `project:<id>`: packages discovered under `<workspace>/.yoi/plugins/`.
|
||||
|
||||
Packages under `${XDG_DATA_HOME:-~/.local/share}/yoi/plugins/` or `<workspace>/.yoi/plugins/` are discovery only. Their presence is never permission to register Hooks or Tools, initialize WASM, start processes, open files, use network providers, read secrets, or launch MCP servers.
|
||||
|
||||
Trust differs by source, but none of the sources is self-authorizing:
|
||||
|
||||
- Builtin packages can be trusted as shipped code/data, but still require explicit enablement for a Worker/Profile when they affect runtime behavior.
|
||||
- User packages are local user-installed artifacts and should be visible to workspaces, but they cannot bypass manifest/profile/tool/scope/secret policy.
|
||||
- Project packages are repository-controlled artifacts and should be treated as untrusted until explicitly enabled by local policy. Cloning a repository must not be enough to execute a package.
|
||||
|
||||
## Identity and selector rules
|
||||
|
||||
Runtime identity is source-qualified: `builtin:<id>`, `user:<id>`, and `project:<id>` are distinct plugins even when `<id>` is the same string.
|
||||
|
||||
Durable enablement records should use source-qualified ids. Ambiguous unqualified ids fail closed. The implementation may offer convenience listing or search by bare id, but any operation that enables a package, grants permission, pins a digest, or records restored runtime state should require the fully qualified id.
|
||||
|
||||
Collision handling:
|
||||
|
||||
- Two packages with the same source-qualified id in the same effective store set are a discovery diagnostic and neither candidate is enabled implicitly.
|
||||
- A `user:example` package does not override `builtin:example` unless a future explicit override rule says so.
|
||||
- A `project:example` package does not override `user:example` or `builtin:example` by name alone.
|
||||
|
||||
## Discovery versus enablement
|
||||
|
||||
Discovery is a read-only inventory operation. It may report package metadata, validation errors, source, canonical store path, and deterministic digest. It must not initialize any runtime contribution.
|
||||
|
||||
Enablement is a resolved runtime plan. It should come from Profile/manifest configuration or another explicit local policy layer, then be recorded into the resolved Manifest/session metadata used to start the Worker. Restored Workers should use that resolved enabled-plugin plan instead of silently re-running fresh discovery and picking newer packages. Fresh discovery must not silently upgrade a restored Worker.
|
||||
|
||||
A minimal implemented enablement record is shaped like this. `version` is an exact package-version requirement; richer range constraints are deferred. `digest` is optional in authoring config, but fresh startup records the resolved digest into runtime metadata.
|
||||
|
||||
```toml
|
||||
[[plugins.enabled]]
|
||||
id = "user:example"
|
||||
version = "0.1.0" # optional exact package-version requirement
|
||||
digest = "sha256:..." # optional pin in authoring, resolved in runtime metadata
|
||||
config = { level = "concise" }
|
||||
```
|
||||
|
||||
If no digest is pinned in authoring, fresh startup may resolve the newest acceptable discovered package according to explicit policy. Once a Worker is started, the resolved manifest/session metadata should record the exact source-qualified id and digest so restore is stable.
|
||||
|
||||
## Permissions and grants
|
||||
|
||||
Plugin permission declarations are requests, not grants. Effective grants are the result of Plugin-layer policy combined with existing Yoi authority layers:
|
||||
|
||||
- resolved manifest/profile plugin enablement;
|
||||
- Plugin policy for the source-qualified package id and deterministic digest;
|
||||
- normal tool permission policy;
|
||||
- filesystem scope checks;
|
||||
- web provider enablement and network safety checks;
|
||||
- secret references and secret-store policy;
|
||||
- runtime limits for WASM or other execution engines.
|
||||
|
||||
The Plugin package permission model must not reuse `worker::feature` HostAuthority or grant concepts. The feature layer is an API/contribution substrate; it is not a security boundary for untrusted plugin packages. Plugin grants need their own explicit policy that can fail closed before a Hook, Tool, WASM host function, provider bridge, or external runtime is exposed.
|
||||
|
||||
When a package requests authority outside policy, diagnostics should explain the denied category and package identity without leaking raw secret values, environment contents, full private config, or large plugin-provided text.
|
||||
|
||||
## Archive safety and materialization
|
||||
|
||||
Archive handling should validate before runtime use:
|
||||
|
||||
- Reject absolute paths, `..`, empty segments, Windows drive prefixes, NUL bytes, duplicate normalized paths, and paths that normalize outside the package root.
|
||||
- Reject symlinks, hardlinks, device files, special files, and entries that are not regular files or directories.
|
||||
- Enforce bounded extraction: maximum archive size, maximum expanded size, maximum entry count, maximum per-file size, and a compression-ratio limit.
|
||||
- Validate every manifest-referenced path against the normalized entry set.
|
||||
- Decode text manifests as UTF-8 and bound diagnostic excerpts.
|
||||
- Ignore or normalize archive metadata such as mtimes, owners, groups, and executable bits; these should not affect runtime authority.
|
||||
|
||||
After validation, compute a deterministic digest over the normalized materialized package, not over incidental ZIP ordering or timestamps. A stable digest input should include the format version, normalized relative path, file length, and file content hash for each regular file in sorted order.
|
||||
|
||||
Runtime should materialize packages into a digest-keyed cache, for example:
|
||||
|
||||
```text
|
||||
<cache>/plugins/sha256-<hex>/
|
||||
plugin.toml
|
||||
module.wasm
|
||||
...
|
||||
```
|
||||
|
||||
Initialization should read from the digest-keyed cache, not directly from the mutable user/workspace store. This makes restore, diagnostics, and lock/pin behavior reproducible.
|
||||
|
||||
Optional lock behavior can be added in a later Ticket:
|
||||
|
||||
- an authoring-time pin in Profile/manifest configuration;
|
||||
- a workspace lock file recording source-qualified id, version, source store, digest, and selected package path;
|
||||
- restore metadata that records the actual digest used by the Worker.
|
||||
|
||||
A lock or pin is selection authority, not execution authority. Enablement and grants are still required.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Diagnostics should be safe, bounded, and attributable:
|
||||
|
||||
- Include source-qualified id when available, source kind, validation phase, and digest when computed.
|
||||
- Prefer canonical store-relative paths or redacted absolute paths; avoid dumping large path lists.
|
||||
- Never print raw secret values, provider tokens, environment dumps, or plugin-supplied opaque payloads.
|
||||
- Treat package metadata and README text as untrusted content when showing it to an LLM or UI.
|
||||
- Report discovery errors without disabling unrelated valid packages.
|
||||
|
||||
## Runtime notes
|
||||
|
||||
Declarative hooks are data contributions. Loading a declarative hook still requires explicit package enablement. Hook text should enter the system through the normal Hook/Engine paths, preserving the rule that model-affecting inputs are committed to history before they affect context when applicable.
|
||||
|
||||
WASM packages should initialize only from the digest-keyed cache after enablement and grant resolution. The host should use a narrow ABI, bounded memory, fuel/time limits, bounded output, and explicit host functions. A WASM module must not inherit filesystem, network, tool, secret, process, or MCP authority from the package store path.
|
||||
|
||||
Tool contributions from plugins should pass through the normal ToolRegistry and permission checks. Plugin-provided schemas can describe arguments, but schema presence is not permission to execute a tool.
|
||||
|
||||
## MCP boundary
|
||||
|
||||
MCP remains a separate feature-backed integration and is out of the initial Plugin package runtime. A `.yoi-plugin` package must not launch an MCP server or imply MCP enablement.
|
||||
|
||||
A future MCP/plugin bridge would need its own Ticket covering external process authority, lifecycle, permission mapping, resource/prompt operations, diagnostics, and trust model. Until then, package metadata may mention compatibility for humans, but runtime packaging should ignore it.
|
||||
|
||||
## Follow-up implementation cuts
|
||||
|
||||
Good follow-up Tickets are intentionally separable:
|
||||
|
||||
1. Manifest/Profile plugin enablement schema and resolved-session metadata, including restore behavior and digest pins.
|
||||
2. Package discovery for builtin, user, and project stores with source-qualified identity and collision diagnostics.
|
||||
3. `.yoi-plugin` archive validation, deterministic digest computation, and digest-keyed cache materialization.
|
||||
4. Plugin-layer permission policy that combines package requests with existing tool/scope/web/secret/runtime allowlists without using `worker::feature` HostAuthority concepts.
|
||||
5. Declarative hook package loading from enabled, materialized packages.
|
||||
6. WASM package ABI, initialization limits, host-function grants, and Tool/Hook contribution plumbing.
|
||||
7. Optional lock-file or pin update workflow for reproducible fresh startup.
|
||||
8. Future MCP/plugin bridge, only if explicitly approved as a separate design and implementation effort.
|
||||
|
||||
### Component Model Tool runtime
|
||||
|
||||
Tool packages may use WebAssembly Component Model runtime metadata:
|
||||
|
||||
```toml
|
||||
[runtime]
|
||||
kind = "wasm-component"
|
||||
component = "plugin.component.wasm"
|
||||
world = "yoi:plugin/tool@1.0.0"
|
||||
```
|
||||
|
||||
For new Rust Tool packages, the preferred authoring path is the first-party
|
||||
`yoi-plugin-pdk` plus the embedded `resources/plugin/templates/rust-component-tool/`
|
||||
starter. The template uses a checkout-local path dependency for development and
|
||||
documents a future out-of-tree pinned git `rev` dependency pattern. Crates.io
|
||||
publication, remote template fetching, and package authoring commands are not
|
||||
part of the current package/runtime contract.
|
||||
|
||||
Legacy raw core-Wasm metadata remains documented only as a rejected migration diagnostic. Packages must not use `entry`/`abi`; discovery reports `kind = "wasm"` / `abi = "yoi-plugin-wasm-1"` packages as rejected without executing the artifact. Component execution still requires explicit package enablement, exact source/version/digest grants, and matching Tool/host API permissions.
|
||||
Server-installed Plugin packages and Addons are future work. That platform must provide explicit immutable package identity and digest, Server-owned artifact delivery and Workspace selection, a Backend-authored per-Worker execution plan, Runtime verification, and sandboxed execution. It must not restore repository-local or user-data discovery as a compatibility fallback.
|
||||
|
||||
Reference in New Issue
Block a user