I've used it to translate SQLite (with a few extensions) and, that I know of, it's been used (to varying degrees of success) to translate the MARISA trie library (C++), libghostty (Zig), zlib, Perl, and QuickJS.
More on-topic, I use a mix of an unevaluated expression stack and a stack-to-locals approach to translate Wasm.
Interesting. I started working on this same idea a couple of years ago as a way to bypass CGo. Eventually I moved on to something else. Glad someone else is working on this. How does the generated Go performance compare to the original WASM performance?
That's going to depend on what you mean for "original Wasm performance".
What were you using to run Wasm instead of this?
I can compare with wazero, which I was previously using, and say performance stayed mostly in the same ballpark. Things that crossed the Go-to-Wasm boundary very often became much faster, things that stayed mostly in Wasm became slightly slower, as the wazero compiler is pretty good.
wasm2go also does not support SIMD, so if your Wasm module uses/benefits from SIMD, you'll notice.
Go generates large Wasm modules, because it bundles its goroutine scheduler, garbage collector and standard library into the module.
Translating that back to Go will give you a pretty big Go file.
Go is "known" for being fast to compile, but that huge Go file will take (at least?) as long to compile as compiling the Go toolchain does.
wasm2go is best used on moderately sized modules (like SQLite). Last I heard, the person who tried to translate Perl got a 80MB Go file that was taking them 20min to compile.
I use Swival’s /learn command at the end of a session to make it write down what it got wrong, how it fixed the issue, and what it should remember next time. Works pretty well.
It can update those notes automatically, but I’ve found that even with regular nudges, models are still somewhat reluctant to do it.
So manually running /learn every now and then, especially when I can tell it didn’t take the most direct path, helps.
This is essentially ADRs — capturing what the agent learned and why. The manual trigger is the interesting constraint though; the hard part is teaching the agent to recognise the moment a decision worth recording has been made, without being asked. That's what the triggers/suppression definitions are trying to formalise — the when of capture, not just the what.
GPT-5.4 is already an incredible model for code reviews and security audits with the swival.dev /audit command.
The fact that GPT-5.5 is apparently even better at long-running tasks is very exciting. I don’t have access to it yet, but I’m really looking forward to trying it.
I really like local models for code reviews / security audits.
Even if they don't run super fast, I can let them work overnight and get comprehensive reports in the morning.
I used Qwen3.6-27B on an M5 (oq8, using omlx) and Swival (https://swival.dev) /audit command on small code bases I use for benchmarking models for security audits.
It found 8 out of 10, which is excellent for a local model, produced valid patches, and didn't report any false positives. which is even better.
It’s a complete mess, and the hardest part of this kind of tool is maintenance.
It’s not just about incompatible APIs, but also about how messages are structured. Even getting reliable tool calling requires a significant amount of work and testing for each individual model.
Just look at LiteLLM’s commit history and open issues/PRs. They’re still struggling with reliable multi-turn tool calling for Gemini, Kimi requires hardcoded rules (so K2.6 is currently unsupported because it’s not on the list), and so on.
Implementing the basic, generic OpenAI/Anthropic protocols is trivial, and at that point it almost feels like building an AI gateway is done. But it isn’t — that’s just the beginning of a long journey of constantly dealing with bugs, changes, and the quirks of each provider and model.
reply