Official Plugins
Official plugins are public WebAssembly Component Model packages published by
the Sigil project under the
sigil-plugins GitHub organization. Their
immutable releases carry keyless provenance that Sigil verifies before
installation and pins in the project lock.
Run this command for the live inventory:
sigil plugin list-remoteInstall a release into the per-user cache, then add that installed release to
the project. For the first official plugin in a new directory, add creates a
minimal non-deploying project config; otherwise it preserves the existing
.sigil/sigil.toml. In Sigil 0.35.0, add can acquire a missing package through
verified remote installation before declaring the exact dependency, writing the
reproducibility lock, and generating the matching LuaLS stub. Explicit install
first makes acquisition visible and also works with older hosts.
For an existing project lock and an empty cache, run sigil plugin sync
before adding or upgrading a dependency. This restores the other locked
plugins needed to publish the complete dependency generation.
| Plugin | Release | What it does | Requested host capabilities |
|---|---|---|---|
codec | 1.1.2 | Reference plugin that echoes a u32 | None |
mysql | 0.2.1 | Stateful typed SQL for SingleStore 5.7 and complete MySQL 8 authentication | Network, named secrets, and entropy |
s3 | 0.3.0 | Bounded read-only S3 GET, HEAD, and one caller-driven list page | Network and host-owned SigV4 |
parquet | 0.2.0 | Parquet metadata plus typed cell, column, and projected-row reads with UTC-adjustment semantics | None |
temporal | 0.1.1 | Typed workflow Start, Describe, and caller-paginated History | Host-owned semantic unary gRPC |
Codec 1.1.2
Section titled “Codec 1.1.2”Codec is the small, capability-free reference plugin. It is useful for checking
that plugin installation, locking, LuaLS generation, and the Component Model
runtime work end to end. It is not a general-purpose codec library: its current
interface exports one echo-u32 function.
sigil plugin install codec@1.1.2sigil plugin add codec@1.1.2return { title = "Codec plugin is available", priority = "P1", policy = { capabilities = { "wasm.codec" } },
run = function() local codec = require("wasm.codec") expect(codec["echo-u32"](42) == 42) end,}View the immutable Codec 1.1.2 release.
MySQL 0.2.1
Section titled “MySQL 0.2.1”MySQL is a stateful, bounded Classic Protocol driver for
SingleStore’s MySQL 5.7 wire dialect and stock MySQL 8. It completes cold and
warm caching_sha2_password, server auth-switch handling, and
mysql_native_password; a wrong password is a typed authentication failure
with the server’s bounded vendor code and SQLSTATE. Sigil owns endpoint
resolution, TCP, TLS verification, timeouts, byte quotas, secret grants,
entropy, cancellation, and teardown; the component sees only a logical
endpoint and the names of specifically granted secrets.
sigil plugin install mysql@0.2.1sigil plugin add mysql@0.2.1Expose the credential names to scenarios, grant those names to this plugin,
and map its logical database endpoint to the lane-local service:
[scenario.env]MYSQL_USER = { from = "MYSQL_USER" }MYSQL_PASSWORD = { from = "MYSQL_PASSWORD" }
[plugins.grants.mysql]secrets = ["MYSQL_USER", "MYSQL_PASSWORD"]entropy = true
[plugins.grants.mysql.network.database]target = "mysql:3306"tls = "upgrade"tls_server_name = "mysql"tls_ca_file = ".sigil/certs/mysql-ca.pem"connect_timeout = "5s"io_timeout = "10s"max_connections = 2max_bytes = "16MiB"Then keep one server session across typed queries and commands:
return { title = "MySQL responds to a query", priority = "P1", policy = { capabilities = { "wasm.mysql" } },
run = function() local mysql = require("wasm.mysql") local connection, connect_error = mysql.connect({ endpoint = "database", ["username-secret"] = "MYSQL_USER", ["password-secret"] = "MYSQL_PASSWORD", database = "app", ["max-rows"] = 1000, ["max-result-bytes"] = 8 * 1024 * 1024, }) expect(connection ~= nil, connect_error and connect_error.message)
local rows, query_error = connection:query( "SELECT UNIX_TIMESTAMP(created_at), amount, nullable_note FROM records" ) expect(rows ~= nil, query_error and query_error.message) expect(rows.rows[1].cells[1].tag == "signed") expect(rows.rows[1].cells[2].tag == "decimal") expect(rows.rows[1].cells[3].tag == "null")
local command, exec_error = connection:exec("CREATE TEMPORARY TABLE probe(id BIGINT)") expect(command ~= nil, exec_error and exec_error.message) expect(command["affected-rows"] == 0) expect(command.warnings == 0)
connection:close() end,}Integers remain integers, DECIMAL remains exact text, NULL is a tagged value
rather than absent Lua data, and temporal values retain their server lexeme and
declared type. Server failures preserve bounded vendor-code and sqlstate.
A semantic row or result-byte limit returns no partial result and closes the
session; a host wire ceiling is an unmaskable plugin_infrastructure failure.
The driver never retries, reconnects, replays, or opens a replacement session
after an ambiguous failure. It does not support prepared statements, the
binary protocol, multi-statements or multi-results, or LOCAL INFILE.
View the immutable MySQL 0.2.1 release.
S3 0.3.0
Section titled “S3 0.3.0”S3 performs bounded, read-only path-style GET, HEAD, and one ListObjectsV2 page against S3-compatible stores such as MinIO. Anonymous and presigned requests remain available; private requests name an opaque SigV4 grant so the component never receives credentials, signing time, authority, or signature material. Use this release with Sigil 0.33.2 or a compatible newer release.
sigil plugin install s3@0.3.0sigil plugin add s3@0.3.0The operator owns the socket route, secrets, signed Host, methods, canonical paths, and exact query policy:
[plugins.grants.s3.network.object-store]target = "minio:9000"tls = "disabled"connect_timeout = "5s"io_timeout = "10s"max_connections = 1max_bytes = "8MiB"
[plugins.grants.s3.sigv4.private-read]endpoint = "object-store"access_key_secret = "OBJECT_STORE_ACCESS_KEY"secret_key_secret = "OBJECT_STORE_SECRET_KEY"region = "us-east-1"service = "s3"authority = "minio:9000"methods = ["GET", "HEAD"]canonical_uri_prefixes = ["/results/exports/"]query = {}header_names = []
[plugins.grants.s3.sigv4.results-list]endpoint = "object-store"access_key_secret = "OBJECT_STORE_ACCESS_KEY"secret_key_secret = "OBJECT_STORE_SECRET_KEY"region = "us-east-1"service = "s3"authority = "minio:9000"methods = ["GET"]canonical_uri_prefixes = ["/results/"]header_names = []
[plugins.grants.s3.sigv4.results-list.query.list-type]required = trueexact_values = ["2"]
[plugins.grants.s3.sigv4.results-list.query.max-keys]required = truedecimal_max = 1000
[plugins.grants.s3.sigv4.results-list.query.prefix]required = trueencoded_prefixes = ["exports%2F"]
[plugins.grants.s3.sigv4.results-list.query.continuation-token]required = falseopaque_max_encoded_bytes = 6144The secret names must also be present in the scenario environment allowlist. The scenario drives pagination explicitly and composes list, metadata, and exact-byte reads:
local s3 = require("wasm.s3")local page, list_error = s3["list-objects"]({ bucket = "results", prefix = "exports/", ["max-keys"] = 100, ["continuation-token"] = nil, auth = { tag = "sigv4", value = "results-list" },})expect(page ~= nil, list_error and list_error.message)
local key = page.objects[1].keylocal metadata, head_error = s3["head-object"]({ bucket = "results", key = key, auth = { tag = "sigv4", value = "private-read" },})expect(metadata ~= nil, head_error and head_error.message)
local bytes, get_error = s3["get-object"]({ bucket = "results", key = key, auth = { tag = "sigv4", value = "private-read" }, ["max-bytes"] = 4 * 1024 * 1024,})expect(bytes ~= nil, get_error and get_error.message)Each listed object returns a string key, unsigned size, exact optional ETag,
and unnormalized optional Last-Modified text. A truncated page returns one
opaque next-continuation-token; the plugin never follows it automatically.
Host API 1.2 validates the token’s allowed canonical ASCII form and encoded
length under the grant before signing or I/O. The host does not add token
contents to diagnostics or evidence; scenario Lua receives the token, so code
that explicitly logs or attaches it remains responsible for that disclosure.
GET reserves its body ceiling plus exactly 64 KiB of response framing; LIST
reserves 4 MiB plus 64 KiB. A reservation outside the network grant is an
uncatchable PLUGIN_RESOURCE_LIMIT/plugin_infrastructure failure. A body
over the plugin’s own ceiling returns nil, {class = "limit", ...} with no
partial bytes. HEAD returns optional size, ETag, and exact Last-Modified text
without reading a body. The plugin exposes no write, delete, bucket-management,
range, redirect, retry, or fallback operation.
View the immutable S3 0.3.0 release.
Parquet 0.2.0
Section titled “Parquet 0.2.0”Parquet accepts a complete file as a binary Lua string, reports flat leaf metadata, and reads one typed scalar cell, a bounded column window, or a projected row window. It has no filesystem or network capability. The intended object-store flow composes it with S3 in the scenario, without making either plugin depend on the other:
sigil plugin install s3@0.3.0sigil plugin install parquet@0.2.0sigil plugin add s3@0.3.0sigil plugin add parquet@0.2.0Use the S3 endpoint grant from the preceding section, then pass the downloaded bytes directly to Parquet:
return { title = "Read projected rows from a Parquet object", priority = "P1", policy = { capabilities = { "wasm.s3", "wasm.parquet" } },
run = function() local s3 = require("wasm.s3") local parquet = require("wasm.parquet")
local bytes, download_error = s3["get-object"]({ bucket = "results", key = "exports/run/output.parquet", auth = { tag = "sigv4", value = "private-read" }, ["max-bytes"] = 4 * 1024 * 1024, }) expect(bytes ~= nil, download_error and download_error.message)
local names, column_error = parquet["read-column"](bytes, { column = "last_name", offset = 0, limit = 3, }) expect(names ~= nil, column_error and column_error.message)
local batch, rows_error = parquet["read-rows"](bytes, { columns = { "last_name", "event_epoch_s", "amount" }, offset = 0, limit = 3, }) expect(batch ~= nil, rows_error and rows_error.message) expect(batch.rows[1].cells[3].tag == "decimal") end,}Rows are positional in the exact order of batch.columns. Duplicate, unknown,
nested, repeated, or unsupported projected columns fail before page decode.
An out-of-bounds row window returns not-found and is never silently clamped
to a shorter successful result. NULL remains tagged, decimal keeps exact
precision, scale, and unscaled bytes, and timestamp cells retain their raw
integer, unit, and is-adjusted-to-utc boolean; the reader never normalizes
the value a scenario is trying to assert. Required or optional non-repeated scalar columns,
plain or dictionary encoding, and uncompressed or Snappy pages are supported.
INT96, nanosecond temporal values, external column chunks, and other compression
codecs fail explicitly. Input is capped at 16 MiB.
Version 0.2.0 corrects the WIT shape to preserve Parquet’s isAdjustedToUTC.
Structured column metadata returns is-adjusted-to-utc as true or false
for TIME/TIMESTAMP annotations and nil for non-temporal columns. Every time
or timestamp cell carries the required boolean beside its raw value and unit;
false must not be treated as missing. The existing logical_type string
is unchanged. Regenerate editor stubs when updating the dependency.
View the immutable Parquet 0.2.0 release.
Temporal 0.1.1
Section titled “Temporal 0.1.1”Temporal provides exactly three WorkflowService operations through
require("wasm.temporal"): start-workflow-execution,
describe-workflow-execution, and get-workflow-execution-history.
It requires Sigil >=0.35.0, exact Host API 1.3.0, and manifest
schema 4. It requests grpc-unary, not raw network or secret access.
The minimum-only Sigil requirement removes the evaluator minor ceiling; it
does not bypass host-interface checks or certify future hosts. The application
WIT and fixed Start identity remain 0.1.0 / sigil-temporal@0.1.0.
Sigil 0.35.1 adds operator denial guidance and recognizes semantic endpoint use in unused-network-grant warnings. These host diagnostics are distinct from the plugin’s compatibility requirement.
For an existing locked project, restore its pinned packages first:
sigil plugin syncThen install and pin the stable release:
sigil plugin install temporal@0.1.1sigil plugin add temporal@0.1.1sigil plugin syncDeclare "wasm.temporal" in each calling scenario’s capabilities. The operator
owns the named profile, RPC aliases, namespace/workflow constraints, route,
TLS policy, credentials, and transport limits. Each plugin call makes at most
one host exchange. The plugin never retries, sleeps, reconnects, or follows
history pages automatically. A Start failure with an unknown mutation outcome
must not become an automatic retry.
See Semantic gRPC for Plugins for operation aliases, request identity, History flags, and timeout ceilings. The versioned Temporal README provides the operator configuration and caller contract.
Opt-in Lua companion
Section titled “Opt-in Lua companion”The companion source
is copied project Lua, not another WASM export and not installed by plugin add.
Copy it unchanged into your scenario library as lib/temporal.lua, record the
source version and file hash, and use require("lib.temporal"). Every transitive
caller declares wasm.temporal, even for decoder-only use of this module.
It provides run, wait_after_start, bounded history, completion-aware
result, and optional one-layer decode_json. Existing temporal_poll.lua
callers are not switched automatically. Preserve the application’s status and
payload representation when adopting it; richer helper returns are not a reason
to change product assertions. See helper semantics and limits.
View the immutable Temporal 0.1.1 release.
The earlier Temporal 0.1.0 release
retains its immutable >=0.35.0, <0.36.0 requirement, so Sigil 0.36.0 and
later refuse it. Upgrade a project that locks 0.1.0 to 0.1.1 before moving to
Sigil 0.36.0. Installing 0.1.1 does not rewrite old packages or locks.
Commit the dependency generation
Section titled “Commit the dependency generation”After adding plugins, commit the complete reproducibility generation and lint the scenarios:
git add .sigil/sigil.toml .sigil/sigil.plugins.lock .sigil/types/wasmsigil scenario lintSee Using Plugins for locking, syncing, updates, removal, third-party sources, and CI behavior.