Skip to main content
Scaffold a plugin, build it to a WebAssembly component, and get it into your account.

Before you start

  • An account on the Portal.
  • A Rust toolchain. This walkthrough uses the Rust template; the steps after the build are identical in every language.
Plugins can be written in Rust, Python, JavaScript, TypeScript, or Go — each has a working example and a guide under Languages. Whatever the source language, what you upload is a WASI Preview 2 component, and admission checks the same things — see How plugins run.
1

Install the CLI

If noorle --version does not resolve in a new shell, follow whatever the installer printed about your PATH.
2

Scaffold the project

You get a wit/world.wit interface, a src/lib.rs implementing it, a noorle.yaml, a Cargo.toml, and a build.sh the CLI calls. See Project structure for what each file does.
3

Declare the tool in WIT

The exported functions in wit/world.wit become your tools. The doc comment above each one becomes the description a model reads, so write it for the model.
Return result<T, string> — that is how an error reaches the caller.
4

Implement it

For outbound HTTP use the waki crate. reqwest does not compile to a WASI component.
5

Grant the permissions it needs

A plugin with no permissions block gets no network, no storage, and no environment variables. Name the hosts you call:
Scope hosts specifically — a wildcard grants more than you meant. Full grammar in the configuration reference.
6

Build

This compiles the component and packages it. The archive lands in dist/ as a .npack — a gzip-compressed tar holding the .wasm, your noorle.yaml, and the .wit.
7

Upload it

In the Portal, go to Plugins → New plugin, choose .npack archive, and pick the file from dist/.Plugin names are 2–50 characters. The component is validated before it is stored; if validation fails you get the errors back and nothing is written.On success the upload becomes the plugin’s active version in the same commit, and its tools are available to bind.
8

Bind it and call it

Attach the plugin to an agent or a gateway the same way you attach any capability — see Attaching capabilities.The wire name of your tool is {namespace}_{tool}, where the namespace is a short prefix the platform assigns to the capability. Read it off the capability in the Portal or off the gateway’s tools/list response; it is not derived from the plugin’s name.

What happens on the first call

Plugin tools are classified Act. Where autonomy enforcement is on for your account and the agent sits at its default Supervised level, an Act call pauses for approval rather than running straight through — approve it in the Playground, or add it to the agent’s auto-approve list.

Troubleshooting

Upload rejected: “Component exports no callable functions” — the binary is a core WebAssembly module, not a component, or nothing is exported from the world. Confirm crate-type = ["cdylib"] in Cargo.toml and that export! is present in src/lib.rs. Upload rejected on imports — the component imports an interface outside the nine allowed WASI prefixes. wasi:keyvalue/store is supported; wasi:keyvalue/atomics, batch, and watch are not — those pass admission and then fail at call time. The tool runs but every outbound request fails — check the network.allow list in noorle.yaml. An absent or empty list means no outbound access at all. CIDR entries are rejected outright; use host patterns. Calls time out — the default wall clock is 30 seconds, and CPU fuel exhaustion is also reported as a timeout. You can raise the timeout in noorle.yaml up to 120 seconds; fuel is not settable per plugin.

Next