Skip to content

Quickstart: Building a Murmur Tool in Python

Murmur's ecosystem is currently Rust-centric, but Murmur is designed to work well with any language.
If your tool can be packaged as a supported artifact runtime, it can participate in the ecosystem.

This guide walks through building, packaging, and publishing a Murmur tool artifact written in Python.

By the end, you will have a working .mur.zip published to your local registry and a capsule that can invoke it.

Prefer shipping a native binary instead of WASM? See Python Tool Quickstart (Native).


How it works

A Murmur tool can be distributed as a WASM component. For Python, the flow is:

tool.py → componentize-py → tool.wasm → mur build → .mur.zip → mur publish
  • componentize-py compiles Python + WIT interface definitions into a WASM component
  • mur build packages the WASM and manifest into a .mur.zip artifact
  • mur publish registers the artifact so capsules can declare and install it

Prerequisites

  • Python 3.10+
  • componentize-py installed:
pip install componentize-py
  • mur CLI installed

Step 1 — Set up the project folder

my-tool/
  wit/
    tool.wit
  tool.py
  murmur.yaml

Step 2 — Write the WIT interface file

Create my-tool/wit/tool.wit:

package murmur:tool@0.1.0;

interface run {
  enum status {
    passed,
    failed,
    error,
  }

  record tool-input {
    data: option<string>,
    log-path: option<string>,
  }

  record tool-result {
    status: status,
    summary: option<string>,
    data: option<string>,
    data-path: option<string>,
    truncated: bool,
    metadata: list<tuple<string, string>>,
  }

  run: func(input: tool-input) -> tool-result;
}

world tool {
  export run;
}

Notes:

  • Keep only this file in the wit/ directory for this quickstart.
  • Pass the wit/ directory to --wit-path.
  • The @0.1.0 on the package line matches the version the host's murmur:tool WIT currently ships (see WIT Interfaces). The host resolves a tool's murmur:tool/run export by versioned name first and falls back to the unversioned name, so an unversioned package murmur:tool; still works today — but pin the version so mur build output matches what the host actually expects.

Step 3 — Generate Python bindings

cd my-tool
componentize-py --wit-path ./wit --world tool bindings .

This generates wit_world/ bindings (do not hand-edit generated files).


Step 4 — Implement the tool

Create my-tool/tool.py:

from wit_world import exports
from wit_world.exports import run


class Run(exports.Run):
    def run(self, input: run.ToolInput) -> run.ToolResult:
        path = input.data or "input.jsonl"

        try:
            with open(path) as f:
                count = sum(1 for line in f if line.strip())

            return run.ToolResult(
                status=run.Status.PASSED,
                summary=f"{count} lines",
                data=str(count),
                data_path=None,
                truncated=False,
                metadata=[],
            )
        except OSError as e:
            return run.ToolResult(
                status=run.Status.ERROR,
                summary=str(e),
                data=None,
                data_path=None,
                truncated=False,
                metadata=[],
            )

Key points:

  • Class name must be Run
  • Method must be run(self, input) and return ToolResult
  • On failures, return status = error rather than crashing

Step 5 — Compile to WASM

componentize-py --wit-path ./wit --world tool componentize tool -o tool.wasm

Expected output:

Component built successfully

Step 6 — Write the manifest

Create my-tool/murmur.yaml:

name: jsonl-line-count
version: "0.1.0"
requires_files:
  - tool.wasm

requires_files: is what mur build packages alongside the manifest. Without it the compiled tool.wasm is not put in the artifact — see requires_files.


Step 7 — Build and publish

From my-tool/:

mur build .
mur publish jsonl-line-count-0.1.0.mur.zip

Expected publish output:

Published jsonl-line-count@0.1.0

Step 8 — Declare the tool in a capsule

In capsule murmur.yaml:

name: my-capsule
version: "0.1.0"
artifacts:
  - name: jsonl-line-count
    version: "0.1.0"
    runtime: wasm

Step 9 — Run

With your capsule artifact in place, run:

mur run

At runtime, Murmur resolves jsonl-line-count@0.1.0, installs it, and dispatches it when invoked.


Common errors

World 'tool' not found in package 'murmur:tool'
--wit-path pointed to a file instead of the directory. Use --wit-path ./wit.

package identifier does not match previous package name
Your wit/ folder contains extra WIT files from other packages.

No module named ...
Bindings were not generated (or imports don't match generated paths). Re-run:

componentize-py --wit-path ./wit --world tool bindings .