Skip to main content
A workflow is a WASM module with a signed manifest of what it needs. It runs with no filesystem, no environment, no sockets, and no host function it did not declare — which is what makes it safe to install one you did not write. Reach for it when a recipe is not enough: real control flow, state across runs, or tools of your own.

The shape of one

The manifest

tools: is also what install grants, so you do not repeat those names under capabilities:. It is the list the operator reads.

Host functions

log, config, trigger, recall, remember, notify, http, ask, gateway, harness, summarize, propose, remind, run_loop, operator_chats, short_set, short_get, short_all, short_forget, chat_summary_get, chat_summary_save, and tool. tool is the one that matters. Every integration reaches a workflow through it:
There is no WhatsApp host function, no GitHub host function, and no Notion host function. Adding an integration costs no ABI.

Providing tools to the agent

A workflow can hand your agent tools of its own:
Register in init, not in run: the host serves a provided tool on a fresh instance where run has never executed. That is deliberate — the turn calling your tool is often one your own ask started, and re-entering a live instance means calling into a module suspended inside a host call. A fresh instance costs 3.4ms and makes that case identical to the case where nothing is running. Provided tools exist only while the agent is working on your workflow’s behalf: during your ask, and during a later turn your work caused. They are not added to the agent permanently.

Testing without a toolchain

pkg/loopwasm compiles on a normal machine, where every host call returns ErrNotInWASM. Keep your decisions in a file without the wasip1 build tag and test them directly — that is how wa-monitor tests what it decides without WhatsApp being involved.

Publishing

Open a PR against karmax-loops with the source and loop.yaml. Artifacts attach to a Release rather than being committed — a .kloop is ~3MB, and a registry carrying every version forever becomes a clone nobody wants. index.json points at the release and pins it by digest.

While you are still writing it

Untrusted means nobody vouched for who wrote it. It does not mean it may do anything: the digest still binds the module to its manifest, the manifest still gates every call, and the Broker still enforces every grant. KARMAX will ask you to type the loop’s name to confirm — y is not accepted.