WASI Documentation

WebAssembly System Interface

5,825 stars Rust Rust 21 files ยท ~17,543 tokens #http#os#wasi#webassembly
RAW Doc

Technical Documentation: WebAssembly/WASI

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

WebAssembly System Interface

The WebAssembly System Interface (WASI) is a set of APIs for WASI being
developed for eventual standardization by the WASI Subgroup, which is a
subgroup of the WebAssembly Community Group.

WASI started with launching what is now called Preview 1, an API using
the witx IDL, and it is now widely used. Its major influences are POSIX and
CloudABI.

WASI 0.2 (Preview 2) is a modular collection of APIs defined with the Wit IDL,
incorporating many of the lessons learned from WASI 0.1, including support for
a wider range of source languages, modularity, a more expressive type system,
and virtualizability.

WASI 0.3 (Preview 3) is the current preview. It builds on WASI 0.2, replacing
the earlier explicit streams and polling interfaces with the component model's
native, composable async functionality via the future and stream types.

Find the APIs

Development of each API happens in its own repo, which you can access
from the proposals list.

This repo is for general discussion, as well as documenting how we work
and high-level goals.

Propose a new API

If you would like to create a new proposal, get started with our
Contributing guide.

All new API proposals should use the new format and the new repo structure that is shown in the proposal template.

See the Wit in WASI document for more information about using Wit for WASI proposals.


Overview (`.github/scripts/README.md`)

CI Scripts

cm-features.js

Reads the Component Model adoption record in docs/ComponentModelFeatures.md,
which is the single source of truth for which gated features WASI requires.

  • publish.yml runs it to write the "Component Model features" section of each
    released specifications/wasi-<version>/Overview.md.
  • validate-proposals.js imports readRecord from it to build the
    wasm-tools validate feature flags.
bash
# Print the section for a given version
node .github/scripts/cm-features.js 0.3.1

validate-proposals.js

Validates WIT definitions for changed proposals. Used by the CI workflow.

Prerequisites

Running Locally

bash
# Validate specific proposals by simulating changed files
WIT_FILES='["proposals/cli/wit/command.wit"]' node .github/scripts/validate-proposals.js

# Validate multiple proposals
WIT_FILES='["proposals/cli/wit/command.wit", "proposals/http/wit/worlds.wit"]' node .github/scripts/validate-proposals.js

Environment Variables

