gloat - Glojure Automation Tool
Gloat compiles Clojure or YAMLScript to Go code or native binaries
Cross-compiles to 20+ platforms including Wasm.
Before using the Try Gloat - Live Demo badge above, read the Gloat Live Demo section below.
# Compile to native binary (default)
gloat app.clj # Creates ./app binary
gloat app.clj -o myapp # Creates ./myapp binary
# Output intermediate formats
gloat app.ys -t clj # Clojure to stdout
gloat app.ys -t glj # Glojure to stdout
gloat app.ys -t go # Go to stdout
# Create files with -t .ext shorthand
gloat app.ys -t .clj # Creates app.clj
gloat app.ys -t .glj # Creates app.glj
gloat app.ys -t .go # Creates app.go
# Create a portable Go project directory
gloat app.ys -o build/ # Creates build/ directory
# Cross-compile
gloat app.ys -o app-linux --platform=linux/amd64
gloat app.ys -o app.exe --platform=windows/amd64
# Compile and run
gloat --run app.ys # Compile and run (no binary kept)
gloat --run app.ys -- <args...> # Pass arguments to program
# Start the Glojure REPL
gloat --repl # Auto-detects ./gljdeps.edn
gloat --repl=mydir # Use mydir/ as build directory
gloat --repl --deps=gljdeps.edn # Explicit deps file
# WebAssembly targets
gloat app.ys -o app.wasm # WASI target
gloat app.ys -o app.wasm -t js # JavaScript targetGloat compiles Clojure or YAMLScript source files to any of these forms:
- Native binaries
- Cross compile to 20+ OS/Arch environments
- Web Assembly
- Wasi P1 - Run on server
- JS Wasm - Run in browser
- Shared libraries (
.so,.dylib,.dll)- With
.hheader files for FFI binding
- With
- Go source files
- Standalone Go build directories
- Standalone Babashka (Clojure) files
.ys → ys -c → .clj
↓
.clj ────────→ rewrite → .glj
↓
.glj ──────────────────→ glj compile → .go
↓
go build → binary/wasmThe tool has zero external dependencies.
All required tools (bb, glj, go, ys) are installed the first time you run
gloat via the Makes build system.
All of these tools will be installed local to the gloat repository under
/path/to/gloat/.cache/.local/ and you will be prompted about it first.
The gloat repository comes with a lot of demo programs.
You can find them in the demo/clojure/, demo/yamlscript/, and
demo/interop/ directories.
A great way to view the demos is to start the Gloat Demo Webpage Server with:
$ make serve-demo
...some output...
Starting server on http://localhost:8080
Press Ctrl+C to stop
That serves a webpage that will let you try all of the examples interactively.
In the webpage you can choose an example and then click Compile, which sends it back to the local server, turns it into a Wasm file that can run in the browser. It will also show you the Glojure and the Go code that was generated to create the Wasm. After a program compiles, you can run it with the Run button.
At the top of this file, you may have noticed this badge:
GitHub users can click that and see the demo without cloning this repository. It opens in a GitHub Codespaces session, which starts as an empty VScode editor session. If you wait a couple minutes (literally) the demo will start in an editor pane.
Notes: The demo page literally takes 1-2 minutes to start. Use Cmd/Ctrl + Shift + P -> View Creation Log to see full logs. After the demo starts in the editor, you can pop it out to a separate browser pane.
Try these:
gloat --run demo/yamlscript/dragon-curve.ys
gloat -r demo/clojure/even-or-odd.clj -- 7 42 31337
To pass options to a program run with gloat --run, put the after a -- arg.
Gloat can compile YAMLScript to shared libraries (.so/.dylib/.dll)
with auto-generated C header files, enabling FFI (Foreign Function Interface)
bindings from 23 programming languages.
The demo/so-bindings/ directory
contains working examples for every supported language, all calling the same
shared library compiled from a single YAMLScript source file
(demo/so-bindings/example.ys).
The library exports 6 functions: factorial, greet, repeat_string,
shout_it, maybe, and sort_json_array.
Supported languages: Ada, C, C++, C#, Crystal, D, Dart, Delphi, Fortran, Go, Haskell, Java, Julia, Lua, Nim, Node.js, Perl, Python, Raku, Ruby, Rust, V, Zig
# Build the shared library and run all 23 language bindings
make test-so-bindings
# Run a single language binding
make -C demo/so-bindings/python runGloat supports hybrid builds where a handwritten Go shim implements a Go
interface and delegates all logic to compiled Clojure code via
glj.Var("ns", "fn").Invoke(...).
The demo/interop/bubbletea/ directory
shows this pattern using Bubbletea,
a Go TUI framework.
Bubbletea requires implementing the tea.Model interface, which Glojure cannot
do directly (no deftype/reify).
The solution: a small shim.go implements tea.Model and calls Clojure
functions for init-model, update-model, and view-model.
cd demo/interop/bubbletea
make build
./pickerInstall gloat to ~/.local with a single command:
make -f <(curl -sL gloathub.org/make) installThis clones the gloat repository to ~/.local/share/gloat, creates a symlink
at ~/.local/bin/gloat, and installs all dependencies automatically.
Make sure ~/.local/bin is in your PATH, then run gloat --help.
Run make -f <(curl -sL gloathub.org/make) help to see all available targets.
# Install to a custom prefix
make -f <(curl -sL gloathub.org/make) install PREFIX=~/mytools
# Install a specific version
make -f <(curl -sL gloathub.org/make) install VERSION=v0.1.2
# Also install the glj compiler
make -f <(curl -sL gloathub.org/make) install-glj
# Uninstall
make -f <(curl -sL gloathub.org/make) uninstallClone this repository and source the appropriate rc file for your shell:
$ git clone https://github.com/gloathub/gloat
# For Bash, Fish or Zsh
$ source gloat/.rc
$ gloat --help
==> Installing gloat dependencies (bb, glj, go, ys) locally into:
/home/ingy/src/gloat/worktree/clojure-rewrite/.cache/.local/
Press Enter to continue (or Ctrl-C to cancel)...
...installs stuff within the gloat repo dir...
$ man gloatThe first time you run the gloat command, all its dependencies will be
installed under the /path/to/gloat/.cache/.local/ directory.
Sourcing the rc file adds gloat to your PATH and automatically loads shell
completions for your shell.
To make gloat a permanent install, add this to your shell's rc file:
# For Bash: add to ~/.bashrc
# For Zsh: add to ~/.zshrc
source /absolute/path/to/gloat/.rc
# For Fish: add to ~/.config/fish/config.fish
source /absolute/path/to/gloat/.fishrc| Format | Flag | Description |
|---|---|---|
bin |
-t bin or no extension |
Native executable (default) |
clj |
-t clj |
Clojure source |
bb |
-t bb |
Babashka self-contained script |
glj |
-t glj |
Glojure source |
go |
-t go |
Go source |
dir |
-o path/ |
Portable Go project directory |
lib |
.so or .dylib extension |
Shared library |
wasm |
.wasm extension |
WebAssembly (WASI) |
js |
-t js with .wasm |
WebAssembly (JavaScript) |
The output format is inferred from the -o extension, or can be explicitly
set with -t.
When outputting to a directory (-o build/), gloat generates a self-contained
Go project that builds with zero pre-installed dependencies:
build/
├── Makefile # Makes-based build (auto-installs Go)
├── go.mod # Go module definition
├── main.go # Entry point
└── pkg/app/core/ # Glojure runtime code
Anyone can build it with just make - Go is automatically installed.
Use --platform=OS/ARCH to cross-compile for different platforms:
# Linux targets
gloat app.ys -o app-linux-amd64 --platform=linux/amd64
gloat app.ys -o app-linux-arm64 --platform=linux/arm64
# macOS targets
gloat app.ys -o app-darwin-amd64 --platform=darwin/amd64
gloat app.ys -o app-darwin-arm64 --platform=darwin/arm64
# Windows targets
gloat app.ys -o app.exe --platform=windows/amd64
gloat app.ys -o app-win-arm64.exe --platform=windows/arm64
# WebAssembly targets
gloat app.ys -o app.wasm --platform=wasip1/wasm # WASI
gloat app.ys -o app.wasm --platform=js/wasm # JavaScriptCommon platform targets:
| OS | Architectures |
|---|---|
linux |
amd64, arm64, 386, arm |
darwin |
amd64, arm64 |
windows |
amd64, arm64, arm, 386 |
freebsd |
amd64, arm64, 386 |
openbsd |
amd64, arm64 |
netbsd |
amd64, arm64 |
wasip1 |
wasm |
js |
wasm |
Less common platform architectures:
| OS | Architectures |
|---|---|
linux |
ppc64le, s390x, riscv64, mips64le |
dragonfly |
amd64 |
Extensions add post-compilation processing steps.
Enable them with -X (or --ext):
gloat app.ys -o app.js -Xhtml
gloat app.ys -o app.wasm -Xprune,gzip
Multiple extensions can be combined with commas, and some accept a
value with =:
gloat app.ys -o app.js -Xserve,html=100
Run gloat --extensions to list all available extensions.
Compress WASM output with Brotli
(auto-installed if needed).
Applies to wasm and js output formats.
gloat app.ys -o app.wasm -Xbrotli
Print the dependency graph of the compiled program (implies prune).
With no value, prints a flat list; with =tree, prints a tree.
gloat app.ys -o app -Xdeps # Flat list
gloat app.ys -o app -Xdeps=tree # Tree view
Include the Go standard library (~135 packages) in the runtime pkgmap.
By default, gloat excludes these to produce smaller binaries — AOT-compiled
programs use direct Go imports instead of pkgmap lookups, so the pkgmap
entries are not needed.
Use this extension only if your program performs dynamic Go interop at
runtime (e.g. calling Go packages by name via the interpreter).
Applies to binary builds (bin, lib, wasm, js, dir).
gloat app.ys -o app -Xgoimports
Compress WASM output with gzip (requires gzip on PATH).
Applies to wasm and js output formats.
gloat app.ys -o app.wasm -Xgzip
Generate a self-contained HTML page for running a JS/WASM module in
the browser.
Only valid with js format (-o app.js).
gloat app.ys -o app.js -Xhtml
gloat app.ys -o app.js -Xhtml='arg1 arg2'
This generates app.html alongside app.js, with the Go WASM
runtime (wasm_exec.js) inlined.
After generation, gloat prints the command to serve locally.
Note:
fetch()requires HTTP, notfile://, so a local server is needed to run WASM in the browser.
Open the page in your default browser after starting the server.
Implies -Xserve (which implies -Xhtml).
Only valid with js format.
gloat app.ys -o app.js -Xopen
gloat app.ys -o app.js -Xopen='arg1 arg2'
The implication chain: -Xopen → -Xserve → -Xhtml.
Prune unused clojure.core and YAMLScript runtime functions from
the compiled output, producing smaller binaries.
Applies to binary builds (bin, lib, wasm, js, dir).
gloat app.ys -o app -Xprune
gloat app.ys -o app.wasm -Xprune
Write a binary size analysis report.
Applies to binary builds (bin, lib, wasm, js).
gloat app.ys -o app -Xreport
gloat app.ys -o app -Xreport=out.md
gloat app.ys -o app -Xreport=keep
gloat app.ys -o app -Xreport=keep+out.md
gloat app.ys -o app -Xreport=html
gloat app.ys -o app -Xreport=report.html
gloat app.ys -o app -Xreport=open
gloat app.ys -o app -Xreport=keep+report.html
By default, the report is written to report.md (Markdown) and the
unstripped binary (needed for symbol analysis) is deleted afterward.
Use =keep to save the unstripped binary as <output>-unstripped,
or =filename.md to write the report to a specific path.
Use =html or =filename.html for an HTML report with sortable
table columns.
Use =open to generate an HTML report and open it in a browser
(implies html).
Combine options with +.
The report includes source files, section breakdown, category analysis,
top packages, and top symbols by size.
Start a local HTTP server after building.
Implies -Xhtml.
Only valid with js format.
gloat app.ys -o app.js -Xserve
gloat app.ys -o app.js -Xserve='arg1 arg2'
Without explicit -Xhtml, the HTML page is served from a temporary
directory so the output directory is left clean.
With -Xserve,html, the HTML is generated alongside the output.
-t, --to ... Output format (inferred from -o; see --formats)
-o, --out ... Output file or directory
--platform ... Cross-compile (e.g., linux/amd64; see --platforms)
-X, --ext ... Enable a processing extension (see --extensions)
--ns ... Override namespace
--module ... Go module name (e.g., github.com/user/project)
--formats List available output formats
--extensions List available processing extensions
--platforms List available cross-compilation platforms
--repl[=value] Start REPL client (see man gloat-repl)
--nrepl[=value] Start nREPL server (see man gloat-repl)
--srepl[=value] Start socket REPL server (see man gloat-repl)
--deps=file Path to gljdeps.edn for --repl/--nrepl/--srepl
--shell Start a sub-shell or run a command (-- cmd...)
--shell-all Like --shell but install all dev tools
--complete ... Generate shell completion script (bash, fish, zsh)
-r, --run Compile and run (pass program args after --)
-f, --force Overwrite existing output files
-v, --verbose Print timing for each compilation step
-q, --quiet Suppress progress messages
--upgrade Upgrade gloat (use --upgrade=v1.2.3 to pin a version)
--reset Remove all cached dependencies and reinstall
-h, --help Show this help
--version Show version
Gloat provides tab completion for all shells.
Completions are automatically loaded when you source .rc (bash/zsh) or
.fishrc (fish).
To manually generate or reload completions:
# Bash
eval "$(gloat --complete=bash)"
# Zsh
eval "$(gloat --complete=zsh)"
# Fish
gloat --complete=fish | sourceCompletions provide:
- All command-line options (short and long forms)
- Available values for
--to(output formats) - Available values for
--platform(cross-compilation targets) - Available values for
--ext(processing extensions) - File completion for source files (
.ys,.clj,.glj) - File completion for
--outoutput paths - Directory completion for
--replbuild directory - File completion for
--deps(.ednfiles)
The Makefile is set up so that you don't need to install any dependencies.
They get installed the first time they are needed by a rule invoked by a make
command that you run.
However, these tools are only accessible inside the Makefile; to the rules that
get run when you use make commands.
In other words, they are NOT available for you to run directly in your shell.
Sometimes you want to run these commands like go, glj, ys and bb
directly in your shell.
Gloat provides two shell variants:
-
gloat --shell— Starts a subshell with the core tools (bb, glj, go, ys) pluswasmtimeon PATH. This is the everyday variant for compiling and running programs. -
gloat --shell-all— Like--shellbut also installs all developer tools (gh, go-md2man, shellcheck, brotli, etc.). Use this when you need the full development environment.
Your shell prompt will be prefixed with (gloat) so that you know you are in
the subshell.
To leave this environment and get back to the shell that you started in, just
press Ctrl-D or run the exit command.
Both variants also support running a single command without starting an
interactive shell, using -- followed by the command:
# Run a command string via bash -c (single argument)
gloat --shell -- 'glj --version'
# Run a command with separate arguments (direct exec)
gloat --shell -- glj --version
# Use --shell-all for commands that need dev tools
gloat --shell-all -- go-md2man --helpgloat --repl starts an interactive Glojure
REPL with full access to Go packages.
Unlike typical Clojure REPLs, this one features full vi and emacs editing with
multiline support, namespace-aware tab completion with descriptive menus, smart
2-space indentation, Ctrl+Z job control with clean terminal restore, Ctrl+R
reverse history search, bracketed paste, and Ctrl+C interrupt of long-running
evaluations.
See doc/gloat-repl.md or man gloat-repl for the
full reference.
gloat --repl # Start REPL (auto-detects ./gljdeps.edn)
gloat --repl=mydir # Use mydir/ as the REPL build directoryThe REPL needs a Go module directory to bootstrap dependencies and generate import glue code. The build directory is resolved in this priority order:
--repl=dir— explicit directoryGLOAT_REPL=dir— environment variable.(current directory) — when./gljdeps.ednis present and no explicit--depsis given./gljrepl/— default fallback (created automatically)
Using . keeps all generated files alongside your source, which is convenient
when your project already has a go.mod and a gljdeps.edn.
./gljrepl/ must either not exist, or be a directory that was previously
initialized (contains a go.mod).
Use --force to proceed anyway if it exists without a go.mod.
To make Go packages available in the REPL, declare them in a gljdeps.edn
file:
{:deps {github.com:yaml:go-yaml {:mvn/version "v3.0.1"}
github.com:google:uuid {:mvn/version "v1.6.0"}}}The deps file is located via --deps, GLOAT_GLJDEPS, or auto-detection of
./gljdeps.edn in the current directory.
Process substitution works too, for one-off experiments:
gloat --repl --deps=<(echo '{:deps {github.com:yaml:go-yaml {:mvn/version "v3.0.1"}}}')On first run, glj fetches the declared packages with go get, generates
import glue code, and re-launches itself with the new packages on the load
path.
Subsequent runs in the same build directory skip the fetch if versions match.
gloat --glj prints the absolute path of the glj binary that gloat would
use, and nothing else.
It is intended for scripting:
glj=$(gloat --glj)
"$glj" --nrepl=.nrepl-portIf glj has not yet been installed, gloat will install it first; any install
output is suppressed so the captured value is just the path.
If your cached dependencies become corrupted or you want a clean reinstall, run:
gloat --resetThis removes the .cache/ directory entirely (binaries, build artifacts,
REPL working dirs).
The next invocation of gloat will reinstall all dependencies from scratch.
Move to the latest released version:
gloat --upgradePin (or roll back) to a specific version. Gloat will switch the checkout,
clear .cache/, and reinstall the dependencies that pair with that release
(including the matching GLJ version) on the next run:
gloat --upgrade=v1.2.3If your clone has uncommitted changes, --upgrade will refuse and ask you
to stash or commit them first.
By default, gloat downloads a pre-built glj binary from GitHub releases.
If a pre-built binary is not available for your platform, or you need to test
unreleased Glojure changes, you can build glj from source.
Set GLOJURE_FROM_SOURCE as an environment variable:
export GLOJURE_FROM_SOURCE=trueTo develop gloat against a local glojure checkout (e.g. to test
unreleased changes), set GLOJURE_DIR to the path of your local
glojure repository:
export GLOJURE_DIR=~/src/glojureThis tells gloat to use your local glojure for go mod replace
directives and to build glj from that directory.
Combined with make repl, this builds glj from your local checkout
and starts a REPL with it:
make repl| Variable | Description |
|---|---|
GLOJURE_DIR |
Path to a local glojure checkout for development. |
GLOAT_GLJDEPS |
Path to a gljdeps.edn file for --repl. Equivalent to --deps=. |
GLOAT_MODULE |
Go module name for compiled output. Equivalent to --module. |
GLOAT_NAMESPACE |
Namespace override for compiled output. Equivalent to --ns. |
GLOAT_REPL |
Default build directory for --repl. Overridden by --repl=dir. |
GLOAT_SHELL |
Preferred shell for --shell when the parent shell cannot be detected (default: bash). |
GLOAT_X_PRUNE |
Set to any non-empty value to enable the prune extension without -Xprune. |
- gloat-repl(1) -- full REPL reference (
man gloat-repl)
Copyright 2026 - Ingy dot Net
MIT License - See License file.