Skip to main content

Customize your wash CLI with WebAssembly components and wash plugins

· 4 min read

Customize your wash CLI with WebAssembly components and wash plugins

In wash v0.28, we introduced wash plugins: a simple system for extending the wasmCloud Shell (wash) CLI with WebAssembly components. Users can install plugins from OCI registries, local files, or over HTTP, then execute the plugin as a subcommand to wash. Plugin developers simply build a given piece of CLI functionality as a component.

In this post, we'll show you how to install your first plugin. In themselves, plugins represent powerful, versatile tools that will accelerate workflows and help developers tailor tooling to their needs. But wash plugins are also a great example of how modular CLIs can be implemented with WebAssembly—and how components can accelerate development across a team.

Faster development with components

Using components for plugin functionality means that very little of the implementation is particular to wash or wasmCloud. Taylor Thomas, who built the plugin system, describes it as "essentially a thin shim around wasi:cli/run." In fact, you can run plugins in Wasmtime with minimal configuration. The common interface of WASI makes components ideally suited to building modular CLIs, and even reusing plugins across different component-powered CLIs.

Because the plugin design is so firmly rooted in standards, the feature could be spun out of only a few days' work during the wasmCloud maintainers' Spring Hackathon. About a week after the Hackathon, plugins were merged into wash—a few days after that, Brooks Townsend had his wit2wadm project working as a plugin. The wasmCloud project has been all-in on components for a while now, but the team was a bit surprised by just how quickly these projects could go from independent ideas to integrated releases.

Getting started with wash plugins

If you have wash v0.28 or later installed, you've got everything you need. (If not, head on over to the Installation page.) You can run wash -V to check your version.

With wash installed, installing a plugin is just a matter of running wash plugin install against a target, whether that's a local file, an OCI registry, or an HTTP address. For this example, we'll use the wit2wadm plugin which is available as an OCI artifact hosted on GitHub Packages. wit2wadm will let us generate application deployment manifests automatically from a components' defined interfaces, cutting way down on time spent writing YAML and speeding up local development workflows.

shell
wash plugin install oci://ghcr.io/brooksmtownsend/wit2wadm:0.2.0

We can see our installed plugins:

shell
wash plugin list

Now we can generate deployment manifests by targeting a component with the wit2wadm subcommand. For the purposes of our demo, we'll create a new "Hello world" component:

shell
wash new component hello --template-name hello-world-rust

Now we can navigate to the project directory and build our component from the Rust template:

shell
cd hello
wash build

To generate the manifest, we'll simply target the .wasm file generated by our build:

shell
wash wit2wadm ./build/http_hello_world_s.wasm

And here's our manifest:

yaml
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: wit2wadm
  annotations:
    description: A wasmCloud Application
    version: v0.1.0
  labels:
    generated-by: wit2wadm
spec:
  components:
  - name: wit2wadm
    type: component
    properties:
      image: myregistry.io/wit2wadm:v0.1.0
    traits:
    - type: spreadscaler
      properties:
        instances: 1
  - name: wasi:http-source
    type: capability
    properties:
      image: ghcr.io/wasmcloud/http-server:canary
    traits:
    - type: link
      properties:
        target: wit2wadm
        namespace: wasi
        package: http
        interfaces:
        - incoming-handler

The wit2wadm plugin extrapolates and defines things like links from the component, and then fills in unknown values (like the component's name or registry source) with placeholder values. We can use CLI flags to define those values as well:

shell
wash wit2wadm --name demo --version 0.2.0 --description "Say hello" ./build/http_hello_world_s.wasm
yaml
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: demo
  annotations:
    description: Say hello
    version: 0.2.0
  labels:
    generated-by: wit2wadm
spec:
  components:
  - name: demo
    type: component
    properties:
      image: myregistry.io/demo:0.2.0
    traits:
    - type: spreadscaler
      properties:
        instances: 1
  - name: wasi:http-source
    type: capability
    properties:
      image: ghcr.io/wasmcloud/http-server:canary
    traits:
    - type: link
      properties:
        target: demo
        namespace: wasi
        package: http
        interfaces:
        - incoming-handler

You can learn more about the wit2wadm project in the GitHub repo, and more about using wash plugin in the wasmCloud documentation.

Developing wash plugins

If you're interested in developing wash plugins, the wasmCloud documentation includes a wash plugin developer guide. The developer guide breaks down the plugin API (a small wrapper around the wasi:cli/run interface) along with details on implementing the run function, accessing local files, plugin configuration, and more.

Join the community

We're excited to see what the community does with wash plugins, both as users and developers. If you have questions, want to share a plugin, give feedback on the feature, or just talk components and wasmCloud, join us on the wasmCloud community Slack!