Quickstart: Building a Murmur Tool in Python (Native Binary Path)
Murmur is WASM-first, but it also supports a native compatibility path for tools.
Use this path when:
- you want to ship quickly from existing Python code
- a dependency stack is difficult to compile to WASM
- you prefer a process-based tool runtime
Native tools trade off isolation compared to WASM tools. In Murmur docs/specs this is an explicit compatibility mode.
How it works
For native tools, the runtime launches a binary and normalizes its output to Murmur's tool-result envelope.
Typical flow:
tool.py → package as executable → mur build → .mur.zip → mur publish → capsule invokes tool
Prerequisites
- Python 3.10+
murCLI installed- A packaging approach for your platform (example below uses
pyinstaller)
Step 1 — Create the tool project
my-native-tool/
murmur.yaml
src/
tool.py
bin/
run # final executable copied here
Step 2 — Implement tool logic
Create src/tool.py:
Tip: if your runtime version expects additional envelope fields, generate a canonical native stub first with
murmur-scaffoldand copy its output shape.
#!/usr/bin/env python3
import json
import sys
def main() -> int:
raw = sys.stdin.read().strip() or "{}"
payload = json.loads(raw)
data = payload.get("data")
summary = f"received: {data}" if data is not None else "received empty payload"
result = {
"status": "passed",
"summary": summary,
"data": json.dumps({"echo": data}),
"truncated": False,
"metadata": {},
}
print(json.dumps(result))
return 0
if __name__ == "__main__":
raise SystemExit(main())
Step 3 — Build an executable
Example with PyInstaller:
pip install pyinstaller
pyinstaller --onefile src/tool.py --name run
mkdir -p bin
cp dist/run bin/run
chmod +x bin/run
At this point, bin/run is the executable Murmur packages.
Step 4 — Write the tool manifest
Create murmur.yaml:
name: py-echo-native
version: "0.1.0"
runtime: native
requires_files:
- bin/run
requires_files: is what mur build packages alongside the manifest. Without it the executable
built in Step 3 is not put in the artifact — see
requires_files.
Step 5 — Build and publish
From my-native-tool/:
mur build .
mur publish py-echo-native-0.1.0.mur.zip
Step 6 — Declare in a capsule
In capsule murmur.yaml:
name: my-capsule
version: "0.1.0"
artifacts:
- name: py-echo-native
version: "0.1.0"
runtime: native
Step 7 — Run and test
mur run
When the capsule invokes py-echo-native, the runtime executes the packaged binary and forwards the normalized result back to the caller.
The binary does not inherit the host's environment as-is: HOME is replaced with a session-scoped synthetic directory, credential-shaped variables (GITHUB_TOKEN, *_API_KEY, AWS_*, etc.) are stripped, and only a safe baseline (PATH, HOME, USER, LANG, LC_ALL, TMPDIR, TEMP, TMP, CARGO_HOME, RUSTUP_HOME, TERM) passes through — the same sanitization shell tool subprocesses get, applied regardless of whether the capsule declares capabilities.shell.allow.
Common errors
Tool launches but fails with missing shared libraries
Bundle dependencies into the executable (or run in an environment matching your target).
runtime mismatch in capsule manifest
If the artifact is published as native, declare it with runtime: native in the capsule manifest.
Binary works locally but fails on another platform
Build/publish per target platform (for example linux/amd64, linux/arm64, darwin/arm64) and resolve the correct variant at runtime.
Which Python path should you choose?
- Choose Python Tool Quickstart (WASM) for stronger isolation and component-model alignment.
- Choose Python native when ecosystem compatibility or packaging speed is more important for your use case.