Variable Description
WIT_FILES JSON array of changed files in proposals/*/wit/**

What it validates

  1. wit-deps lock - If deps.toml exists, checks that deps.lock is up to date
  2. WIT syntax - Parses WIT files with Wasm-tools component wit
  3. Wasm encoding - Validates Wasm binary encoding with --Wasm flag

Overview (`proposals/cli/README.md`)

WASI CLI World

A proposed WebAssembly System Interface API.

Current Phase

wasi-cli is currently in Phase 3.

Champions

  • Dan Gohman

Portability Criteria

WASI CLI must have host implementations which can pass the testsuite
on at least Windows, macOS, and Linux.

WASI CLI must have at least two complete independent implementations.

Table of Contents

Introduction

Wasi-cli a World proposal for a Command-Line Interface (CLI) environment. It provides APIs commonly available in such environments, such as filesystems and sockets, and also provides command-line facilities such as command-line arguments, environment variables, and stdio.

Goals

Wasi-cli aims to be useful for:

  • Interactive command-line argument programs.

  • Servers that use filesystems, sockets, and related APIs and expect to be started with
    a CLI-style command-line.

  • Stream filters that read from standard input and write to standard output.

Non-goals

Wasi-cli is not aiming to significantly re-imagine the concept of command-line interface programs. While WASI as a whole is exploring ideas such as Typed Main, wasi-cli sticks to the traditional list-of-strings style command-line arguments.

API walk-through

The full API documentation can be found here.

TODO [Walk through of how someone would use this API.]

[Use case 1]

[Provide example code snippets and diagrams explaining how the API would be used to solve the given problem]

[Use case 2]

[etc.]

Detailed design discussion

Should stdout be an `output-stream`?

For server use cases, standard output (stdout) is typically used as a log,
where it's typically not meaningfully blocking, async, or fallible. It's just
a place for the program to send messages to and forget about them. One option
would be to give such use cases a dedicated API, which would have a single
function to allow printing strings that doesn't return a result, meaning it
never fails.

However, it'd only be a minor simplification in practice, and dedicated cloud
or edge use cases should ideally migrate to more specialized worlds than the
wasi-cli world anyway, as they can result in much greater simplifications, so
this doesn't seem worthwhile.

Should stderr be an `output-stream`?

This is similar to the question for stdout, but for standard error (stderr),
it's a little more tempting to do something like this because stderr is used
in this logging style by many kinds of applications.

However, it seems better overall to keep stderr consistent with stdout, and
focus our desires for simplification toward other worlds, which can achieve
even greater simplifications.

Should environment variables be arguments to `command`?

Environment variables are useful in some non-cli use cases, so leaving them
as separate imports means they can be used from worlds that don't have a
command entrypoint.

Stakeholder Interest & Feedback

TODO before entering Phase 3.

[This should include a list of implementers who have expressed interest in implementing the proposal]

References & acknowledgements

The concept of wasi-cli has been in development for over a year since the proposal is
posted here, and many people have contributed ideas that have influenced. Many thanks
for valuable feedback and advice in particular from:

  • Luke Wagner
  • Pat Hickey

Overview (`proposals/clocks/README.md`)

WASI Clocks

A proposed WebAssembly System Interface API.

Current Phase

WASI-clocks is currently in Phase 3.

Champions

  • Dan Gohman

Portability Criteria

WASI clocks must have host implementations which can pass the testsuite
on at least Windows, macOS, and Linux.

WASI clocks must have at least two complete independent implementations.

Table of Contents

Introduction

WASI Clocks is a WASI API for reading the current time and measuring elapsed
time.

Unlike many clock APIs, WASI Clocks is capability-oriented. Instead
of having functions that implicitly reference a clock, WASI Clocks' APIs are
passed a clock handle.

Goals

The primary goal of WASI Clocks is to allow users to use WASI programs to
read the current time and to measure elapsed time.

Non-goals

WASI Clocks is not aiming to cover date formatting, or modifying the time of a clock.

API walk-through

Measuring elapsed time

The monotonic clock APIs can be used to measure the elapsed time of a region of code:

wit
default-monotonic-clock: monotonic-clock
rust
let start: Mark = monotonic_clock::now(clock);

   // some stuff

   let stop: Mark = monotonic_clock::now(clock);

   let elapsed: Duration = stop - start;

Telling the current human time:

rust
let the_current_time = system_clock::now();

    println!("it has been {} seconds and {} nanoseconds since the Unix epoch!", the_current_time.seconds, the_current_time.nanoseconds);

Retrieving the timezone:

rust
let instant: Instant = system_clock::now();
    let id = timezone::id();
    let offset_h = timezone::utc_offset(instant) as f64 / 3600e9;
    println!("the timezone is {} at UTC{:+}", id, offset_h);

Detailed design discussion

What should the type of a timestamp be?

In POSIX, clock_gettime uses a single timespec type to represent timestamps
from all clocks, with two fields: seconds and nanoseconds. However, in applications
that just need to measure elapsed time, and don't need to care about absolute
time, working with seconds and nanoseconds as separate fields adds extra code size
and complexity. For these use cases, a single 64-bit nanoseconds value, which can
measure up to about 584 years, is sufficient and simpler.

For system time, it's still useful to have both seconds and nanoseconds, both
to be able to represent dates in the far future, and to reflect the fact that
code working with system time will often want to treat seconds and fractions
of seconds differently.

And so, this API uses different data types for different types of clocks.

Considered alternatives

Per-process and per-thread clocks

WASI preview1 included two clocks which measured the CPU time of the current process and the current thread, respectively. These clocks are difficult to implement efficiently in WASI implementations that have multiple wasm instances in the same host process, so they've been omitted from this API.

Wasi-libc has support for emulating these clocks, by using the monotonic clock instead, which isn't a technically precise replacement, but is enough to ensure minimal compatibility with existing code.

Stakeholder Interest & Feedback

TODO before entering Phase 3.

Preview1 has monotonic and wall clock functions, and they're widely exposed in toolchains.

References & acknowledgements

Many thanks for valuable feedback and advice from:

  • [Person 1]
  • [Person 2]
  • [etc.]

Development

Generating imports.md

The file imports.md is generated using wit-bindgen.

bash
wit-bindgen markdown wit --html-in-md --features clocks-timezone

Overview (`proposals/filesystem/README.md`)

WASI filesystem

A proposed WebAssembly System Interface API.

Current Phase

WASI-filesystem is currently in Phase 3.

Champions

  • Dan Gohman

Portability Criteria

WASI filesystem must have host implementations which can pass the testsuite
on at least Windows, macOS, and Linux.

WASI filesystem must have at least two complete independent implementations.

Table of Contents

Introduction

WASI filesystem is a WASI API primarily for accessing host filesystems. It
has functions for opening, reading, and writing files, and for working with
directories.

Unlike many filesystem APIs, WASI filesystem is capability-oriented. Instead
of having functions that implicitly reference a filesystem namespace,
WASI filesystems' APIs are passed a directory handle along with a path, and
the path is looked up relative to the given handle, and sandboxed to be
resolved within that directory. For more information about sandbox, see
WASI filesystem path resolution.

WASI filesystem hides some of the surface differences between Windows and
Unix-style filesystems, however much of its behavior, including the
semantics of path lookup, and the semantics of files, directories, and
symlinks, and the constraints on filesystem paths, is host-dependent.

WASI filesystem is not intended to be used as a virtual API for accessing
arbitrary resources. Unix's "everything is a file" philosophy is in conflict
with the goals of supporting modularity and the principle of least authority.

Many of the ideas related to doing capability-based filesystem sandboxing with
openat come from CloudABI and
Capsicum.

Goals

The primary goal of WASI filesystem is to allow users to use WASI programs to
access their existing filesystems in a straightforward and efficient manner.

Non-goals

WASI filesystem is not aiming for deterministic semantics. That would either
require restricting it to fully controlled private filesystems, which would
conflict with the goal of giving users access to their existing filesystems,
or requiring implementations to do a lot of extra work to emulate specific
defined behaviors, which would conflict with the goal of being efficient.

API walk-through

Opening a file

rust
/// Write "Hello, World" into a file called "greeting.txt" in `dir`.
fn write_hello_world_to_a_file(dir: Descriptor) -> Result<(), Errno> {
    let at_flags = AtFlags::FollowSymlinks;
    let o_flags = OFlags::Create | OFlags::Trunc;
    let descriptor_flags = DescriptorFlags::Write;
    let mode = Mode::Readable;
    let file =
        dir.openat(at_flags, "greeting.txt", o_flags, descriptor_flags, mode)?;
    let message = b"Hello, World\n";
    let mut view = &message[..];
    let mut offset = 0;
    while !view.is_empty() {
        let num_written = file.pwrite(view.to_owned(), 0)?;
        offset += num_written;
        view = &view[num_written..];
    }
    // The file descriptor is closed when it's dropped!
}

Perhaps the biggest change from the preview1 version of openat, called
path_open, is the removal of the rights flags. Preview1 associates
a set of flags with every file descriptor enumerating which operations
may be performed on it, such as reading, writing, appending, truncating,
and many other operations. In practice, this created a lot of ambiguity
about how it mapped to POSIX semantics, as it doesn't directly correspond
to any feature in POSIX, or in Windows either.

The other major change from preview1 is the introduction of the mode
argument, which controls the permissions of the generated file. There
was no way to control permissions in preview1, so this is new
functionality.

Streaming read from a file

TODO

Reading from a directory

fn read_entries(dir: Descriptor) -> Result<(), Errno> {
// TODO: Implement this example.
}

[etc.

Detailed design discussion

Should WASI filesystem be case-sensitive, case-insensitive, or platform-dependent?

Even just among popular platforms, there are case-sensitive and
case-insensitive filesystems in wide use.

It would be nice to have an API which presented consistent behavior across
platforms, so that applications don't have to worry about subtle differences,
and subtle bugs due to those differences.

However, implementing case sensitivity on a case-insensitive filesystem, or
case-insensitivity on a case-sensitive filesystem, are both tricky to do.

One issue is that case insensitivity depends on a Unicode version, so the
details can differ between different case-insensitive platforms. Another
issue is the WASI filesystem in general can't assume it has exclusive access
to the filesystem, so approaches that involve checking for files with names
that differ only by case can race with other processes creating new files.

Considered alternatives

Fully deterministic filesystem

The main tradeoff with full determinism is that it makes it difficult to access existing filesystems that the Wasm runtime doesn't have full control over. This proposal is aiming to address use cases where users have existing filesystems they want to access.

Stakeholder Interest & Feedback

TODO before entering Phase 3.

Preview1 has a similar filesystem API, and it's widely exposed in toolchains.

References & acknowledgements

Many thanks for valuable feedback and advice from:

  • [Person 1]
  • [Person 2]
  • [etc.]

Overview (`proposals/http/README.md`)

WASI HTTP

A proposed WebAssembly System Interface API.

Current Phase

wasi-http is currently in Phase 3

Champions

  • Pat Hickey
  • Lann Martin
  • John VanEnk

Portability Criteria

WASI-http must have at least two complete independent implementations
demonstrating embeddability in a production HTTP server context.

Introduction

The WASI-http proposal defines a collection of interfaces for sending and
receiving HTTP requests and responses. WASI-http additionally defines two
worlds: wasi:http/service, which circumscribes an execution
environment for a broad category of HTTP services including web applications,
API servers, and proxies; and wasi:http/middleware, for services that
forward requests along a chain of handlers.

Goals

The proposal intends to abstract over HTTP version and transport protocol
choices (such as HTTP/1.1, HTTP/2 or HTTP/3) by mapping directly to the
abstract HTTP Semantics, allowing hosts to (mostly) transparently use any of
these.

The wasi:http/service world is meant to be implementable by a wide variety of
hosts including Web service workers, forward- and reverse-proxies and
origin servers by requiring a minimal set of additional runtime support.

The wasi:http/service world is meant to support flexible auto-scaling
("serverless") execution by moving the core accept() loop into the host and
allowing the host to dynamically spin up wasm instances in response to arriving
requests.

The wasi:http/middleware world is meant to allow the chaining of HTTP
intermediaries to be implemented directly in terms of Component Model linking,
letting a request flow through a series of handlers on its way to a terminal
service while the corresponding response flows back in the opposite direction.

Non-goals

WASI-http does not intend to define a more fully-featured cloud execution
environment (for this, see the wasi-cloud-core proposal).

API walk-through

The proposal can be understood by first reading the comments of worlds.wit,
then types.wit.

Working with the WIT

Bindings can be generated from the wit directory via:

text
wit-bindgen c wit/ --world service

and can be validated and otherwise manipulated via:

text
wasm-tools component wit wit/ ...

The wit/deps directory contains a live snapshot of the contents of several
other WASI proposals upon which this proposal depends. It is automatically
updated by running wit-deps update
in the root directory, which fetches the live contents of the main branch of
each proposal. As things stabilize, wit/deps.toml will be updated to refer to
versioned releases.

References & acknowledgements

  • This proposal was seeded by and developed in consultation with
    proxy-wasm.

Overview (`proposals/random/README.md`)

WASI Random

A proposed WebAssembly System Interface API.

Current Phase

WASI-random is currently in Phase 3.

Champions

  • Dan Gohman

Portability Criteria

WASI random must have host implementations which can pass the testsuite
on at least Windows, macOS, and Linux.

WASI random must have at least two complete independent implementations.

Table of Contents

Introduction

WASI Random is a WASI API for obtaining pseudo-random data.

Goals

The primary goals of WASI Random are:

  • To allow users to use WASI programs to obtain high-quality low-level
    random data suitable for cryptography.
  • To allow source languages to enable DoS protection in their hash-maps
    in host environments that support it.

Non-goals

WASI Random is not aiming to allow programs to handle errors or to query for
availability. It always succeeds (though on platforms where randomness is
unavailable, programs may fail to be instantiated or may trap).

WASI Random is not aiming to be a full DRBG API. Such an API could be
considered in WASI, but it should be a separate proposal.

WASI Random does not include facilities for feeding entropy back into
the system. It is expected that most entropy that applications would observe
should also be observable by the host implementation, and so there should
be little need to feed it back in. There may be other uses for such an API,
but they can be addressed in separate proposals.

WASI Random does not have an async API. It is expected to be implemented with
a CSPRNG which is expected to be sufficiently seeded.

WASI Random does not have an explicit facility for domain separation or
personalization messages. If such features are desired, it would make sense to
define them as custom sections, rather than program data, so that they could
easily be excluded from module caching and possibly also from code signing.
This would make sense as a separate proposal.

WASI Random does not provide an "entropy API" or a "true random" API directly.
The currently expected use cases want a CSPRNG API.

WASI Random does not expose an entropy estimation. It is expected to always
have sufficient entropy to seed a CSPRNG.

WASI Random does not provide any facility for replacing random data with
deterministic data. It is intended to be usable in use cases where determinism
would break application assumptions. Implementations may have debugging
facilities which make this API deterministic, however these should only be
used for debugging, and not production use.

API walk-through

Main API: getting cryptographically-secure pseudo-random bytes

Return a list of cryptographically-secure pseudo-random bytes:

rust
let len: u32 = your_own_code_to_decide_how_many_bytes_you_want();

    let bytes: Vec<u8> = get_random_bytes(len);

Main API: getting cryptographically-secure pseudo-random bytes faster

Sometimes the bindings for list can have some overhead, so
another function is available which returns the same data but as a
u64:

rust
let data: u64 = get_random_u64();

Insecure API: Hash-map DoS protection

Return a pair of u64's that can be used to initialize a hash implementation:

rust
let init: (u64, u64) = insecure_random();

    let combined: u128 = init.0 as u128 | (init.1 as u128 << 64);

    your_own_code_to_initialize_hash_map(combined);

Detailed design discussion

What if the system lacks sufficient entropy during early boot?

Randomness APIs which can fail, or which can be "nonblocking" and return
incomplete results, are error prone and tend to lead applications to resort
to fallbacks which don't tend to be well-tested.

CSPRNGs are believed to be good enough that most systems in most situations
can provide effectively unlimited random data. The main case where this
isn't the case is on systems which have just booted and which have not yet
collected sufficient entropy to initialize their CSPRNGs. In these cases,
this API is designed with the belief that it's better for implementations
to respond to the problem, rather than to pass the responsibility on to
applications.

What should happen on host platforms with weak or broken randomness APIs?

It's implementations' responsibility to handle these situations. They may do
so by supplementing the host platform APIs with data collected from other
sources, they may refuse to run programs that use Random APIs, or if needed,
they may trap programs dynamically to prevent programs from continuing to
execute with poor data.

Implementations are encouraged to perform regular reseeding (if the host
platform doesn't already do so).

Should there be a randomness resource, and should the API take a handle?

Programs shouldn't need to be aware of which random generator they have, since
the data is random and indistinguishable.

WASI programs using the Random API will have imports specific to the Random API,
because they are distinct from imports used for general-purpose stream.

Should random data be provided as a `stream`?

Reusing the stream type is tempting, however it's desirable for users of this
API to be provided actually random data, and not the contents of arbitrary
streams which might be substituted, so it doesn't turn out to be useful to unify
this API with stream.

This also ensures that programs using the Random API can be identified by
their imports, as mentioned in the previous question.

Should the API specify a number of bits of security?

Best practices suggest that implementations should provide at least 196 bits of
security. However, many host platforms' CSPRNG APIs do not currently document
their bits of security, and it doesn't seem desirable to require wasm engines to
run their own CSPRNG on a platform which already has one, so for now, the API
does not specify a specific number.

Why is insecure-random a fixed-sized return value?

This limits the amount of data that can be obtained through it. Since it's
insecure, it's not intended to be used as an alternative to getrandom.

Stakeholder Interest & Feedback

TODO before entering Phase 3.

Preview1 has a random function, and it's widely exposed in toolchains.

References & acknowledgements

Many thanks for valuable feedback and advice from:

  • Zach Lym
  • Luke Wagner
  • Linux Weekly News' many articles about Linux random APIs including this one.

Overview (`proposals/sockets/README.md`)

WASI Sockets

A proposed WebAssembly System Interface API.

Current Phase

Phase 3

Champions

  • Dave Bakker (@badeend)

Portability Criteria

  • At least two independent production implementations.
  • Implementations available for at least Windows, Linux & MacOS.
  • A testsuite that passes on the platforms and implementations mentioned above.

Table of Contents

Introduction

This proposal adds TCP & UDP sockets and domain name lookup to WASI. It adds the basic BSD socket interface with the intent to enable server and client networking software running on WebAssembly.

Unlike BSD sockets, WASI sockets require capability handles to create sockets and perform domain name lookups. On top of capability handles, WASI Socket implementations should implement deny-by-default firewalling.

The socket APIs have been split up into standalone protocol-specific WASI modules. Both current and future socket modules can then be tailored to the needs of that specific protocol and progress the standardization process independently.

This proposal introduces 4 new WASI modules:

Goals

  • Start out as an MVP; add the bare minimum amount of APIs required to create a basic functioning TCP/UDP application.
  • Toolchains must be able to provide a POSIX compatible interface on top of the functions introduced in this proposal.

Non-goals

  • SSL/TLS support
  • HTTP(S) support
  • Retrieving network-related information of the executing machine, like: installed network interfaces and the computer hostname.

API walk-through

[Walk through of how someone would use this API.]

Asynchronous APIs

At the moment, WIT has no built-in way of expressing asynchronous operations. To work around this limitation, we split up async functions into two parts: start-* and finish-*.

Desired signature:

text
operation: func(this, the-inputs...) -> future<result<the-outputs..., error-code>>

Temporary workaround:

text
start-operation: func(this, the-inputs...) -> result<_, error-code>
finish-operation: func(this) -> result<the-outputs..., error-code>

The semantics are as follows:

  • When start-* completes successfully:
    • The operation should be considered "in progress".
    • This is the POSIX equivalent of EINPROGRESS.
    • The socket can be polled for completion of the just started operation, using wasi-poll.
    • Its corresponding finish-* function can be called until it returns something other than the would-block error code.
  • When finish-* returns anything other than would-block:
    • The asynchronous operation should be considered "finished" (either successful or failed)
    • Future calls to finish-* return the not-in-progress error code.
  • The documented error codes can be returned from either the start-* function or the finish-* function. Both are equally correct.

Runtimes that don't need asynchrony, can simply validate the arguments provided to the start function and stash them on their internal socket instance and perform the actual syscall in the finish function. Conveniently, sockets only allow one of these start/finish asynchronous operation to be active at a time.

Example of how to recover blocking semantics in guest code:

rs
// Pseudo code:
fn blocking-connect(sock: tcp-socket, addr: ip-socket-address) -> result<tuple<input-stream, output-stream>, error-code> {
    
    let pollable = tcp::subscribe(tcp-socket);

    let start-result = tcp::start-connect(sock, addr);
    if (start-result is error) {
        return error;
    }

    while (true) {
        poll::poll-oneoff([ pollable ]);

        let finish-result = tcp::finish-connect(sock);
        if (finish-result is NOT error(would-block)) {
            return finish-result;
        }
    }
}

Use case: Wasm module per connection

Thanks to the low startup cost of Wasm modules, its feasible for server software with Wasm integration to spawn a Wasm module for each inbound connection. Each module instance is passed only the accepted client socket. This way, all connection handlers are completely isolated from each other. This resembles PHP's "shared nothing" architecture.

[Use case 2]

[Provide example code snippets and diagrams explaining how the API would be used to solve the given problem]

Detailed design discussion

[This section should mostly refer to the .wit.md file that specifies the API. This section is for any discussion of the choices made in the API which don't make sense to document in the spec file itself.]

Dualstack sockets

IPv6 sockets returned by this proposal are never dualstack because that can't easily be implemented in a cross platform manner. If an application wants to serve both IPv4 and IPv6 traffic, it should create two sockets; one for IPv4 traffic and one for IPv6 traffic.

This behaviour is deemed acceptable because all existing applications that are truly cross-platform must already handle this scenario. Dualstack support can be part of a future proposal adding it as an opt-in feature.

Related issue: Emulate dualstack sockets in userspace

Modularity

This proposal is not POSIX compatible by itself. The BSD sockets interface is highly generic. The same functions have different semantics depending on which kind of socket they're called on. The man-pages are riddled with conditional documentation. If this had been translated 1:1 into a WASI API using Interface Types, this would have resulted in a proliferation of optional parameters and result types.

Instead, the sockets API has been split up into protocol-specific modules. All BSD socket functions have been pushed into these protocol-specific modules and tailored to their specific needs. Functions, parameters and flags that did not apply within a specific context have been dropped.

A downside of this approach is that functions that do not differ per protocol (bind, local_address, connect, shutdown, ...) are duplicated as well.

POSIX compatibility

See Posix-compatibility.md.

Why not getaddrinfo?

The proposed wasi-ip-name-lookup module focuses strictly on translating internet domain names to ip addresses and nothing else.

Like BSD sockets, getaddrinfo is very generic and multipurpose by design. The proposed WASI API is not. This eliminates many of the other "hats" getaddrinfo has (and potential security holes), like:

  • Mapping service names to port numbers ("https" -> 443)
  • Mapping service names/ports to socket types ("https" -> SOCK_STREAM)
  • Network interface name translation (%eth0 -> 1)
  • IP address deserialization ("127.0.0.1" -> Ipv4Address(127, 0, 0, 1))
  • IP address string canonicalization ("0:0:0:0:0:0:0:1" -> "::1")
  • Constants lookup for INADDR_ANY, INADDR_LOOPBACK, IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT.

Many of these functionalities can be shimmed in the libc implementation. Though some require future WASI additions. An example is network interface name translation. That requires a future if_nametoindex-like syscall.

Security

Wasm modules can not open sockets by themselves without a network capability handle. Even with capability handles, WASI implementations should deny all network access by default. Access should be granted at the most granular level possible. See Granting Access for examples. Whenever access is denied, the implementation should return EACCES.

This means Wasm modules will get a lot more EACCES errors compared to when running unsandboxed. This might break existing applications that, for example, don't expect creating a TCP client to require special permissions.

At the moment there is no way for a Wasm modules to query which network access permissions it has. The only thing it can do, is to just call the WASI functions it needs and see if they fail.

Deferred permission requests

This proposal does not specify how wasm runtimes should handle network permissions. One method could be to let end users declare on the command line which endpoints a wasm component may connect to. Another method could be to somehow let component authors distribute a manifest alongside the component itself, containing the set of permissions that it requires.

Both of these examples depend on the network permissions being known and granted upfront. This is not always feasible and that's usually where dynamic permission requests come into play.

The most likely contenders for permission prompt interception are:

  • TCP: connect
  • TCP: bind
  • TCP: listen
  • UDP: bind
  • UDP: connect

Now, again, this proposal does not specify if/how permission prompts should be implemented. However, it does at least facilitate the ability for runtimes to do so. Since waiting for user input takes an unknowable amount of time, the operations listed above have been made asynchronous. POSIX-compatibility layers can simply synchronously block on the returned futures.

TCP State Machine

See Operational Semantics.

Considered alternatives

[This section is not required if you already covered considered alternatives in the design discussion above.]

[Alternative 1]

[Describe an alternative which was considered, and why you decided against it.]

[Alternative 2]

[etc.]

Stakeholder Interest & Feedback

TODO before entering Phase 3.

[This should include a list of implementers who have expressed interest in implementing the proposal]

References & acknowledgements

Many thanks for valuable feedback and advice from:

  • [Person 1]
  • [Person 2]
  • [etc.]

Overview (`proposals/cli/test/README.md`)

Testing guidelines

TK fill in testing guidelines

Installing the tools

TK fill in instructions

Running the tests

TK fill in instructions


Overview (`proposals/clocks/test/README.md`)

Testing guidelines

TK fill in testing guidelines

Installing the tools

TK fill in instructions

Running the tests

TK fill in instructions


Overview (`proposals/filesystem/test/README.md`)

Testing guidelines

TK fill in testing guidelines

Installing the tools

TK fill in instructions

Running the tests

TK fill in instructions


Overview (`proposals/random/test/README.md`)

Testing guidelines

TK fill in testing guidelines

Installing the tools

TK fill in instructions

Running the tests

TK fill in instructions


Overview (`proposals/sockets/test/README.md`)

Testing guidelines

TK fill in testing guidelines

Installing the tools

TK fill in instructions

Running the tests

TK fill in instructions


Capabilities (`docs/Capabilities.md`)

Capabilities in WASI

What is a capability?

The Wasm language has no syscall instructions or built-in I/O facilities.
To let programs interact with the outside world, Wasm programs can be provided
with capabilities.

There are two main kinds of capabilities in WASI, link-time capabilities
and runtime capabilities.

In short, link-time capabilities are functions that you can import that
do things.

They're called link-time capabilities because the exports that satisfy the
imports are chosen at link time. And if someone wants to virtualize those
capabilities, or attenuate them to provide a restricted functionality, they
may use a component that provides the needed exports and link them in
instead, also at link time.

Strictly speaking, link-time capabilities in the Wasm component model are
instance imports. These imports request an already-instantiated instance.
Being already instantiated, the instance already has some capabilities of
its own that were granted to it at its own link time.

Link-time capabilities may also be called instantiation-time capabilities,
because the linking we're talking about here is the linking that happens
as part of instantiation.

When these imports are satisfied by the host, the host doesn't need to
literally create a new Wasm instance, but from the perspective of the guest
it behaves the same way.

Runtime capabilities

In short, runtime capabilities are [handles] that you can pass around that
grant access to resources.

Handles are first-class, so they can flow anywhere at runtime, and they're
unforgeable, so they can be used to pass around access to individual
resources without exposing other resources.

In programming languages that can't directly manipulate unforgeable references,
handles may be exposed to applications in the form of i32 indices into
per-component-instance tables, that conceptually hold the real handles, and
the bindings take care of the bookkeeping when handles are passed from one
instance to another.

If you have use cases that need multiple distinct resources live at the
same time, and the ability to dynamically distinguish between them, you'll
need runtime capabilities. For example, it's common for programs using
filesystem to have multiple files open at once, so files need to be
exposed as handles.

If you have an API where most use cases will only ever have one resource
that gets used, such as a clock API with a "get the time" function where
most users will just have one instance of the clock, link-time capabilities
can be more convenient to use.

There may eventually be situations where an API has been designed to use
link-time capabilities, and someone needs to use it with runtime capabilities.
In our clock API example, if someone does wish to have multiple distinct
clocks at runtime, they'll want handles. In the future, the component model
will hopefully help out here, by adding features to allow component instances
to be usable as handles, which would allow link-time capabilities to be
used as runtime capabilities.


Charter (`docs/Charter.md`)

WebAssembly System Interface Subgroup Charter

The System Interface Subgroup is a sub-organization of the
WebAssembly Community Group of the W3C.
As such, it is intended that its charter align with that of the CG. In particular,
the sections of the CG charter relating to
Community and Business Group Process,
Contribution Mechanics,
Transparency, and
Decision Process also apply to the Subgroup.

Goals

The mission of this subgroup is to provide a forum for pre-standardization
collaboration on a system interface API for WebAssembly programs.

Scope

The Subgroup will consider topics related to system interface APIs, including:

  • APIs for host filesystems, network stacks, and other resources.
  • APIs for graphics, audio, input devices
  • APIs for encryption, format conversion, and other transformations
    (particularly where hardware acceleration may be available on some platforms)

Deliverables

Specifications

The Subgroup may produce several kinds of specification-related work output:

  • Creation of new specifications in standards bodies or working
    groups (e.g. Wasm WG or TC39)
  • Creation of new specifications outside of standards bodies
    (e.g. similar to the LLVM object file format documentation in Wasm tool conventions)

Non-normative reports

The Subgroup may produce non-normative material such as requirements
documents, recommendations, and use cases.

Software

The Subgroup may produce software related to Wasm system interface APIs (either
as standalone libraries, tooling, or integration of interface-related
functionality in existing CG software such as Binaryen or WABT). Capabilities may
include:

  • Libraries implementing external standard APIs in terms of WebAssembly
    System Interface APIs
  • Tools for producing code that uses WebAssembly System Interface APIs
  • Tools for implementing WebAssembly APIs
  • Tools for debugging programs using WebAssembly System Interface APIs

Amendments to this Charter and Chair Selection

This charter may be amended, and Subgroup Chairs may be selected by vote of the full
WebAssembly Community Group.


ComponentModelFeatures (`docs/ComponentModelFeatures.md`)

Component Model features in WASI

WASI APIs are defined in terms of the Component Model, which develops new WIT
syntax, types, and canonical ABI functionality behind gated features. Stable
(@since-gated) WASI APIs may only depend on a gated feature after the WASI
Subgroup has voted to adopt it, following the process described in
CONTRIBUTING.md.

This document records which features have been adopted, and the release they
were adopted for. Adoption is cumulative: implementing a given WASI version
requires the default (ungated) Component Model features, plus every feature
adopted in that version and in all earlier ones.

Adopting a feature does not mean that any WASI API uses it. It means that WASI
APIs in that release and later may use it, and that runtimes and toolchains
which implement that WASI version must implement the feature regardless of
whether it is used yet.

Adopted features

This table is the source for the "Component Model features" section of each
released specification overview.

WASI version Gate Feature Adopted
0.2.0 โ€” The default (ungated) Component Model features WASI 0.2 vote (predates this process)
0.3.0 ๐Ÿ”€ async lift/lower, future and stream WASI 0.3 vote (predates this process)
0.3.1 ๐Ÿ—บ๏ธ The map<K, V> type 2026-08-06 (#943)
0.3.1 ๐Ÿท๏ธ implements and external-id annotations on plain-named interface imports and exports 2026-08-06 (#942)

Features which have not been adopted are listed under gated features in the
Component Model Explainer. WASI proposals may experiment with them in
prerelease versions (such as 0.3.0-rc-* releases), but stable releases must
remain implementable without them.

CI enforces this: each changed proposal is encoded to a component and validated
with the features in the table above enabled, so a proposal that depends on an
un-adopted feature fails validation.


DesignPrinciples (`docs/DesignPrinciples.md`)

WASI Design Principles

Capability-based security

WASI is designed with capability-based security principles, using the
facilities provided by the Wasm component model. All access to external
resources is provided by capabilities.

There are two kinds of capabilities:

  • Handles, defined in the component-model type system, dynamically
    identify and provide access to resources. They are unforgeable, meaning
    there's no way for an instance to acquire access to a handle other than
    to have another instance explicitly pass one to it.

  • Link-time capabilities, which are functions which require no handle
    arguments, are used sparingly, in situations where it's not necessary
    to identify more than one instance of a resource at runtime. Link-time
    capabilities are interposable, so they are still refusable in a
    capability-based security sense.

WASI has no ambient authorities, meaning that there are no global
namespaces at runtime, and no global functions at link time.

Note that this is a different sense of "capability" than Linux
capabilities

or the withdrawn POSIX
capabilities
, which
are per-process rather than per-resource.

Interposition

Interposition in the context of WASI interfaces is the ability for a
Webassembly instance to implement a given WASI interface, and for a
consumer WebAssembly instance to be able to use this implementation
transparently. This can be used to adapt or attenuate the functionality
of a WASI API without changing the code using it.

Component model interfaces always support link-time interposition. While
WASI APIs are often implemented in hosts, they can also be implemented
in Wasm, which may itself be a wrapper around the host. This may be used
to implement attenuation, providing filtered access to the underlying
host-provided functionality.

Interposition is sometimes referred to as "virtualization", however we
use "interposition" here because the word "virtualization" has several
related meanings.

Compatibility

Compatibility with existing applications and libraries, as well as
existing host platforms, is important, but will sometimes be in conflict
with overall API cleanliness, safety, performance, or portability.
Where practical, WASI seeks to keep the WASI API itself free of
compatibility concerns, and provides compatibility through libraries,
such as WASI libc, and tools. This way, applications which don't require
compatibility for compatibility's sake aren't burdened by it.

Portability

Portability is important to WASI, however the meaning of portability
will be specific to each API.

WASI's modular nature means that engines don't need to implement every
API in WASI, so we don't need to exclude APIs just because some host
environments can't implement them. We prefer APIs which can run across
a wide variety of engines when feasible, but we'll ultimately decide
whether something is "portable enough" on an API-by-API basis.

Modularity

WASI will include many interfaces that are not appropriate for every host
environment, so WASI uses the component model's worlds mechanism to allow
specific sets of APIs to be described which meet the needs of different
environments.


HighLevelGoals (`docs/HighLevelGoals.md`)

WASI High Level Goals

(In the spirit of WebAssembly's High-Level Goals.)

  1. Define a set of portable, modular, runtime-independent, and
    WebAssembly-native APIs which can be used by WebAssembly code to interact
    with the outside world. These APIs preserve the essential sandboxed nature of
    WebAssembly through a Capability-based API design.
  2. Specify and implement incrementally. Start with a Minimum Viable Product
    (MVP), then adding additional features, prioritized by feedback and
    experience.
  3. Supplement API designs with documentation and tests, and, when feasible,
    reference implementations which can be shared between wasm engines.
  4. Make a great platform:
    • Work with WebAssembly tool and library authors to help them provide
      WASI support for their users.
    • When being WebAssembly-native means the platform isn't directly
      compatible with existing applications written for other platforms,
      design to enable compatibility to be provided by tools and libraries.
    • Allow the overall API to evolve over time; to make changes to API
      modules that have been standardized, build implementations of them
      using libraries on top of new API modules to provide compatibility.

Proposals (`docs/Proposals.md`)

WASI proposals

WASI APIs are developed as proposals. These proposals go through 5 phases of development (following the WASI Subgroup's Phase Process).

You can learn more about contributing new proposals (and other ways to contribute) in our Contributing guide.

Active Proposals

Phase 5 - The Feature is Standardized (WG)

Proposal Champion Versions

Phase 4 - Standardize the Feature (WG)

Proposal Champion Versions

Phase 3 - Implementation Phase (CG + WG)

Proposal Champion Versions
Clocks Dan Gohman, Colin Murphy
Random Dan Gohman, Roman Volosatovs
Filesystem Dan Gohman, Victor Adossi
Sockets Dave Bakker
CLI Dan Gohman, Lann Martin
HTTP Pat Hickey, Lann Martin, John VanEnk

Phase 2 - Proposed Spec Text Available (CG + WG)

Proposal Champion Versions
Clocks: Timezone Dan Gohman, Colin Murphy
HTTP: Informational Outbound Response Pat Hickey, Lann Martin, John VanEnk
I2C Friedrich Vandenberghe, Merlijn Sebrechts, Maximilian Seidler
Key-value Store Jiaxiao Zhou, Dan Chiarlone
Machine Learning (wasi-nn) Andrew Brown and Mingqiu Sun
Runtime Config Jiaxiao Zhou, Dan Chiarlone
WebGPU Mendy Berger, Sean Isom
Messaging Jiaxiao Zhou, Dan Chiarlone, Taylor Thomas.

Phase 1 - Feature Proposal (CG)

Proposal Champion Versions
Blob Store Jiaxiao Zhou, Dan Chiarlone.
Crypto Frank Denis and Daiki Ueno
GPIO Merlijn Sebrechts, Maximilian Seidler
Distributed Lock Service Jiaxiao Zhou, Dan Chiarlone.
Logging Dan Gohman
Observe Caleb Schoepp
Parallel Andrew Brown
Pattern Match Jianjun Zhu
SPI Merlijn Sebrechts
SQL Jiaxiao Zhou, Dan Chiarlone.
SQL Embed Robin Brown
Threads Alexandru Ene, Marcin Kolny, Andrew Brown
TLS Joel Dice, Dave Bakker, James Sturtevant
URL Radu Matei
USB Wouter Hennen, Warre Dujardin, Merlijn Sebrechts
OTel Caleb Schoepp, Andrew Steurer

Phase 0 - Pre-Proposal (CG)

Note: The pre-proposal phase is simply meant as a way to share ideas. This means that there may be overlap between pre-proposals. It also means that the WASI subgroup has not yet decided that the pre-proposal is in scope for WASI.

Proposal Champion Versions

Inclusion in WASI 0.3

WASI 0.3 (also known as Preview 3, or WASIp3) corresponds to versions numbered
0.3.x in Wit packages and related identifiers.

To be included in WASI 0.3, a proposal must:

Versioning

Once a proposal reaches Phase 3, we expect the champions to start creating releases, following the conventions of semantic versioning (semver). Releases for active proposals are linked in the chart above.

Proposals remain in the 0.x semver range until they reach Phase 5 and are fully standardized. At that point, a 1.0 release should be made available.

For some APIs, it makes sense to add new features after the API itself has reached Phase 5. These feature additions should go through the same standardization process. Once they have reached Phase 5, the minor version number of the release should be incremented.

Some APIs may require backwards-incompatible changes over time. In these cases, we allow proposals to increment the major version number only if the old API can be implemented in terms of the new API. As part of the new version, champions are expected to provide a tool that enables this backwards-compatibility. If that is not possible, then a new API proposal with a new name should be started. The original API can then be deprecated over time if it makes sense to do so.


Release (`docs/Release.md`)

Release

New patch versions of WASI (0.3.x) are released every two months, on the second
Tuesday of the month. This schedule is sometimes also referred to as "the WASI
release train", since releases are determined by a fixed schedule rather than
reaching some feature threshold.

The one exception to the WASI 0.3 release train has been WASI 0.3.0, which was
part of a one-off vote. For WASI 0.2.1-0.2.12 we also followed a two-monthly
release cadence, but with releases happening on the first Tuesday of every two
month rather than the second Tuesday.

Once we are ready to ship WASI 1.0 we may schedule a one-off release outside the release train
again. The release cadence for WASI proposals post 1.0 is still undetermined and
may be subject to change.

Scheduled WASI 0.3 releases 2026-2027

  • WASI 0.3.0: 2026-06-11 (one-off release)
  • WASI 0.3.1: 2026-08-11
  • WASI 0.3.2: 2026-10-13
  • WASI 0.3.3: 2026-12-08
  • WASI 0.3.4: 2027-02-09
  • WASI 0.3.5: 2027-04-13
  • WASI 0.3.6: 2027-06-08
  • WASI 0.3.7: 2027-08-10
  • WASI 0.3.8: 2027-10-12
  • WASI 0.3.9: 2027-12-14

Creating a new release

The release process is entirely automated via GitHub Actions. To create a new
release, a WASI Co-chair will run the Release
WASI

workflow which begin the release process. This process has the following steps:

  1. Trigger the Release WASI workflow by running gh workflow run release.yml -f prev_version=0.3. -f next_version=0.3.<next>.
  2. A PR updating all version numbers is created. This is blocked on CI and review (example).
  3. Create a GitHub release by running gh release create "v0.3.<version>" --generate-notes.
    If the release adopts new Component Model features, the generated notes must
    be edited to call them out. See Component Model features in
    WASI
    .
  4. Once the release has been created, a second PR will be automatically created to populate the specifications/ dir (example).
  5. Once this final PR is merged the release process is complete.

WitInWasi (`docs/WitInWasi.md`)

Wit in WASI

Starting in Preview2, WASI APIs are defined using the Wit IDL.

To set up a git repository, start by cloning the wasi-proposal-template,
renaming the wit file, and adding content and new files as needed.

Conventions

Getters

TODO: Should we have a recommendation for whether to say get- or not? Or
maybe even build a concept of getters into wit itself?

Temporary workarounds

The component model specification and implementations are still in development,
so at this time some features or planned features in the component model are
not ready for use in WASI APIs. Here's a list of those features and what to use
for now in their place.

Value Imports

As a temporary workaround for the lack of value imports, link-time authority
functions may be used.

In place of a value import like this:

wit
/// An example value import.
    /// 
    /// A description of the value import.
    values: list<i32>

Define an instance function, like this:

text
/// An example value import.
    /// 
    /// A description of the value import.
    /// 
    /// This [represents a value import](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Value_Imports).
    instance-values: func() -> list<u32>

If the value type contains any handles, for now specify that calling the
function more than once creates new handles each time.

It is often desirable to put these functions in their own interface, so that
worlds may chose to include or exclude them independently of the rest of the
APIs they're associated with.

Star Imports

TODO: Are there specific patterns we should recommend for working around star imports?

And add this comment:

wit
/// This [represents a star import](https://github.com/WebAssembly/WASI/blob/main/WasiWitdocs/WitInWasi.md#Star_Imports).

To avoid trouble when migrating to star imports in the future, also avoid
depending on dynamic keys.

Dependencies

To use types from one package in another, use a use declaration:

wit
use clocks.monotonic-clock.{instant, duration}

For now, the tooling requires the wit files defining types to be colocated with
the wit files using them. The convention for now is to have a "deps" directory
underneath the top-level "wit" directory containing copies of any needed wit
files.

In the future, wit is expected to support an identifier syntax for naming
types in other packages.


--- METRICS ---