Skip to Content
CapabilitiesCode (Wasm)Wasm Executor

Code (Wasm)

A wasm capability runs a WebAssembly module you wrote. Use it when a capability needs logic the other executors cannot express: combining several files, transforming data, or calling an API in more than one step. The agent includes the runtime, so the agent host needs no compiler or extra software.

The usual way to write a module is in Go with the Onprest SDK; see Writing code in Go. This page covers how the agent runs it.

capabilities: customer_report: executor: type: wasm module: ./customer-report.wasm effects: none sandbox: enabled: true permissions: filesystem: [{root: ./templates, access: read}] input: properties: customer: {type: string, pattern: '^[A-Za-z0-9 ]{1,64}$'} required: [customer] output: data: {} files: {}

The module receives the validated input and returns data and files. As with every executor, only what output declares reaches the caller.

Executor settings

KeyDefaultMeaning
modulerequiredPath to the .wasm file, relative to the configuration directory
sha256noneExpected SHA-256 of the module, as 64 lowercase hex characters. The agent refuses to start if the file differs
effectspossiblenone or possible: whether the code may change anything. Published as metadata only
sandbox{enabled: false}What the code may access; see below
limitssee belowMemory and I/O budgets

Modules must be built with onprest-agent code build (or carry the same metadata). At startup and in validate, the agent compiles the module and checks its metadata, imports, and size without running it.

This check must finish within 60 seconds per module, a limit you cannot change. Otherwise the agent refuses to start, and validate and the code commands fail with Wasm module validation did not finish within 1m0s. Retry on a less busy host, give it more CPU, or make the module smaller, for example by removing dependencies it does not need.

Sandbox

The sandbox is off by default. With sandbox.enabled: false, the code can read and write any file and reach any network address that the agent’s operating-system user can, and it sees the agent’s environment variables. Run the agent as a dedicated user with narrow permissions if you use code this way.

With sandbox.enabled: true, the code can access nothing except what permissions grants:

sandbox: enabled: true permissions: filesystem: - {root: ./templates, access: read} - {root: /srv/exchange/out, access: read_write} http: - origin: https://inventory.internal.example methods: [GET] path_prefix: /v1/stock environment: [TZ]
PermissionFields
filesystemroot (absolute or relative to the configuration directory) and access: read or read_write
httporigin, methods, path_prefix, and optional allowed_cidrs. Without allowed_cidrs, the same address rules as for HTTP sources apply. HTTPS certificates are verified and proxy variables are ignored
environmentNames of environment variables the code may read

Files uploaded in the current call are always readable by that call, even with no permissions. Leave out permissions entirely when the sandbox is off.

The sandbox limits what the code can reach, not what it does with it. Code with an HTTP grant can send any data it can read to that destination, and file changes or HTTP requests it makes are not rolled back when the call fails. Review the code and how it uses its input, especially input that selects a path or a destination.

Inside the module, relative paths and the working directory are the agent’s configuration directory, in both modes. On Windows, absolute paths use a WASI form: C:\service\data is /volumes/C/service/data, and a UNC path \\server\share\data is /unc/server/share/data.

Limits

Set these under executor.limits. All must be positive. Each call runs separately, so every limit except the module size applies within one call.

KeyDefaultMeaning
memory_bytes128MiBMemory the module may use, between 64KiB and 4GiB
max_module_bytes32MiBSize of the .wasm file, checked at startup and in validate
max_handles64Things the code can have open at once: files and directories, uploaded files, returned files being written, and HTTP request and response bodies
max_host_calls8File or HTTP operations that can be in progress at the same time, for example from several goroutines
max_file_read_bytes, max_file_write_bytes64MiB eachBytes read from, or written to, one file
max_total_file_read_bytes, max_total_file_write_bytes256MiB eachBytes read, or written, across all files in the call
max_file_operations65536Number of file operations, such as opening, reading, writing, or listing
max_http_request_bytes, max_http_response_bytes32MiB eachBody size of one HTTP request the code sends, or one response it receives

File and HTTP budgets count every byte the code reads or writes during the call, including reopened files. Going over any limit other than memory_bytes and max_module_bytes fails that operation with a limit error (onprest.ErrLimitExceeded in the SDK); if the code does not handle it, the call fails with LIMIT_EXCEEDED. The usual policy limits such as timeout apply as well.

Results, errors, and logs

The module’s return value becomes data and its returned files become files, then pass through output selection like any other executor.

An ordinary error from the code fails the call with EXECUTION_FAILED and a generic message. To show the caller a specific business error, return an application error with a code such as APP_CUSTOMER_NOT_FOUND and a message; REST returns it with HTTP 422. See Errors.

Log messages from the SDK and anything the module writes to stdout or stderr go to the agent’s local log, not to the caller. HTTP requests made by the code are sent once without retries, and redirects are followed only if the code enables them.

Without the SDK

The SDK is the supported way to write modules. The raw host ABI example  shows a module that talks to the agent directly, for readers who want to see the low-level interface.