Goalchemy is a transpiler for a restricted, Go-compatible language. You write a program once as ordinary .go files, and Goalchemy lowers it to Go, TypeScript, Python, Java, C#, Rust, C, and Swift with the same observable behavior on every target.
The source is plain Go: it builds, runs, and tests with the standard Go toolchain, and needs no new syntax or custom parser. Goalchemy accepts the subset of Go described in the language specification and rejects everything else with a clear diagnostic.
Shipping the same logic as an SDK in several languages usually means maintaining several hand-written ports that drift apart. Goalchemy keeps one typed source of truth and generates each port from it. The motivating workload is the OpenTDF SDK, whose encryption and decryption logic needs to behave identically across languages.
Goalchemy is a framework for building one SDK that ships in several languages. You write the SDK's logic once, in a restricted subset of Go, and Goalchemy generates the Go, TypeScript, Python, Java, C#, Rust, C, and Swift packages from it with the same behavior.
It is not a general-purpose transpiler. It won't convert arbitrary Go programs, and it doesn't try to reproduce the whole Go standard library on every target.
The runtime library is deliberately small:
- Goalchemy provides the language runtime, a set of pure-logic
std/packages (strings, conversions, sorting, encodings), and a few host capabilities that most SDKs need (crypto, HTTP, clocks, logging). - Each SDK is designed to provide everything specific to its domain, including its own capabilities: declared with Go signatures and contracts, implemented natively per target, and checked against the same contracts and tests as Goalchemy's own.
If a feature is useful to only one SDK, it belongs in that SDK, not in Goalchemy.
- Load and validate. Packages are loaded and type-checked with
go/packagesandgo/types, then checked against the language gate. Unsupported constructs fail closed with a stable code, source span, and one-line remedy. - Lower to a typed IR. A project-owned intermediate representation makes evaluation order, value copies, aliasing, and runtime operations explicit, so emitters never decide semantics.
- Emit and link. Each target emitter writes source code plus only the runtime files the program needs. Every runtime function has one implementation file per target and a canonical YAML contract that defines its behavior.
- Verify. Differential tests compare native Go, lowered Go, and every other target against the same fixtures and contract cases.
Notable semantics that hold on every target:
intanduintare always 64-bit, with Go's wrapping and conversion rules.float32andfloat64retain their IEEE precision, including signed zero, NaN, infinity, numeric conversions and float values in collections and exported APIs. See float semantics and verification.- Strings are immutable byte sequences; slices and maps keep Go's sharing and aliasing.
- Structs and arrays are copied by value, even on hosts that share objects by default.
- Errors are values; panics,
defer, andrecoverfollow Go's rules. - Concurrency (
go, channels,select,sync,context) runs on a deterministic cooperative scheduler under thecooperativegate.
Goalchemy is built with the Go 1.27.1 reference toolchain:
go install github.com/eugenioenko/goalchemy/cmd/goalchemy@latestOr from a checkout:
go build -o bin/goalchemy ./cmd/goalchemymkdir hello && cd hello
go mod init example.com/hello
go get github.com/eugenioenko/goalchemy@latest
cat > main.go <<'GO'
package main
func main() {
println("Hello from Goalchemy")
}
GO
goalchemy check .
goalchemy run -target python .
goalchemy compile -target rust -out out/rust .The go get makes Goalchemy's packages resolvable from your module. Source modules must declare go 1.25 or earlier. Programs print with Go's print and println builtins.
The Go standard library is replaced by packages that keep the standard names, so code still reads and runs as ordinary Go:
std/: pure-logic packages (strings,strconv,bytes,io,sort,unicode,unicode/utf8,encoding/hex,encoding/binary,encoding/json(Marshal,Unmarshal,Encoder,Decoder),encoding/jsonvalue,encoding/json/jcs(RFC 8785 canonical JSON),encoding/protojson,connect,time,errors,fmt,log/slog,os,net/url, andnetforJoinHostPortandSplitHostPort) written once in the Goalchemy subset and compiled with your program. They behave identically on every target with no native dependencies.lib/: capability packages that reach the host (crypto,http,encoding,checksum,clock,log,os,callback,sync,context,time,errors). Each has a native implementation per target, checked against a contract.
The runtime library reference explains the split and documents every function.
protoc-gen-goalchemy generates subset-Go messages with proto3 JSON encoding and Connect service clients from .proto files.
The IEEE CRC32 host mappings distinguish standard APIs,
the official Microsoft package, and portable fallbacks.
These are the gaps most SDKs and programs hit today, in priority order. Each lands in std/ when it is pure logic and in lib/ when it needs the host.
| Addition | Root | Notes |
|---|---|---|
fmt: Print, Println |
lib/ |
Writes to stdout through a small host capability. |
os.Getenv |
lib/ |
Reports "not set" where the host has no environment, such as browsers. |
os.Args, os.Exit, stdin |
lib/ |
For programs and examples; SDKs rarely need them. |
Domain formats such as ZIP archives for OpenTDF are candidates for the SDK that needs them rather than for Goalchemy, per the scope above.
| Command | Purpose |
|---|---|
goalchemy check [packages] |
Load, type-check, and validate against the language gate. |
goalchemy compile -target <name> -out <dir> [packages] |
Write a complete, runnable target directory. -target ir dumps the IR. |
goalchemy run -target <name> [-keep] [packages] |
Compile to a temporary directory and run the program. |
goalchemy build [-config goalchemy.yaml] |
Compile every target listed in a project configuration. |
goalchemy docs -format json|markdown|site -out <dir> [packages] |
Generate consumer API references and an optional Starlight site. |
goalchemy features |
Print supported language features per gate and target. |
goalchemy spec validate / spec generate [-check] |
Validate the contract catalog and regenerate target specs. |
goalchemy test |
Run runtime contract cases through each target's harness. |
goalchemy version |
Print the compiler version. |
check, compile, and run share these flags:
| Flag | Meaning |
|---|---|
-gate sequential|cooperative |
Language gate; cooperative enables tasks, channels, and select. |
-tags a,b |
Build tags used when loading packages. |
-C <dir> |
Directory to load packages from. |
-json |
Write diagnostics as JSON. |
Generated source keeps Go identifiers by default on all targets: types,
functions, globals and locals retain their source names, and a name is renamed
only on a collision (a reserved word, a shadowed local, or the same name in two
packages). Compiler-created names start with _, such as the task parameter
_t and temporaries like _4.
compile, run, and build accept --names=source|readable|compact (and
names: in goalchemy.yaml). Source names, the default, keep Go identifiers
and rename only on a collision; --name-collisions=fail reports collisions
instead. --compact-names remains a shorthand for --names=compact. Public
library names and runtime behavior stay the same in every mode. See
generated naming conventions for the limits of
these names.
A project can list its targets in goalchemy.yaml and build them all at once:
schema_version: 1
packages: [.]
gate: sequential
targets:
go: {out: out/go}
typescript: {out: out/ts}
python: {out: out/py}
rust: {out: out/rs}Non-main packages compile to value libraries for every target. See the usage guide for library boundaries and output layout.
| Target | Output | To run generated programs |
|---|---|---|
| Go | main.go, go.mod |
Go 1.25 or later |
| TypeScript | main.ts (ES2022) |
Node.js 22.6 or later |
| Python | main.py |
Python 3.10 or later |
| Java | Main.java, run.sh |
JDK 21 or later |
| C# | Main.cs, main.csproj |
.NET SDK 8 |
| Rust | src/main.rs, Cargo.toml |
Stable Rust, edition 2021 |
Rust no_std (experimental) |
src/lib.rs, Cargo.toml |
-target rust-nostd; allocator and platform entry supplied by the application |
| C | main.c, run.sh |
C17 compiler and bdwgc 8.x with threads |
| Swift (experimental) | main.swift, run.sh |
Swift 6.4, C compiler, pkg-config, OpenSSL 3, zlib, libcurl; Linux x86_64 |
Each output directory also contains its runtime files, a README.md, a line map back to the Go source, and a goalchemy.manifest.json recording the compiler version, contracts, and files. Output is deterministic for the same inputs.
Swift libraries emit a SwiftPM product named GoalchemyGenerated with typed
public values and synchronous or asynchronous operations. All Swift outputs
currently include native dependency prerequisites. See Swift setup and library
use; Apple SDK integration has not yet been verified.
The examples/ directory has complete programs with a goalchemy.yaml for all targets:
bank: typed errors, interfaces, and deferred audit loggingcalc: an integer expression parser and evaluatorfetch: downloads a CSV dataset over HTTPS and summarizes itjwt: signs and verifies HS256 JSON Web Tokenslife: Conway's Game of Life on a toroidal boardpipeline: workers, channels,select, and per-job deadlines on the cooperative schedulerwordfreq: word counting and ranking
goalchemy run -target python ./examples/calc
cd examples/bank && goalchemy buildThe public documentation is at goalchemy.dev. The Astro Starlight site lives in docs-web/; see its maintenance guide for local development and GitHub Pages deployment.
| Topic | Reference |
|---|---|
| Commands, configuration, output, libraries | Usage guide |
| Consumer API catalog, Markdown, and Starlight template | API documentation |
Runtime library: std/ and lib/ packages |
Library reference |
| Protobuf messages, proto3 JSON and Connect clients | Protobuf |
| Accepted language and semantics | Language specification |
| Diagnostic codes | Diagnostics |
| Supported feature matrix | specs/features.yaml |
| Runtime and type contracts | specs/runtime, specs/types |
| Host lifecycles per target | Host operations |
Embedded Rust with core and alloc |
Rust no_std profile |
| Implementing a new target language | Adding a language |
| Swift setup, representation, libraries and verification | Swift target |
| Testing, toolchains, reports | Hardening |
| Known limits and future work | Follow-ups |
| Design and roadmap | Implementation plan |
Per-target details live in docs/: library boundaries, byte storage, and host operations for TypeScript, Python, Java, C#, Rust, C, and Swift.
Goalchemy is licensed under Apache-2.0.
An experimental TinyGo WASI profile emits WebAssembly commands while preserving 64-bit source integers. Its benchmark report compares direct and lowered Go/TinyGo builds with performance, peak RSS, and Wasm linear memory side by side.
