Skip to main content
Understand the structure of a Noorle plugin and what each file does.

Directory Layout

After creating a new plugin with noorle plugin new my-plugin, you’ll have:
my-plugin/
├── src/
│   ├── lib.rs            (main implementation)
│   └── ...
├── Cargo.toml            (Rust dependencies)
├── noorle.yaml           (plugin metadata & config)
├── world.wit             (component interface definition)
├── .env                  (environment variables)
├── .env.example          (example env template)
├── .gitignore
├── README.md
└── Cargo.lock

Required Files

plugin.wasm

The compiled WebAssembly module. This file:
  • Is generated during noorle plugin build
  • Contains your plugin’s entire compiled implementation
  • Must target WASI Preview 2
  • Is included in the .npack archive when uploaded
You don’t create this manually — it’s the output of compilation.

Configuration Files

noorle.yaml

Metadata and configuration for your plugin. Must be in the root directory.
schema_version: "1.0"

metadata:
  name: "my-plugin"
  description: "Does something useful"
  author: "Your Name"
  license: "MIT"
  tags:
    - "data-processing"

runtime: "v1"

permissions:
  network:
    allow:
      - host: "api.example.com"

  filesystem:
    allow:
      - uri: "fs://work/agent/**"
        access: [read, write]

  environment:
    allow:
      - key: "API_KEY"

resources:
  limits:
    memory: "512Mi"
    timeout: "30s"
See the Configuration Reference for all options.

.env (Optional)

Environment variables available to your plugin at runtime.
API_KEY=sk-1234567890
DATABASE_URL=postgres://localhost/mydb
DEBUG=true
LOG_LEVEL=info
Important:
  • Not included in version control (use .env.example)
  • Values are encrypted at rest
  • Only accessible within your plugin’s sandbox
  • Set via CLI: noorle env set KEY=value
Template showing required environment variables without actual values.
API_KEY=
DATABASE_URL=
DEBUG=false
LOG_LEVEL=info
Commit this to version control so others know what env vars are needed.

Source Files

Rust (src/)

src/
├── lib.rs         (main entry point)
├── tools.rs       (tool implementations)
├── models.rs      (data structures)
└── utils.rs       (utilities)
lib.rs is the entry point. Export your tools as public functions:
pub fn my_tool(input: String) -> String {
    format!("processed: {}", input)
}

Python

src/
├── __init__.py       (entry point)
├── tools.py          (tool implementations)
└── utils.py          (utilities)
Define tools as module-level functions:
def my_tool(input: str) -> str:
    return f"processed: {input}"

TypeScript

src/
├── index.ts          (entry point)
├── tools.ts          (tool implementations)
└── utils.ts          (utilities)
Export tools as module functions:
export function myTool(input: string): string {
  return `processed: ${input}`;
}

Interface Definition (world.wit)

Component Model interface defining your exported tools. Auto-generated but can be customized.
package noorle:plugin;

interface tools {
  my-tool: func(input: string) -> string;
  another-tool: func(x: i32, y: i32) -> i32;
}

world my-plugin {
  export tools;
}
This defines:
  • Tool names and signatures
  • Parameter types and return types
  • Used for introspection and discovery

Build Configuration

Cargo.toml (Rust)

[package]
name = "my-plugin"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }

[lib]
crate-type = ["cdylib"]

[profile.release]
opt-level = "z"
lto = true
Key settings for plugin development:
  • crate-type = ["cdylib"] — Compile to WebAssembly component
  • Use [profile.release] for optimization
  • Minimize dependencies to reduce WASM size

package.json (TypeScript)

{
  "name": "my-plugin",
  "version": "0.1.0",
  "main": "src/index.ts",
  "scripts": {
    "build": "noorle plugin build",
    "test": "npm test"
  },
  "dependencies": {
    "@componentize/component-model": "^0.5.0"
  }
}

pyproject.toml (Python)

[project]
name = "my-plugin"
version = "0.1.0"

[build-system]
requires = ["setuptools", "componentize-py"]

File Inclusion Rules

When you run noorle plugin build, the CLI:
  1. Always includes:
    • plugin.wasm (compiled output)
    • noorle.yaml (if present)
  2. Optionally includes (if present):
    • world.wit
    • .env (encrypted before inclusion)
  3. Never includes:
    • src/ directory (source code)
    • Cargo.toml, package.json, pyproject.toml
    • .git/, node_modules/, target/
    • Files in .gitignore

.npack Archive Format

The final .npack file is a gzip-compressed tar archive:
my-plugin-v1.npack (tar.gz)
├── plugin.wasm          (50KB)
├── noorle.yaml          (1KB)
└── world.wit            (2KB)
Extract and inspect:
tar -tzf my-plugin-v1.npack
# Output:
# plugin.wasm
# noorle.yaml
# world.wit

Size Optimization

Keep your plugin small for faster uploads and execution:

Minimize Dependencies

# ❌ Don't include everything
tokio = { version = "1.0", features = ["full"] }

# ✅ Include only what you need
tokio = { version = "1.0", features = ["sync"] }

Enable Optimizations

[profile.release]
opt-level = "z"        # Optimize for size
lto = true             # Enable LTO
strip = true           # Strip symbols

Typical Sizes

  • Simple plugin: 100KB - 500KB
  • Medium plugin: 500KB - 2MB
  • Complex plugin: 2MB - 5MB
Plugins larger than 10MB may have issues with some deployment environments.

Testing Your Plugin

Local Testing

Before uploading, test your plugin locally:
# Build the plugin
noorle plugin build

# Run tests (language-specific)
cargo test                    # Rust
pytest tests/                 # Python
npm test                      # TypeScript
go test ./...                 # Go

# Simulate execution
noorle plugin invoke my-tool --input '{"param": "value"}'

Version Management

After uploading, previous versions are preserved:
my-plugin (Capability)
├── v1 (previous)
├── v2 (previous)
└── v3 (active)
Change the active version via Console or CLI:
noorle plugin activate my-plugin --version 2

Next Steps