v0.0.2 released — modules, generics & the full regex dialect →

Text processing,
built into the language.

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.

  1. One obvious way. For any task there is exactly one idiomatic construct — no redundant syntax.
  2. Functional-first. Immutable bindings, transformed data, first-class functions, expressions everywhere.
  3. Inferred static types. Every expression is typed at compile time; annotations are rarely required.
  4. Text is a first-class concern. Regex and grammars are the language's signature capability.
  5. 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
Tutorial series

Get started with guji

Six short, hands-on parts. Each one builds on the last, shows you exactly what to type, and tells you what you should see.

Prerequisites

  • Some programming experience. The code here is short, but it helps to know what a function is.
  • The guji binary. A single self-contained download — part one walks you through it. (No toolchain needed.)
  • A command terminal. Any shell on Linux or macOS; WSL on Windows.
  • Optional: a C compiler (cc/gcc/clang) — only needed for part six, where you compile to a native binary.

Prefer reference material? The full specification lives in the documentation.

Get guji

Download a prebuilt binary — no toolchain required. Current release: v0.0.2.

Download a binary

PlatformArchitectureDownload
Linuxx86-64guji-v0.0.2-linux-amd64.tar.gz
LinuxARM64guji-v0.0.2-linux-arm64.tar.gz
macOSApple Siliconguji-v0.0.2-darwin-arm64.tar.gz
macOSIntelguji-v0.0.2-darwin-amd64.tar.gz
Windowsx86-64guji-v0.0.2-windows-amd64.tar.gz
Sourceguji-v0.0.2-src.tar.gz

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.

Download v0.0.2 — built from commit 703bf6b; checksums in SHA256SUMS.

2026-06-11 · Release

guji v0.0.1 — first public release

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.