Design: WASM — a browser authoring surface, and capability-based plugin isolation
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Two separable questions, one honest answer each.
Flowstate in the browser
The authoring half would work today. flow validate, flow fix, the LSP, and Flowfile→spec compilation are pure Go over cel-go and goccy/yaml, all of which compile to js/wasm. A playground page that validates, compiles, and shows diagnostics client-side — no server, no install — is a real adoption surface, and the Validate/Compile RPCs landed in #89 mean the same checks are also reachable server-side for anyone who would rather not ship the wasm. The costs are binary size (cel-go + protobuf runtime is tens of MB before compression; measure before promising) and a syscall/js shim for the LSP's stdio transport.
The execution half should not. A Temporal worker needs real sockets. And flow run local in a browser would be a rehearsal that lies: netpolicy's guarantees live at the dialer (the resolved-IP check, redirect re-validation, the metadata-endpoint denials), and a browser's fetch never exposes the resolved address — so the egress policy literally cannot be enforced there. Invariant 3 says a local run exists to tell an author what production will do; a browser run that skipped the policy would tell them something else. If a browser "try it" story is ever wanted, it is expression evaluation and compilation only, stated plainly, never the http task.
WASM as a plugin runtime (beside, not replacing, the process protocol)
Today a plugin is an OS process over a Unix socket, and the isolation is whatever the OS gives that process — which is real for crashes and dependency conflicts, and nothing for filesystem, network, or syscalls (#100). A WASM runtime (wazero is the obvious choice: pure Go, no cgo, fits the toolchain) inverts the default:
- A wasm plugin has no ambient capabilities at all. It cannot open a socket, read a file, or see the environment unless the host hands it a function that does. Network access becomes a host function the worker provides — which means a wasm plugin's egress is governed by the worker's netpolicy by construction, not by trust. That is precisely the compute/network/storage separation #100 asks for, arrived at by runtime choice rather than by sandbox configuration.
- One artifact, every platform. No per-OS builds, no
flowstate-plugin-<name>.exevs ELF, and distribution (#97) gets simpler: a wasm module in an OCI artifact is a solved packaging problem. - The natural first tenants are compute-shaped tasks: transforms, format conversions, policy evaluations, parsers — things that take bytes and return bytes and should never have had network access in the first place. A vault-shaped plugin (long-lived connections, TLS, auth flows) stays on the process protocol; WASI's socket story is not there yet and the host-function bridge for a full HTTP client is a project of its own.
The cost is a second plugin ABI. The socket protocol speaks Connect over a socket; a wasm module exports functions. Two SDKs, two test harnesses, two docs pages — not worth it for breadth alone, worth it if the capability-isolation argument carries #100. The honest sequencing: design the host-function surface as part of #100's policy work (what may a plugin reach, expressed once, enforced for processes by policy and for wasm by construction), and only then decide whether the second ABI pays.
More task/plugin ideas surfaced while thinking about this, for the roster
dns:lookup andwhois-shaped enrichment plugins — security investigations and agentic triage want them constantly, and they are small, bounded, and vendor-free enough to be early wasm candidates- pagerduty / opsgenie — incident-response runbooks (the ARCHITECTURE.md workload list names these) need to page someone
- jira / linear — ticket creation as a workflow effect, the business-process half
- s3 / gcs blob read/write — the artifact story for exec and for data pipelines, pairs with the claim-check codec ARCHITECTURE.md describes
- smtp / email — approval gates that reach people who do not live in Slack
- a
queue.emit-shaped publisher — the one effect http genuinely cannot express (fire-and-forget), already noted in the builtin-admission analysis as the generic primitive every second plugin would otherwise reimplement
None of these change the built-in registry (log, http, exec-when-policied stays the whole of it, per docs/DSL.md's admission test) — they are all <plugin>.<task>: spellings on the ecosystem in #95.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading ARCHITECTURE.md and docs/DSL.md, then review the referenced issues #89, #95, #97, and #100. This issue spans browser authoring, plugin ABI design, and capability policy rather than naming one implementation entry point. Done would require an agreed scope and sequencing for the WASM surface and its relationship to the existing process protocol.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, wasm
- Domain
- backend, security, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100