Skip to main content
Every plugin project, in any language, carries the same four things: an interface, an implementation, a configuration file, and a build script. This page describes them and what the platform does with each.
The code below is the Rust template, which noorle plugin init <name> --template rust scaffolds. The per-language layouts and build commands are under Languages; everything on this page about wit/world.wit, noorle.yaml, and the archive applies to all of them.

Layout

Build with noorle plugin build, not with cargo directly — the CLI drives build.sh and packages the archive.

wit/world.wit — the interface

The WIT world defines your tools: their names, parameter types, and return types. Two things follow from it. Exported functions become tools. Discovery walks the compiled component’s exports, so what you export is what agents see. Doc comments become tool descriptions. The /// line above an export is the text a model reads when deciding whether to call it. Write it for the model, not for a compiler.
Return result<T, string> so failures reach the caller as errors rather than as a success carrying an error string. The .wit file is packaged into the archive and stored with the version, but it is not what produces the tool schema — the schema is generated from the component’s own types. Shipping the file gets you descriptions; omitting it gets you tools with no descriptions.

src/lib.rs — the implementation

wit_bindgen generates a Guest trait from the world; you implement it and export the implementing type.
  • Outbound HTTP goes through waki. reqwest does not compile to a WASI component.
  • Environment variables are read with std::env::var, and only the keys you list under permissions.environment are visible.
  • Files live under the mounts you grant — /workspace/input, /workspace/output, /workspace/home. There is no host filesystem behind them; see Permissions.
  • Avoid unsafe.

noorle.yaml — configuration

Metadata, the permission policy, and credential declarations. This is the file that decides what your plugin can reach at runtime; without it, the plugin runs with no network, no storage, and no environment access.
Full key-by-key reference: noorle.yaml.

Cargo.toml

crate-type = ["cdylib"] is required — without it the build produces something that is not a component, and admission validation rejects it.

What ends up in the archive

noorle plugin build writes a .npack to dist/. When the platform unpacks it, it looks for four things by filename pattern: Everything else in the archive is ignored. Your source is not uploaded — the upload path stores the component, the manifest, the environment defaults, and the WIT file, and nothing else. (Plugin versions produced by Plugin Builder do keep a source archive, so a later build can iterate on them.)

Size

There is no minimum, and no hard maximum below the upload limit. Validation warns above 20 MB for the component binary — a warning, not a rejection. If you approach it, reach for your toolchain’s size levers: in Rust, release settings such as an opt-level tuned for size, LTO, and symbol stripping; in Go, the -opt=2 -no-debug flags TinyGo already builds with; in Python and JavaScript, trimming dependencies, since the runtime is bundled into the component.

Next