Skip to content

WASM Providers

Every provider is a .wasm module compiled to wasm32-wasip2 and executed in a fresh wasmtime instance per call. There is no shared state between executions — the sandbox is created, the provider runs, the result is collected, and the sandbox is destroyed.

A running provider has:

  • No network access — all I/O goes through host imports
  • No filesystem access — only WASM linear memory
  • No syscalls — minimal WASI context (no env vars, no args, no preopens)
  • No secrets — credentials are injected at the host transport layer
  • Bounded CPU — fuel metering terminates runaway computation
  • Bounded memory — allocation cap prevents memory exhaustion
  • Bounded I/O — call budget limits host import invocations
  • Bounded time — epoch-based wall-clock deadline (works even on tight loops)

LatchGate v0.1 ships two supported providers: http_api and fs. The http_api provider covers the action class that handles the majority of agent traffic — REST APIs, webhooks, web reads, and SaaS integrations. The fs provider handles filesystem operations.

ProviderWASM moduleI/O importsPurpose
http_apihttp_api.wasmio/http, io/logHTTP requests (REST APIs, webhooks, SaaS integrations)
fsfs.wasmio/fs, io/logFilesystem operations (fs_read, fs_write, fs_delete)

The http_api provider powers most of the built-in actions via template manifests. It is production-grade and requires no custom WASM code — actions are defined in YAML. The fs provider handles filesystem operations confined to the configured fs_root_path.

The following providers exist in source under providers/ and are excluded from the v0.1 workspace build. Their WIT interfaces (wit/io-database.wit, wit/io-smtp.wit, wit/io-queue.wit, wit/io-storage.wit) are committed and previewable. No action manifests are shipped for them yet. They are not loaded by the runtime in v0.1.

ProviderWIT interfaceStatus
emailio/smtpImplementation present; pending finalised transactional vs. notification email model
databaseio/databaseImplementation present; SQL classifier needs replacement with a real parser before production
queueio/queueImplementation present; AMQP fault model under review
artifact_storeio/storageImplementation present; bucket policy model being finalised

Future releases will add these action classes once each provider’s validation surface is hardened. Until then, no action manifests are shipped for these providers.

Build the supported provider:

Terminal window
make providers

Providers communicate with external systems through host-implemented import functions defined in the WIT interface files. The host layer enforces:

  • Sink validation — every target URL checked against the grant’s allowed_sinks before executing
  • Credential injection — secrets read from the kernel store, injected into outgoing requests (e.g., Authorization header, connection string) without the provider ever seeing them
  • SSRF protection — private IP blocking (loopback, RFC-1918, link-local, CGNAT, IPv6), DNS pinning (resolve-then-connect to prevent rebinding), redirect blocking, system proxy bypass
  • Timeout and size limits — per-call response time and payload size enforcement
package latchgate:provider@0.1.0;
world provider {
import io-http;
import io-fs;
import io-smtp;
import io-database;
import io-queue;
import io-storage;
import io-log;
export execute: func(task-json: string) -> result<string, string>;
}

In v0.1, io/http, io/fs, and io/log are linked at instantiation. The other imports remain in the WIT package as forward-compatible declarations for future releases. A v0.1 provider that attempts to call an unlinked import fails at instantiation.

  1. Create a Rust library targeting wasm32-wasip2:
Terminal window
cargo new --lib my_provider
cd my_provider
  1. Add the WIT bindings and implement the execute export. The provider receives a JSON task string and returns a JSON result string (or error).

  2. Declare only the I/O imports your provider actually needs. The fewer imports, the smaller the attack surface.

  3. Build:

Terminal window
cargo build --target wasm32-wasip2 --release
  1. Compute the SHA-256 digest and create a manifest YAML referencing it. Or use make providers which handles digest computation automatically.

  2. Place the .wasm in target/providers/ and the manifest in definitions/manifests/.

For a complete walkthrough with code examples, see Custom Actions.

1. Look up pre-compiled Component from cache by digest
2. Create fresh Store with HostState and resource limits
3. Create fresh Instance with only declared imports linked
4. Configure fuel limit, memory limit, I/O call budget, epoch deadline
5. Call provider's execute export
6. Collect result (or timeout/fuel-exhaustion/memory error)
7. Drop Instance + Store (sandbox destroyed)

WASM provider dispatch is bounded by a tokio::sync::Semaphore with MAX_CONCURRENT_EXECUTIONS permits (compile-time constant: 4). Excess requests wait for a permit.

For writing custom actions (YAML-only and WASM), see Custom Actions. For the system architecture and security invariants, see Architecture.