Documentation Index Fetch the complete documentation index at: https://noorle.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
WebAssembly (WASM) lets you write plugins in any language (Rust, C, Python, Go, etc.) and deploy them securely. Noorle runs plugins in a sandboxed environment using Wasmtime, preventing access to the host system.
Why WebAssembly?
Plugins must be:
Secure - Can’t access system, steal data, or harm other processes
Fast - Near-native performance for complex computation
Portable - Write once, run anywhere
Controlled - Resource limits (memory, CPU time)
WASM Sandbox Model
Noorle uses WASI Preview 2 (WebAssembly System Interface) for safe system access:
Plugin Lifecycle
Npack is Noorle’s plugin package format:
myanalyzer.npack (ZIP archive)
│
├─ manifest.json (metadata)
├─ plugin.wasm (compiled WASM binary)
├─ schema.json (MCP tool schemas)
└─ assets/ (optional: config files, etc.)
└─ default.config
manifest.json
{
"name" : "loan_analyzer" ,
"version" : "1.0.0" ,
"description" : "Analyzes loan applications" ,
"author" : "Your Company" ,
"permissions" : [
"cpu_bound" , // allow CPU-intensive work
"memory_bound" // allow large memory allocation
],
"environment" : {
"RISK_THRESHOLD" : "0.75"
}
}
schema.json
Defines MCP tools the plugin exposes:
{
"tools" : [
{
"name" : "analyze_loan" ,
"description" : "Analyze loan application for risk" ,
"inputSchema" : {
"type" : "object" ,
"properties" : {
"income" : { "type" : "number" },
"debt" : { "type" : "number" },
"credit_score" : { "type" : "integer" }
},
"required" : [ "income" , "debt" , "credit_score" ]
}
}
]
}
Example Plugin: Loan Analyzer
Rust Source Code
// src/lib.rs
use serde :: { Deserialize , Serialize };
#[derive( Serialize , Deserialize )]
pub struct LoanApplication {
pub income : f64 ,
pub debt : f64 ,
pub credit_score : i32 ,
}
#[derive( Serialize , Deserialize )]
pub struct RiskAssessment {
pub risk_level : String , // "low", "medium", "high"
pub approval_probability : f64 ,
pub reasoning : String ,
}
pub fn analyze_loan ( app : LoanApplication ) -> RiskAssessment {
let debt_to_income = app . debt / app . income;
let risk = if app . credit_score < 600 {
"high"
} else if debt_to_income > 0.43 {
"high"
} else if app . credit_score < 700 {
"medium"
} else {
"low"
};
RiskAssessment {
risk_level : risk . to_string (),
approval_probability : calculate_approval ( app . credit_score, debt_to_income ),
reasoning : "Based on DTI ratio and credit score" . to_string (),
}
}
fn calculate_approval ( credit_score : i32 , dti : f64 ) -> f64 {
let credit_factor = ( credit_score as f64 - 600.0 ) / 350.0 ;
let dti_factor = ( 0.43 - dti ) . max ( 0.0 ) / 0.43 ;
( credit_factor * 0.6 + dti_factor * 0.4 ) . max ( 0.0 ) . min ( 1.0 )
}
Compilation
# Install Rust WASM target
rustup target add wasm32-wasi
# Compile to WASM
cargo build --target wasm32-wasi --release
# Resulting binary
target/wasm32-wasi/release/loan_analyzer.wasm
Packaging
# Create npack
noorle-cli package \
--wasm ./target/wasm32-wasi/release/loan_analyzer.wasm \
--manifest ./manifest.json \
--schema ./schema.json \
--output loan_analyzer.npack
# Upload
noorle-cli publish loan_analyzer.npack
Runtime Behavior
When an agent calls your plugin:
Agent: "analyze_loan({income: 80000, debt: 25000, credit_score: 720})"
│
├─ Load WASM from registry (cached)
│
├─ Instantiate in Wasmtime sandbox
│ ├─ Memory limit: 256 MB
│ ├─ CPU timeout: 30 seconds
│ ├─ No filesystem access
│ └─ No network access
│
├─ Call exported function
│ analyze_loan({...})
│
├─ Execute in sandbox
│ └─ Computation happens here
│
├─ Return result
│ {
│ "risk_level": "low",
│ "approval_probability": 0.92,
│ "reasoning": "..."
│ }
│
└─ Sandbox destroyed (memory freed)
Permissions & Capabilities
Control what each plugin can do via permissions:
{
"permissions" : [
"cpu_bound" , // allow CPU-intensive work (no limits)
"memory_bound" , // allow large allocations (256 MB)
"execution_timeout:60" // execution timeout: 60 seconds
]
}
Available permissions:
cpu_bound - Remove default CPU time limits
memory_bound - Increase memory limit to 256 MB
env:{var_name} - Access specific environment variable
execution_timeout:{seconds} - Custom timeout
Environment variables:
Pass secrets via env vars (encrypted in config):
{
"permissions" : [ "env:DATABASE_KEY" ],
"environment" : {
"DATABASE_KEY" : "${ENCRYPTED_SECRET}"
}
}
Plugin accesses via WASI:
let api_key = std :: env :: var ( "DATABASE_KEY" ) . unwrap ();
Versioning & Rollback
Plugins are versioned:
loan_analyzer
├─ v1.0.0 (deployed)
├─ v1.1.0 (deployed)
├─ v2.0.0 (in gateway, promoted to prod)
└─ v2.1.0 (beta testing)
Gateway: Attached to v2.0.0
If bug found:
└─ Rollback to v1.1.0 (1 click)
All calls go to v1.1.0
Managing versions:
# List versions
noorle-cli plugins list loan_analyzer
# Deploy new version
noorle-cli plugins deploy loan_analyzer v2.1.0
# Rollback
noorle-cli plugins rollback loan_analyzer v1.1.0
WASM near-native performance:
Task: Analyze 1000 loan applications
Native Code:
└─ 500 ms
WASM Code:
└─ 510 ms (2% overhead from sandbox)
Overhead is minimal, well worth the security.
Startup cost:
First call: 50 ms (load + compile WASM)
(cached for future calls)
Subsequent: 5 ms overhead
(calls are direct)
Supported Languages
Any language that compiles to WASM:
Language Status Setup Rust ✓ Best rustup target add wasm32-wasiC/C++ ✓ Good Emscripten or clang WASM Go ✓ Good GOOS=js GOARCH=wasmPython ⚠ Limited Pyodide (some limitations) JavaScript ✓ Good Node.js WASM target Zig ✓ Good Zig target wasm32-wasi
Recommendation: Use Rust for best developer experience and security.
Debugging
Monitor plugin execution:
# View plugin logs
noorle-cli plugins logs loan_analyzer --tail 100
# Get execution metrics
GET /api/plugins/loan_analyzer/metrics
{
"calls" : 1523,
"errors" : 2,
"avg_duration_ms" : 12,
"max_duration_ms" : 45
}
Best Practices
Pure Functions Plugins should be deterministic. Same input = same output.
Handle Errors Gracefully Return structured errors. Agents need to know what went wrong.
Keep Simple Plugins for specific logic. Use builtins for general tasks.
Test Thoroughly Test locally before uploading. Use unit tests and integration tests.
Limitations
Binary size: Max ~50 MB (practical: 10 MB)
Memory: 256 MB default (or configurable)
Execution time: 30 seconds default (or configurable)
Network: No direct network access (use HttpClient builtin instead)
Filesystem: No direct file access (use Files builtin instead)
Workaround: Use connectors or builtins for network/file operations.
Plugins power custom business logic while maintaining security. Next: Learn about Authentication .