guji is a statically-typed, compiled, functional-first language where
regex literals and PEG grammars are part of the language — not a library you import.
Statically typed·Compiles to a single native binary·No nulls, no exceptions·Immutable by default
grammar.guji
grammar Email {
rule TOP { <user> '@' <domain> }
token user { \w+ }
token domain { \w+ '.' \w+ }
}
sub main(): Int {
match Email.parse('ada@example.com') {
Some($b) {
print($b.text) # ada@example.com
match $b<user> { Some($u) { print($u.text) } None { } } # ada
match $b<domain> { Some($d) { print($d.text) } None { } } # example.com
}
None { print('invalid') }
}
0
}
Declare a parser like you declare a type. parse() returns a typed tree — no parser generator, no build step.
regex.guji
sub main(): Int {
# lookahead: user part only if an @ follows
match 'ada@example.com' ~~ /\w+(?=@)/ {
Some($m) { print($m[0].unwrap()) } # ada
None { print("no match") }
}
# backreference: find a doubled word
match 'hey hey you' ~~ /(\w+) \1/ {
Some($m) { print($m[1].unwrap()) } # hey
None { print("no echo") }
}
# rewrite with a capture template
print("2026-06-12".replace(/(\d+)-(\d+)-(\d+)/, '$3/$2/$1'))
0
}
The full dialect — lookaround, backreferences, possessive quantifiers, grapheme matching — checked at compile time, compiled to native code.
pipeline.guji
sub main(): Int {
@nums = [1, 2, 3, 4, 5]
$even = @nums.filter({ $_ % 2 == 0 }).map({ $_ * 2 })
print("sum: { $even.sum() }") # sum: 12
%ages = {"ada": 36, "bo": 25}
for $name, $age in %ages {
print("$name is $age")
}
0
}
Topic lambdas ($_) and uniform call syntax: every function chains, data flows left to right.
types.guji
enum Shape {
Circle($radius: Int)
Square($side: Int)
}
sub area($s: Shape): Int {
match $s { # checker proves this exhaustive
Circle($r) { $r * $r * 3 }
Square($n) { $n * $n }
}
}
sub parse_age($s: Str): Result[Int, Str] {
$n = $s.parse_int()? # ? propagates the Err
Ok($n)
}
No nulls, no exceptions: absence is Option, failure is Result, and match must cover every case.
Why guji
A small, modern language that takes text seriously and stays honest about types.
Built for text
Regex literals and PEG grammars are language constructs with compile-time checking — the work other languages bolt on through libraries is guji's native ground.
Safe by construction
Static types with inference, immutable-by-default bindings, exhaustive match, and no nulls or exceptions. Whole categories of bugs don't compile.
Zero-friction shipping
One command compiles your program to a single self-contained native executable. No runtime, no VM, no dependency tree to deploy.
First-class regex
Regex literals like /(?<user>\w+)/ and the ~~ match operator return an Option[Match] with named and positional captures.
PEG grammars
Declare grammar / rule / token productions and parse() straight to a typed parse tree (Bush). The signature feature.
Static typing & inference
Local type inference, immutable-by-default bindings, and match that the checker proves exhaustive.
Option, Result, ?
No nulls. Fallible code returns Option/Result, and ? propagates the empty/error case to the caller.
Compiles to native
The compiler lowers programs to C and invokes your system cc to produce a standalone native binary.
Functional-first
Topic lambdas ({ $_ * 2 }) and data-first uniform calls let you chain .filter(...).map(...).sum() cleanly.
Five principles, one language
From §1.1 of the specification — the rules every guji feature answers to.
One obvious way. For any task there is exactly one idiomatic construct — no redundant syntax.
Inferred static types. Every expression is typed at compile time; annotations are rarely required.
Text is a first-class concern. Regex and grammars are the language's signature capability.
One binary. Ahead-of-time compilation to a single self-contained native executable.
Start in a minute
shell
curl -LO https://guji.dev/files/guji-v0.0.2-linux-amd64.tar.gz
tar xzf guji-v0.0.2-linux-amd64.tar.gz # one self-contained binary
./guji hello.guji # run a program
./guji # start the REPL
Verify your download against SHA256SUMS. All artifacts are also browsable at /files/.
Install
# Linux x86-64 shown; pick your platform from the table above
curl -LO https://guji.dev/files/guji-v0.0.2-linux-amd64.tar.gz
sha256sum -c --ignore-missing <(curl -s https://guji.dev/files/SHA256SUMS)
tar xzf guji-v0.0.2-linux-amd64.tar.gz
sudo mv guji /usr/local/bin/ # or anywhere on your PATH
guji # REPL starts -- you're done
Build from source (alternative)
If you prefer to build it yourself, you need the Go toolchain (1.22+).
Unpack the source tarball, then from its root:
go build -o guji ./src/cmd/guji
Platform notes
The interpreter and REPL are fully self-contained — download and run, no dependencies.
macOS: guji v0 binaries are not yet notarized with Apple, so Gatekeeper will warn
“Apple could not verify ‘guji’ is free of malware” if the tarball was downloaded with a
browser. Two fixes:
Download in the terminal with curl as shown above — curl doesn't attach the
quarantine attribute, so the warning never appears; or
clear the quarantine flag after extracting: xattr -d com.apple.quarantine ./guji
You can verify what you ran is exactly what we published via SHA256SUMS.
Signing/notarization is planned.
Native compilation (guji build) additionally needs a C compiler on your PATH (cc/gcc/clang; on Windows, use WSL or MinGW/Clang).
What works in v0
The interpreter implements the v0 surface end to end and is the reference the native compiler is
tested against. The native compiler passes a 102-fixture acceptance suite and supports
the full language tour natively — including modules (the import closure compiles into
one binary), monomorphized user-defined generics, and the full §13 regex
dialect (lookaround, backreferences, possessive quantifiers, atomic groups, grapheme matching).
Remaining native-only gaps are narrow (some deeply-nested collection operations, string-subject
match, mutually-recursive enums); concurrency is post-v0.
See the docs for the current status in detail.
Previous releases
All releases remain available at /files/ with checksums —
v0.0.1 (c6d531b) was the first public build.
guji is dual-licensed MIT OR Apache-2.0.
Release v0.0.2 is built from commit 703bf6b of the reference implementation.
News
Releases and announcements from the guji project.
2026-06-12 · Release
guji v0.0.2 — modules, generics, and the full regex dialect
Nine days of intense work on the reference implementation land in one release.
The headline: three areas that v0.0.1 rejected with "restoration in progress"
diagnostics are now fully implemented — in the interpreter and the native compiler.
Modules (§16).import path::name, pub exports, and
qualified access work end to end; the whole import closure compiles into one native binary.
User-defined generics (§3.3). Your own sub first[T],
enum Box[T], and class Pair[K, V] — type-checked, inferred, and
monomorphized in native builds.
The full §13 regex dialect. Lookaround, backreferences, possessive
quantifiers, atomic groups, the <{ … }> splice, and grapheme matching
(\X, \p{RGI_Emoji}) on a purpose-built backtracking engine.
Closure capture fixed. Capturing lambdas get heap-allocated environments,
removing v0.0.1's known shared-capture divergence.
102-fixture acceptance suite (up from 58): every fixture compiles natively and
must byte-match the interpreter's output and exit code.
The first public guji binaries: a complete tree-walking interpreter with REPL, a native
compiler validated by a 58-fixture acceptance suite, first-class regex, and PEG grammars —
shipped as a single self-contained executable for Linux, macOS, and Windows, alongside the
launch of this site, the rendered specification, and the six-part tutorial.
Built from commit c6d531b. All artifacts remain at /files/.
Community
guji is young and deliberately small. Here is exactly where things stand.
Project status
guji is an owner-led project at v0. The language surface is specified, the
reference implementation moves quickly, and honesty about maturity is a project value: the
roadmap and the
status notes say precisely what works and what doesn't.
Getting the source
Every release ships its full source as a tarball at /files/, dual-licensed
MIT OR Apache-2.0. A public source-control presence (a guji-lang
org on a public host) is planned — release tarballs are the distribution channel until then.
Contributing
Code contribution isn't open yet — the v0 implementation is changing too fast for external
patches to land well. What helps right now: use the language. Work through the
tutorial, write something real, and note where guji surprises
you. When a public repository and RFC process open (modeled on Rust's RFCs and Python's PEPs),
that feedback becomes the first issues.
Governance
BDFL-style for now — the same way Go, Python, Perl, and Rust all began. A public proposal
process arrives when more than one person is making language decisions; a foundation, if ever,
is years away. The deferred-features appendix records
what has been consciously postponed, so the project's restraint is documented rather than
accidental.
FAQ
Why another language?
Because text processing is still a library problem in every mainstream static language.
guji makes regex and grammars part of the language — compile-time checked, natively
compiled — while keeping modern table stakes: inference, Option/Result, single-binary output.
Is guji production-ready?
No. v0 is for learning, experimenting, and giving feedback. The interpreter implements the
full v0 surface; the native compiler covers most of it with documented gaps.
Why the sigils?
$scalar, @list, %map declare a binding's shape at
a glance, at every use site. The type system still tracks precise types underneath — sigils
are ergonomics, not dynamic typing.
What's a Bush?
The parse-tree type a grammar produces. Email.parse($s) returns
Option[Bush]; each named production becomes an addressable sub-tree
($b<user>) with its matched text (.text). Smaller than a
tree — a bush.
Is there a package manager?
Not yet. v0 modules are file-based with qualified imports. A registry is a much-later
milestone — the naming (mirror.guji.dev) is reserved, the service is not built.
Why is the reference implementation in Go?
Go made v0 fast to build and easy to port: the interpreter is pure Go, and the native
compiler lowers guji to C. Self-hosting is a question for after the language has proven
itself, not before.