Appearance
Plugin Structure
Understanding the anatomy of a Noorle plugin.
Overview
Every Noorle plugin follows a consistent structure regardless of language:
tree
my-plugin/
├── Source Files # Language-specific implementation
├── wit/world.wit # API definition (WebAssembly Interface)
├── build.sh # Build script
├── prepare.sh # Dependency installer
├── noorle.yaml # Plugin configuration (optional)
├── Config Files # Language-specific (package.json, Cargo.toml, etc.)
└── dist/ # Build output
├── plugin.wasm # Compiled WebAssembly component
└── *.npack # Deployment archive
Core Components
1. Source Files
Your plugin implementation in your chosen language:
Language | Main File | Description |
---|---|---|
Python | app.py | Python class implementing WIT interface |
TypeScript | app.ts | TypeScript module with exported functions |
JavaScript | app.js | JavaScript module with exported functions |
Rust | src/lib.rs | Rust library with component macro |
Go | main.go | Go package with exported functions |
2. WIT Interface (wit/world.wit
)
Defines your plugin's API using WebAssembly Interface Types:
wit
package noorle:my-plugin;
world my-plugin-component {
/// Process input data
/// This comment becomes the tool description in MCP
export process: func(input: string) -> result<string, string>;
/// Calculate something
export calculate: func(a: f64, b: f64) -> f64;
}
Key Points:
- Package name identifies your plugin
- World name defines the WebAssembly component
- Comments become tool descriptions
- Functions are auto-discovered as MCP tools
3. Build Script (build.sh
)
Template-provided script that handles compilation:
bash
#!/bin/bash
# Checks dependencies
# Compiles source to WebAssembly
# Creates component from module
# Packages into .npack archive
Build Contract:
- Input: Source files and WIT definition
- Output:
dist/plugin.wasm
and.npack
archive - Must be executable (
chmod +x build.sh
)
4. Prepare Script (prepare.sh
)
Installs all required dependencies:
bash
#!/bin/bash
# Installs language toolchain
# Installs WebAssembly tools
# Installs project dependencies
Usage:
bash
./prepare.sh # Interactive installation
./prepare.sh --check # Check dependencies only
./prepare.sh --ci # Non-interactive mode
5. Configuration (noorle.yaml
)
Optional configuration for permissions and metadata:
yaml
schema_version: "1.0" # Required when file exists
metadata:
name: my-plugin # Defaults to folder name
description: "What this plugin does"
author: "Your Name"
tags:
- utility
- api
permissions:
network:
allow:
- host: "api.example.com"
environment:
allow:
- API_KEY
- DEBUG_MODE
Note: This file is completely optional - plugins work without it!
Language-Specific Files
Python
tree
├── app.py # Main implementation
├── pyproject.toml # Dependencies (uv/pip)
└── test_app.py # Unit tests (optional)
TypeScript/JavaScript
tree
├── app.ts/app.js # Main implementation
├── package.json # NPM dependencies
├── tsconfig.json # TypeScript config (TS only)
└── wasi.d.ts # WASI type declarations
Rust
tree
├── src/lib.rs # Main implementation
├── Cargo.toml # Rust dependencies
└── wkg.toml # WIT package config
Go
tree
├── main.go # Main implementation
├── go.mod # Go module definition
├── wkg.toml # WIT package config
└── gen/ # Generated bindings
Build Output
The dist/
Directory
Created during build, contains:
plugin.wasm
- The compiled WebAssembly component- Self-contained binary
- Platform independent
- Includes all code and metadata
*.npack
- Deployment archive- TAR archive of necessary files
- Named:
<plugin-name>-<hash>.npack
- Used for deployment to Noorle
Build Process Flow
WIT Dependencies
The wit/deps/
Directory
Contains WASI interface definitions (pre-included):
tree
wit/deps/
├── wasi-cli/ # CLI arguments, environment
├── wasi-filesystem/ # File system access
├── wasi-http/ # HTTP client
├── wasi-sockets/ # Network sockets
├── wasi-clocks/ # Time functions
├── wasi-random/ # Random numbers
└── wasi-io/ # Basic I/O
Important: Only import what you need in world.wit
:
wit
world my-plugin-component {
// Import only required interfaces
import wasi:http/outgoing-handler@0.2.0;
import wasi:cli/environment@0.2.0;
export my-function: func() -> string;
}
Auto-Discovery
How It Works
- Deploy your
.npack
to Noorle - Platform introspects the WIT interface
- Functions discovered automatically
- MCP tools created with proper schemas
- Available immediately to AI agents
No Configuration Needed
Unlike traditional plugin systems:
- ❌ No manifest files
- ❌ No tool registration
- ❌ No schema definitions
- ✅ Just export functions!
Example
Your WIT:
wit
export analyze: func(data: string) -> result<analysis, string>;
Becomes MCP tool:
json
{
"name": "analyze",
"description": "From WIT comments",
"inputSchema": {
"type": "object",
"properties": {
"data": { "type": "string" }
}
}
}
Universal Plugins
Not Noorle-Specific
Your plugin compiles to a standard WebAssembly component that:
- Works in any WASI runtime
- Can be used outside Noorle
- Follows open standards
- Has no vendor lock-in
Reusability
Plugins can be:
- Shared across projects
- Composed with other plugins
- Versioned using standard practices
- Distributed through any channel
Best Practices
1. Clear WIT Documentation
wit
/// Calculate shipping cost based on weight and distance
///
/// Returns the cost in USD or an error message
export calculate-shipping: func(
weight-kg: f64,
distance-km: f64
) -> result<f64, string>;
2. Consistent Naming
- Use kebab-case in WIT files
- Follow language conventions in source
- Keep names descriptive and clear
3. Error Handling
Always use Result types for fallible operations:
wit
export process: func(input: string) -> result<output, error-message>;
4. Minimal Permissions
Only request what you need:
yaml
permissions:
network:
allow:
- host: "api.example.com" # Only specific API
5. Version Control
Track these files:
- Source code
wit/world.wit
- Configuration files
build.sh
andprepare.sh
Don't track:
dist/
directory- Generated bindings
- Dependencies (node_modules, etc.)
Troubleshooting Structure Issues
Missing Files
bash
# Ensure all required files exist
ls -la wit/world.wit build.sh prepare.sh
# Make scripts executable
chmod +x build.sh prepare.sh
Build Output Issues
bash
# Clean and rebuild
rm -rf dist/
noorle plugin build
# Check output
ls -la dist/
WIT Parsing Errors
Common issues:
- Missing package declaration
- Invalid function signatures
- Unmatched braces
- Missing semicolons
Next Steps
- Configuration - Deep dive into noorle.yaml
- Language Guides - Language-specific details
- Deployment - Publishing your plugin