stanchion Guides GitHub
MIT or Apache-2.0

stanchion

Lua plugins for Rust applications. A stanchion both bears load and marks a boundary — which is what this does: typed contracts and dependency wiring on one side, sandboxing, capabilities and signatures on the other.

Read the guides View on GitHub

Describe the contract in Rust

Write a trait. #[lua_class] generates the class handle, the instance handle, and the conversions — and validates the contract when a plugin loads, not when a method is finally called at 3am.

#[lua_class]
pub trait Greeter {
    fn new(greeting: String) -> Result<Self>;
    fn greet(&self, who: String) -> Result<String>;

    #[lua(field)]
    fn greeting(&self) -> Result<String>;

    #[lua(optional)]
    fn on_unload(&self) -> Result<Option<()>>;

    async fn fetch(&self, url: String) -> Result<String>;
}

Implement it in Lua

An ordinary Lua class. The trait stays dyn-compatible, so a native Rust implementation drops into the same Vec<Box<dyn Greeter>>.

local Greeter = {}
Greeter.__index = Greeter

function Greeter.new(greeting)
  return setmetatable({ greeting = greeting }, Greeter)
end

function Greeter:greet(who)
  return self.greeting .. ", " .. who
end

return Greeter

Seven layers, each optional

Every layer is a feature you turn on. Depend on the facade, take what you need, and pay for nothing else — the sigstore verifier alone brings a large dependency graph, so it lives in its own crate.

Typed contracts

A Rust trait becomes a Lua class binding. Tables or userdata; sync or async.

A plugin registry

Manifests, discovery, dependency order, hot reload, and per-plugin failure isolation.

Isolation

One shared state, one per dependency group, or one per plugin — with VM-enforced memory and per-call instruction limits.

Declared capabilities

A plugin asks; your policy grants, narrows, or refuses. Deny by default.

Signatures

Sigstore-backed provenance over every file — and provenance can tier what a plugin may reach.

Distribution

Packages, an index anyone can host, lockfile pinning, and an upgrade review before you trust it.

Out of process

Run plugins in a child over JSON-RPC, so a crash inside the interpreter is survivable.

What a crash costs you

In-process limits stop a runaway plugin. They cannot stop a segfault in a C rock, or rescue a state whose allocator already failed.

The plugin doesIn processOut of process
while true do endinstruction limitinstruction limit
allocation stormmemory limitmemory limit
os.exit, or a C-rock segfaultyour application diesRemoteError::HostGone
interpreter panicunwinds into your stackthe child dies; you keep serving

Built for

Semi-trusted authors: your team, your customers under contract, a curated community. The capability and signature guides cover what changes when the authors are strangers.

Editors and developer tools

Plugins depending on a shared utilities plugin, reloaded on save without a restart.

Games with mod support

Load-ordered mods, one broken mod reported rather than fatal, and a per-mod instruction budget.

Programmable gateways

Per-route transforms authored outside the binary, dispatched asynchronously.

Rules and alerting

Customer-authored detection logic, where a first-party signature earns network access.

Multi-tenant business rules

Pricing and eligibility per tenant, in their own state, without a deploy.

Data pipelines

Analysts write transforms and get real libraries from LuaRocks, not a bare interpreter.

The crates

A facade plus the layers behind it, so heavy dependencies stay optional.

CrateHolds
stanchionthe facade, and the plugin-host binary
stanchion-corethe #[lua_class] contract
stanchion-macrosthe attribute macro
stanchion-registrymanifests, sandboxing, capabilities, signatures, reload
stanchion-rocksLuaRocks trees and version constraints
stanchion-sigstorekeyless verification, quarantining a large graph
stanchion-remoteout-of-process hosting over JSON-RPC 2.0
stanchion-distpackages, the index protocol, pinned installs
stanchion-indexserving an index, framework-neutral

Guides

Rendered from the repository's own documentation, so they cannot drift from it.