# Getting started
This page takes a UI plugin and a companion daemon from nothing to a packed
bundle. Every source file it refers to is a compiled example in the SDK's
`examples/` directory; the scaffolds `standard-plugin new` writes are those
examples with your plugin's id.
## Tools
- Rust stable with the `wasm32-wasip2` target:
`rustup target add wasm32-wasip2`.
- The CLI: `cargo install standard-plugin-cli --locked`. It installs
`standard-plugin` and `cargo-standard-plugin`, so
`cargo standard-plugin ...` works too.
- The SDK: every scaffold depends on `standard-plugin-sdk = "0.1"`; a
daemon that uses WASI files, sockets or HTTP writes
`{ version = "0.1", features = ["wasi"] }`
([daemon plugins](daemon-plugins.md)).
Install the CLI from the same release line as the SDK a plugin depends
on, so its WIT package matches the SDK's. Never commit a `Cargo.lock`
resolved with a local path patch
([agent guide](agent-guide.md#14-lockfiles-and-a-local-sdk-patch)).
- Optional: [`jco`](https://github.com/bytecodealliance/jco)
(`npm install -g @bytecodealliance/jco`) to inspect the component's
JavaScript form. Viewers do not run it. Without it `build` says it
skipped that step.
`standard-plugin new --sdk-path <dir>` points a scaffold at a local SDK
checkout instead of the published crate.
## A UI plugin
```sh
standard-plugin new my-card --kind ui
cd my-card
```
The scaffold is one crate:
| `Cargo.toml` | A `cdylib` depending on `standard-plugin-sdk`, with size-tuned release settings |
| `src/lib.rs` | The plugin: [`examples/clock_card.rs`](../examples/clock_card.rs) |
| `bundle/standard-plugin.json` | The [manifest](manifest.md): one `sidebar.card` surface in the cell model, no grants |
| `.gitignore` | Ignores `target/` and what `build` writes into `bundle/` |
| `AGENTS.md`, `CLAUDE.md` | Where a coding agent finds these guides for the SDK version in use |
Read `src/lib.rs` top to bottom; it is short:
- The crate is `#![no_std]`. A UI plugin runs inside every viewer with no
WASI, and `std` would import it; `alloc` (`String`, `Vec`, `format!`) is
available through `standard_plugin::prelude`.
- `#[standard_plugin::ui]` on the type exports it as the component's
`ui-plugin` world. The type implements `UiPlugin`: `activate` creates the
`Surface<Cells>` named in the manifest, `frame` paints and commits, and
`event` hears about resizes.
- `frame` repaints only when the second changes and asks for its next
frame at the next second with `frame.wake_at(...)`. The viewer calls
`frame` only when a frame is due *and* the card is visible, so the card
costs nothing while hidden. See [rendering](rendering.md).
Build, check and pack:
```sh
standard-plugin build # cargo build --release --target wasm32-wasip2, into bundle/, then check
standard-plugin check # again, without building
standard-plugin pack # target/standard-plugin/my-card-0.1.0.tar and its sha256
standard-plugin install # the same, then `standard plugin install` on your account
```
`check` parses the manifest with the same code the viewer's host uses,
checks every grant has a reason, and checks the component imports nothing
outside the `ui-plugin` world; see [grants](grants.md) for its warnings.
`install` uploads the package to your account's plugin store, lists its
grants with their reasons and asks before it installs; every viewer signed
in to the account then runs the card ([publishing](publishing.md)). To try
a build in one development viewer without installing it:
```sh
STANDARD_PLUGIN_DIRS=$PWD/bundle standard
```
To test it without a viewer, drive it with `standard_plugin::testing` from
an ordinary `#[test]`; [`tests/testing_harness.rs`](../tests/testing_harness.rs)
is a complete example.
## A companion daemon
A UI plugin is side-effect free: it runs once per open viewer, so anything
it did would happen once per viewer. Work that must happen once belongs to
a *companion*: a daemon plugin with the same id that the UI half asks
through calls and that publishes results the UI half reads. [Working
together](working-together.md) explains the pattern.
```sh
standard-plugin new builds --kind companion
cd builds
```
The scaffold is a Cargo workspace with two crates, one plugin id:
| `ui/src/lib.rs` | The UI half: [`examples/together_ui.rs`](../examples/together_ui.rs) |
| `ui/bundle/standard-plugin.json` | Kind `ui`, grant `call:builds` (with its reason) |
| `companion/src/lib.rs` | The daemon half: [`examples/together_companion.rs`](../examples/together_companion.rs) |
| `companion/bundle/standard-plugin.json` | Kind `companion`, grant `process.exec:make` |
How the halves cooperate:
1. The companion publishes the build status as a durable value,
`builds.status`, and announces each change with the event
`builds.changed`. Both are in the plugin's own namespace, so neither
needs a grant.
2. The UI half reads `builds.status` in `activate`, listens to
`builds.*`, and repaints its card when `builds.changed` arrives.
3. A click on the card is an effect, so the UI half acts only when
`view::is_driving()` says the user is controlling this viewer, and then
inside `claims().once(...)` so exactly one request goes out. It calls
the companion's `rebuild` method (`calls().call(..., Target::Singleton)`,
grant `call:builds`).
4. The companion's `call` handler answers at once and spawns the build as
a task on its executor, which runs when the host next drives the
plugin: it runs `make` (grant `process.exec:make`) and publishes the
new status, which step 2 shows in every viewer.
Build, check and pack from the workspace root; the CLI finds both halves:
```sh
standard-plugin build
standard-plugin pack
```
Both halves build, check, pack and install as one package, and both run
under `standard_plugin::testing`. Once installed, `standardd` runs the
companion on the machines its placement names
([daemon plugins](daemon-plugins.md#where-it-runs)), and the UI half's
calls reach it there.
## Next
- [The manifest](manifest.md) and [grants](grants.md): what a plugin asks for.
- [Rendering](rendering.md): cells, pixels, the shared buffer, the helpers.
- [Working together](working-together.md): values, events, calls, live;
many viewers; companions.