standard-plugin-sdk 0.1.1

Write Standard Code plugins in Rust: wasm components against standard:plugin@2.0.0
Documentation
# Other toolchains (unsupported)

Rust with `standard-plugin-sdk` is the supported way to write a Standard
Code plugin. It is the only toolchain Standard Code tests or supports. The
other guides on these pages assume it: start with
[getting started](getting-started.md).

This page records the rules a component must meet, whatever built it. Use
of any other toolchain is possible, unsupported, and community territory.

## The contract

The contract is the WIT package `standard:plugin@2.0.0` in
[`wit/plugin.wit`](../wit/plugin.wit) in this crate.
It defines two worlds: `ui-plugin` for UI plugins and `daemon-plugin` for
daemon plugins and companions. The Rust SDK is one wrapper over that
package. [The low-level contract](abi.md) describes what the SDK does
over it: the exports, the memory rules and the surface buffer protocol.

## Rules for any component

- **A component.** The file the manifest's `module` names is a WebAssembly
  component. `standard-plugin check` refuses a core module
  (`src/component.rs` in `standard-plugin-cli`,
  `inspect`).
- **Its world's imports only.** A component imports only the interfaces of
  its kind's world. An import outside the world fails at instantiation
  (`plugin.wit`, the package comment).
- **Its world's exports.** A UI plugin exports `activate`, `frame`,
  `event` and `deactivate`. A daemon plugin exports `activate`, `event`,
  `drive`, `deactivate` and the interfaces `daemon-events` and `companion`
  ([the low-level contract]abi.md#worlds-and-exports).
- **No WASI in a UI half.** A UI plugin imports the `ui-plugin` world's
  interfaces and nothing else. It imports no WASI interface of any
  version. `check` reports every `wasi:` import of a UI half as an error
  (`src/check.rs` in `standard-plugin-cli`,
  `check_component`). This also rules out a libc or language runtime that
  imports WASI.
- **WASI 0.2 in a daemon half, as the world states.** A daemon plugin may
  import WASI 0.2 beside the `daemon-plugin` world. The world's comment in
  `plugin.wit` lists what is linked: `wasi:filesystem` with the directories
  the `fs.read:` and `fs.write:` grants name preopened (`/` under
  `machine.full`), `wasi:http/outgoing-handler` to the hosts `fetch:`
  grants name, `wasi:sockets` only under `network.full` or `machine.full`,
  clocks, random, and stdout and stderr into the daemon's log. For
  anything else, see the `daemon-plugin` world in `plugin.wit`. `check`
  does not check which WASI interfaces a daemon half imports.
- **Sizes.** The component is at most 8 MiB and the manifest at most
  64 KiB ([manifest]manifest.md).
- **Memory.** The component exports its memory and the canonical ABI
  realloc function, and follows the surface buffer protocol
  ([the low-level contract]abi.md#the-surface-buffer).

## What the CLI does with a component

The `standard-plugin` CLI builds Rust crates. Its other commands read a
built component and do not care what built it
(`src/lib.rs` in `standard-plugin-cli`).

| Command | Needs Cargo | What it does |
| --- | --- | --- |
| `new` | yes | Writes a Rust crate from the SDK's examples. |
| `build` | yes | Runs `cargo build --lib --target wasm32-wasip2` on a crate with a `cdylib` target, copies the component into `bundle/` under the manifest's `module` name, then runs `check` (`src/build.rs` in `standard-plugin-cli`). |
| `check` | no | Parses the manifest, checks every grant, and checks the component in `bundle/` against its kind's world: imports, exports and WASI (`src/check.rs` in `standard-plugin-cli`). |
| `pack` | no | Runs `check`, then writes the deterministic package and prints its SHA-256 (`src/pack.rs` in `standard-plugin-cli`). |
| `install` | no | Runs `pack`, then `standard plugin install <dir>`, which asks before it installs. `STANDARD_BIN` names another `standard` binary (`src/install.rs` in `standard-plugin-cli`). |
| `guide` | no | Lists or prints these guides, as the SDK the plugin's `Cargo.lock` resolves carries them (`src/guide.rs` in `standard-plugin-cli`). |

Each command takes `--dir <path>` (the default is the current directory).

### The layout the CLI expects

A plugin directory holds its manifest and its component in `bundle/`:

```text
my-plugin/
  bundle/
    standard-plugin.json    the manifest
    <module>                the component; the file name the manifest's "module" gives
```

`check` reads the component from `bundle/`. A manifest beside
`Cargo.toml` is copied into `bundle/` only by `build`, so without Cargo
keep both files in `bundle/`
(`src/project.rs` in `standard-plugin-cli`,
`Plugin`).

A companion pair is a parent directory whose immediate subdirectories are
the two plugins: one of kind `ui` and one of kind `companion`, with the
same `id`. The names of the subdirectories are free; the scaffold uses
`ui/` and `companion/`. `check`, `pack` and `install` on the parent
directory find both halves (`project::plugins`). In the package, `pack`
puts the halves under `ui/` and `daemon/`, each with its runtime manifest
and component ([publishing](publishing.md)).

## Toolchains

A component built by any toolchain that meets these rules can run.
Standard Code does not test or support other toolchains.

- C, C++ and Zig toolchains that build without a WASI-importing libc can
  meet the UI rule.
- Toolchains that bundle an interpreter or a language runtime in the
  component generally import WASI and make large components, so they
  generally cannot meet the UI rule or the 8 MiB limit.