A Plugin Development Kit (PDK) for building Extism plugins in C# using .NET NativeAOT, compiled to WebAssembly.
Write your plugin exports as regular C# methods, annotate them with [ExtismExport], and the included source generator + MSBuild targets handle the rest — WIT generation, WASM compilation, component-model unbundling, and optional WASI stubbing.
The project has three main components:
- Extism.Pdk.NativeAot — The PDK library. Provides the
PdkAPI (input/output, memory, config, variables, logging, HTTP) and MSBuild integration that automatically configures NativeAOT-to-WASM compilation. - Extism.Pdk.SourceGenerator — A Roslyn source generator that finds
[ExtismExport("name")]attributes and generates theUnmanagedCallersOnlywrapper functions, handling serialization/deserialization of strings, byte arrays, primitives, multi-parameter packing, and FlatBuffers types. - clip.py — A post-publish tool that strips the WASM Component Model wrapper, optionally stubs WASI imports, and converts namespaces so the resulting
.wasmfile is a bare module compatible with the Extism runtime.
- .NET 10 SDK
- Python 3.10+ — used by
clip.pyduring post-publish - wasm-tools — the Bytecode Alliance
wasm-toolsCLI (wasm-tools component unbundleandwasm-tools parsemust be on your PATH)
dotnet publish samples/extism-plugin-dotnet/ExtismPluginExample.csproj -c ReleaseThis compiles the plugin to WASM via NativeAOT, then automatically runs clip.py to produce the final ExtismPluginExample_clipped.wasm.
To keep wasi:* imports in the clipped output, set this in your plugin .csproj:
<PropertyGroup>
<ExtismClipKeepWasiImports>true</ExtismClipKeepWasiImports>
</PropertyGroup>To keep stubbing enabled but bridge key WASI P2 calls through wasi_snapshot_preview1
imports (including random/clock/exit, basic stdio handles, and preopen directory
enumeration), set:
<PropertyGroup>
<ExtismClipWasiP1Bridge>true</ExtismClipWasiP1Bridge>
</PropertyGroup>dotnet run --project samples/extism-host-dotnet/ExtismHostExample.csprojThe host loads the clipped WASM plugin and calls every exported function, demonstrating string, numeric, binary, and FlatBuffers round-trips.
- Reference
Extism.Pdk.NativeAotand import its.props/.targetsin your.csproj. - Write static methods and annotate them with
[ExtismExport("name")]:
using Extism.Pdk;
public static class Plugin
{
[ExtismExport("greet")]
public static string Greet(string name) => $"Hello, {name}!";
[ExtismExport("add")]
public static int Add(int a, int b) => a + b;
}| Category | Parameter | Return |
|---|---|---|
string |
yes | yes |
byte[] |
yes | yes |
Primitives (bool, byte, sbyte, short, ushort, int, uint, long, ulong, float, double) |
yes | yes |
void |
— | yes |
FlatBuffers (IFlatbufferObject) |
yes | yes |
Multi-parameter exports are supported when all parameters are primitives (packed as little-endian bytes).
clip.pyis based on the original clip.lua by Pspritechologist- NativeAOT LLVM/WASM backend by SingleAccretion and yowl