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.
The core tools (bb, glj, and go) are installed the first time you run gloat
via the Makes build system. The ys
compiler is installed on demand when compiling YAMLScript source.
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 the standard language bindings
make test-so-bindings
# Include the slow Haskell and Lua bindings
make -C demo/so-bindings test slow=1
# Build and test the bindings with either let-go engine
GLOAT_ENGINE=lgvm make -C demo/so-bindings test
GLOAT_ENGINE=lglvm make -C demo/so-bindings test
# Run a single language binding
make -C demo/so-bindings/python runThe default glj engine and both VM-backed let-go engines support shared
libraries. lgvm invokes the bundled bytecode, while lglvm uses native
lowered Go functions where possible and falls back to the bundled VM for the
rest.
Gloat 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
./pickerFor Bash or Zsh, install gloat to ~/.local and load its shell setup in the
current shell:
source <(curl -sL gloathub.org/install)For Fish:
curl -sL gloathub.org/install | sourceThis runs the Makefile installer, then sources ~/.local/share/gloat/.rc for
tab completion and gloat* man pages.
Install gloat to ~/.local with the Makefile installer:
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 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, its core dependencies will be
installed under the /path/to/gloat/.cache/.local/ directory. The YAMLScript
compiler is added there the first time you compile a .ys file.
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
# For Fish: add to ~/.config/fish/config.fish
source /absolute/path/to/gloat/.rc| 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.
Use -E / --engine to select a compilation engine. Run gloat --engines
to list the available engines and implementation status.
The graalvm engine compiles self-contained, namespaced Clojure programs to
host-native executables with GraalVM Native Image:
gloat --engine=graalvm app.clj
gloat -Egraalvm app.clj -o app
gloat -Egraalvm --run app.clj -- arg1 arg2GraalVM and Leiningen are installed in Gloat's local cache the first time this
engine is used. This initial implementation supports Clojure binary output
only. It does not support YAMLScript, shared libraries, cross-compilation,
gljdeps.edn, Go modules, or -X processing extensions.
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.
-o, --out ... Output file or directory
-f, --force Overwrite existing output files
-t, --to ... Output format (inferred from -o; see --formats)
--formats List available output formats
--ns ... Override namespace
--module ... Go module name (e.g., github.com/user/project)
-E, --engine ... Compilation engine: glj, graalvm, lgvm, lglvm, or lgl (default: glj)
--engines List available compilation engines
--platform ... Cross-compile (e.g., linux/amd64; see --platforms)
--platforms List available cross-compilation platforms
-X, --ext ... Enable a processing extension (see --extensions)
--extensions List available processing extensions
-r, --run Compile and run (pass program args after --)
-T, --time With --run: print the run time (not compile) to stderr
--repl Start REPL client; see 'man gloat-repl'
--nrepl Start nREPL server; see 'man gloat-repl'
--srepl Start socket REPL server; see 'man gloat-repl'
--deps ... Path to gljdeps.edn (Go module deps; AOT or REPL)
--classpath ... Classpath for REPL load paths (e.g. . or src:test)
-C, --color Syntax highlight Clojure code
-F, --fmt Format Clojure code (GLOAT_FMT; default: zprint)
-w, --width ... Width for --fmt formatting
--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)
--which ... Print path to command that gloat uses: go, glj, etc
-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
-F / --fmt formats one Clojure input path with zprint by default and writes
plain text to standard output. It reads standard input when the path is - or
omitted:
gloat -F foo.clj
gloat --fmt - < foo.clj
curl -s https://example.com/code.clj | gloat -F
gloat -F - <(curl -s https://example.com/code.clj)When standard output is an interactive terminal and less is available,
formatted output is displayed with less -rFRX. Redirected and piped output is
written directly without invoking a pager. Set GLOAT_CLJ_PAGER to a complete
pager command, or to none or 0 to disable automatic paging.
Set GLOAT_FMT to use a different complete stdin-to-stdout formatter command.
Commands beginning with cljfmt or zprint are installed automatically;
other commands must already be on PATH:
GLOAT_FMT='cljfmt fix -' gloat -F foo.clj
GLOAT_FMT='cljfmt --function-arguments-indentation zprint fix -' \
gloat -F foo.cljcljfmt also loads .cljfmt.edn or cljfmt.edn from the current directory or
its parents.
Use -w / --width to set the default zprint formatter's width. It requires
--fmt and cannot be combined with GLOAT_FMT; put formatter-specific options
directly in the GLOAT_FMT command:
gloat -F -w 40 foo.clj
gloat -FCw40 foo.clj-C / --color writes the input using the same ANSI syntax highlighting and
rainbow brackets as the Glojure REPL. Coloring is always enabled, including
when output is redirected or piped:
gloat -C foo.clj
gloat --color - < foo.cljInteractive color output is also displayed with less -rFRX when available.
Explicit pipes and redirects bypass the automatic pager.
The options can be combined in either order. Formatting always happens before coloring:
gloat -FC foo.clj
gloat --color --fmt foo.cljThese commands do not change the input file.
Compiler commands also read standard input when their source path is omitted. For example, these commands are equivalent:
gloat -t clj -
gloat -t cljGloat provides tab completion for all shells.
Completions are automatically loaded when you source .rc from bash, zsh or
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) pluswasmtimeon PATH. This is the everyday variant for compiling and running programs. -
gloat --shell-all— Like--shellbut also installs all developer tools (ys, 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 directoryWithout a deps file or explicit build directory, gloat --repl runs glj
in the current directory and creates no build files.
When Go dependencies are involved, the 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./gljrepl/— auto-selected when./gljdeps.ednis present in the current directory- Shared cache — fallback for explicit deps files that are not tied to the current directory
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 --which=CMD prints the absolute path of a command after setting up
Gloat's tool PATH. Use commas to resolve more than one command. It is intended
for scripting:
glj=$(gloat --which=glj)
"$glj" --nrepl=.nrepl-port
gloat --which=glj,go,ysIf Gloat-managed tools have not yet been installed, gloat will install them 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) before the upgrade command exits:
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_FMT |
Complete stdin-to-stdout command used by --fmt (default: zprint). |
GLOAT_MODULE |
Go module name for compiled output. Equivalent to --module. |
GLOAT_NAMESPACE |
Namespace override for compiled output. Equivalent to --ns. |
GLOAT_CLJ_PAGER |
Pager command for interactive --fmt and --color output (default: less -rFRX; none or 0 disables). |
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.