Skip to main content
A Noorle plugin is a WebAssembly component targeting WASI Preview 2, executed on Wasmtime inside the platform. Its exported functions become tools that agents, gateways, and workflows can call.

What the platform stores

Plugins are uploaded either as a bare .wasm component (with an optional .wit file) or as a .npack archive — a gzip-compressed tar. Archive entries are matched by filename pattern, not by fixed path: Directories are skipped; anything else is logged and ignored. Extraction is capped at 256 MB total decompressed across all entries, enforced incrementally — the tar header’s declared size is not trusted. The plugin’s name comes from metadata.name in noorle.yaml, falling back to the archive filename minus .npack, then to the WASM file’s stem.

Admission validation

Every component is validated before it is stored. Four checks:
  1. It must be a Component Model binary. A core WebAssembly module is rejected.
  2. Every import must sit under one of nine WASI prefixes: wasi:clocks/, wasi:random/, wasi:cli/, wasi:sockets/, wasi:io/, wasi:filesystem/, wasi:http/, wasi:config/, wasi:keyvalue/. Anything else is rejected.
  3. It must export at least one callable function.
  4. Binaries over 20 MB produce a warning, not a rejection.
Of wasi:keyvalue, only the store interface is implemented.

How tools are discovered

Tool discovery does not read the .wit file. The platform walks the component’s exported functions using Wasmtime’s component type reflection and generates a JSON Schema for each from the WIT types. The .wit file, when you ship one, supplies the descriptions — the doc comment above an exported function becomes the tool description a model reads. If the file fails to parse, the upload still succeeds; you just get tools with no descriptions.

Tool names

Each capability carries a namespace, and the wire name of a tool is {namespace}_{tool}. The namespace for a plugin is assigned by the platform — a short random lowercase string, unique within your account. It is not derived from the plugin’s name, and there is no field to set it. The tool half is derived from the component’s export path, not from the function name alone. A function exported directly from the world contributes only its own name; a function exported through a WIT interface contributes the package and interface names as well, joined with _. Each part is lowercased, and every character outside az, 09, and - becomes _ — so hyphens survive but dots, colons, slashes, and spaces do not. A name that would exceed 128 characters collapses to the function name alone. Because the namespace is assigned and the tool half depends on how your world is structured, read the final name off the capability in the Portal, or off a gateway’s tools/list response, rather than predicting it. A tool whose namespaced name would collide with a reserved platform tool is dropped from the catalog and logged.

The sandbox

The component runs with no ambient authority. What it can reach is exactly what the permissions block in noorle.yaml grants — and with no permissions block at all, the platform applies a default policy whose every field is empty: no network, no storage, no environment variables.
  • Network — an allowlist of hosts, enforced by a wrapper WASI state built from the policy. An empty allowlist means no outbound access. CIDR ranges are rejected at validation — use host patterns. Outbound request bodies are scanned for secret patterns as they stream; findings are logged, not blocked.
  • Storage — not a real filesystem. Three object-store-backed mounts, granted individually: /workspace/input and /workspace/output, both session-scoped, and /workspace/home, which is agent-scoped and materialised only for agent callers.
  • Environment — only the keys you list are visible; nothing from the host environment leaks in.
  • Credentials — declared in noorle.yaml, stored encrypted, and injected into outbound HTTP at the host boundary. Ciphertext never enters guest memory.
See Permissions for the full grammar.

Resource limits

Three independent stops bound a single tool call: Values are identical in every environment. A plugin may request a lower timeout or a different memory ceiling in noorle.yaml; the request is clamped to these bounds. Fuel is not settable from noorle.yaml — it comes from platform configuration plus an optional per-account override (wasm_cpu_fuel_limit, wasm_memory_limit_mb), itself clamped to the same bounds. Alongside fuel there is an epoch deadline computed from the timeout in 10 ms ticks, and an outer wall clock. Fuel exhaustion is reported to the caller as a timeout, not as a distinct error. Outbound HTTP is separately capped at 100 requests per execution. That number comes from platform configuration and is the same for every plugin.

Caching

Compiled components are cached in-process keyed by content hash, so two capabilities sharing identical WASM compile and pre-instantiate once. A second, byte-weighted cache (256 MB per pod) holds plugin bytes keyed by WASM hash, so a warm plugin skips the object-store fetch.

Where plugin calls sit in the platform

  • Risk tier. Every plugin tool is classified Act — kind-wide, with no per-tool override. Where autonomy enforcement is on and the agent sits at its default Supervised level, an Act call pauses for approval unless it has been auto-approved.
  • Surfaces. Plugins carry no exposure restriction, so they are listed on agent, gateway, and workflow surfaces alike.
  • Billing. Plugin execution is metered and lands in your account’s usage, like any other capability call — see Usage and limits.

Generating a plugin

You do not have to write the code. Plugin Builder takes a natural-language requirement, runs a coding agent inside a build sandbox, and feeds the resulting archive through the same upload, validation, and registration path as a hand-built plugin. It scaffolds from the Rust template, so a generated plugin is a Rust project. Writing the plugin yourself gives you the choice of five languages — see Languages. Two ways in:
  • PortalPlugins → New plugin → Build with AI.
  • As a capability — bind Plugin Builder to an agent and it gets three tools: build, status, and cancel. It is available on agent and gateway surfaces, not in workflows, and is classified Privileged.
In production a build gets an md sandbox, up to 1800 seconds, and up to 50 agent turns. Builds are asynchronous: build returns an id, status reports progress, and the new tool appears on the capability when it completes.
Generated plugins land as ordinary versions of an ordinary capability — same validation, same permissions model, same version history. Review the generated noorle.yaml before activating; the network permissions are the part worth reading.

Next