Open-source project
refaktor/rye avatar
refaktor/rye

Rye is a homoiconic language with a Go interpreter behind it

Programming and interaction language. Flexible about syntax, strict about state.

705 stars32 forksGoBSD-3-Clause

At a glance

What is it?
Rye is a high-level dynamic language inspired by Rebol, Factor, shell pipelines and Go, with a Go-based interpreter and console, and it can be embedded into a Go program as a scripting or configuration language. The trade is that it is a beta with no keywords at all, so every control construct is a function call, and the dialect system is where the real complexity lives.
Who is it for?
Rye suits a Go developer who wants a small, embeddable scripting or configuration language with a real REPL, and who is drawn to a homoiconic design where code and data are the same thing.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

No keywords means every construct is a function call

The problem Rye sets out to solve is not a missing feature but a missing shape. It is a high-level, dynamic programming language inspired by Rebol, Factor, Linux shells and Go, and its defining decision is stated plainly in the key characteristics: it is homoiconic, so code is data and data is code, function-oriented, with no keywords so that everything is a function call, and expression-based, so everything returns a value. That last pair of choices is what makes the pipeline style in the examples read the way it does. A value is produced, a method is applied to it, and the result is piped into the next operation, which is a shell pipeline with words in it. The intended user is a Go developer who wants a language that embeds cleanly, and the README is direct about the appeal, calling it a scripting companion for Go programs.

Values flow through pipes, and blocks are values too

The quick examples show the language in about fifteen lines, and they are worth reading closely because they demonstrate several mechanisms at once:

red
print "Hello World"

"Hello World" .replace "World" "Mars" |print
; prints: Hello Mars

"12 8 12 16 8 6" .load .unique .sum
; returns: 42

{ "Anne" "Joan" "Adam" } |filter { .first = "A" } |for { .print } 
; prints:
; Anne
; Adam

fac: fn { x } { either x = 1 { 1 } { x * fac x - 1 } }
; function that calculates factorial
range 1 10 |map { .fac } |print\csv
; prints: 1,2,6,24,120,720,5040,40320,362880,3628800

kind: "admin"
Open sqlite://data.db |Query { select * from user where kind = ?kind }
; returns: Table of admins

Read %name.txt |fix { "Anonymous" } |Post* https://example.com/postname 'text
; makes HTTP post of the name read from a file, or "Anonymous" if file failed to be read

A string is a value with methods on it, so a replace call produces a new string that is then piped into print. A pipeline of three words, load, unique and sum, over a space separated string returns 42. A block of names is filtered by a block that tests the first element, and the survivors are iterated. The pipe operator is what binds these together, and the code blocks passed to filter and for are values in their own right, which is the homoiconic idea in practice. The factorial example defines a recursive function with fn, a block for the body, and a self reference, and the range example then maps that function over a range and prints the results as CSV.

Dialects are specialised interpreters, and that is the complexity

The characteristic that needs the most thought from an adopter is the multiple dialects feature, described as specialised interpreters for different tasks. The README example shows a dialect in action without naming it: opening a SQLite database and querying it with a block that captures a variable, and reading a file with a fallback when the read fails, which shows the dialect in use as a scoped set of operations. The safety-focused characteristic sits alongside it, with explicit state changes, a separation of pure and impure functions, and a validation dialect. This is the part of the design that makes Rye different from a Lisp with a Go backend, and it is also the part that will take longest to learn, because the same word can mean different things depending on which dialect is active. The security/ directory at the root of the repository suggests this is an area the project works on actively.

Building is one go build, and build tags shrink the binary

The build instructions are Go-shaped, since the interpreter is written in Go and the module is github.com/refaktor/rye. You need Go 1.21.5 or later, then clone the repository:

bash
   git clone https://github.com/refaktor/rye.git
   cd rye

then choose one of three build options. The standard build is a plain go build, or the build script in the repository root. The minimal build uses the b_tiny tag for fewer modules and a smaller binary, and the custom build selects specific modules by tag, for example b_tiny, b_sqlite, b_http and b_json together, and the smallest variant is a single command:

bash
     go build -tags "b_tiny" -o bin/rye

That tag scheme is a real design decision rather than a packaging detail, because it means the same source produces a scripting binary and a full one. The go.mod requires Go 1.26.1 for the module itself, and it pulls in a large dependency set covering HTTP, databases, MQTT, SSH, search and more, which is the practical reason the tiny build exists.

The REPL and the script runner are the same binary

Running Rye takes one of two commands, and the distinction is only the argument. Running the binary with no argument starts the REPL, and running it with a script path executes that file. The build produces it in a bin directory, and the go build invocation names the output explicitly, so the binary lands where the test commands expect it. The test workflow is written in Rye itself, running the built binary against the info directory with the test argument, and a second invocation generates the function reference with the doc argument, which is a nice detail: the language documents itself using its own runtime. The repository root carries helper scripts for the different targets, including build, buildwasm, build_tinygo and buildrpi, which tells you the project targets embedded and single board hardware as well as desktops.

A WebAssembly build that runs in the browser

Rye can run in browsers and other WASM environments, and the build is a single cross compile. Setting GOOS and GOARCH to js and wasm with the b_tiny tag produces a wasm file from main_wasm.go, and there is a helper script for the same job. The result is served from a shell page, and the README points at a local address for it. The wasm directory at the root of the repository holds the result, and the serve_wasm.rye file in the root is the server that serves the shell, which is a neat touch: the web build is served by the language it hosts. The examples directory also includes a server_load.rye example, which suggests load handling is part of what the language is designed around.

Pre-built binaries, package managers and two Docker images

Getting Rye without building it takes three routes. Pre-compiled binaries for Linux, macOS, Windows and WASM are published on the releases page, and the package manager routes are a single command each:

bash
brew install ryelang
yay -S ryelang

The README credits the two maintainers behind the Homebrew and Arch packages. The Docker images come in a binary flavour that runs the published image directly, and a development flavour built from the repository with the .docker directory. Both are run with the same interactive flags. The Docker route is worth noticing because the binary image also includes Emacs-nox, which is how you get a browser-based REPL for a language whose primary interface is a terminal.

Beta status, an editor ecosystem and a small community

The status line in the README is the one to keep in view: beta, with the core language design stated as stable, and the focus on improving the runtime, documentation and usability. That is a project that has settled its syntax and is still moving its tooling, and the repository reflects that, with a rye_syntax_checklist.md and a rye_gotchas.md at the root alongside the CLAUDE.md and AGENTS.md files, and separate documentation and code style rules for contributors. Editor support is broad for a young language, with a VS Code extension, syntax highlighting for Emacs and Neovim, and a tree-sitter grammar for Helix. The community channels are GitHub Discussions, Reddit, a Discord server described as very new with few users, and a Rosetta Code category, and the extensions listed are the GUI toolkit binding, a 2D game engine binding and a binding generation toolkit, the latter two marked as work in progress.

Editorial conclusion

Rye suits a Go developer who wants a small, embeddable scripting or configuration language with a real REPL, and who is drawn to a homoiconic design where code and data are the same thing. It does not suit a team that wants a language with a conventional statement syntax, since Rye has no keywords and every operation is a function call, and it does not suit a project that needs a large standard library today, because the README states the focus is on the runtime, documentation and usability. Before adopting, read the language documentation and the syntax checklist in the repository, try the REPL before committing to a build, and note that the last push to the repository was on 2026-10-16 with release v0.2.65 dated 2026-10-12.

Frequently asked questions

How do I build Rye from source?

Install Go 1.21.5 or later, clone the repository with `git clone https://github.com/refaktor/rye.git`, then build with `go build -o bin/rye`, or use the build script. A smaller binary comes from `go build -tags "b_tiny" -o bin/rye`, and specific modules can be selected with tags such as b_tiny, b_sqlite, b_http and b_json.

What are the main characteristics of the Rye language?

Rye is homoiconic, so code is data and data is code, function-oriented with no keywords so everything is a function call, expression-based so everything returns a value, has first-class functions where functions and code blocks are values, offers multiple dialects as specialised interpreters, and is safety-focused with explicit state changes, a pure and impure function separation and a validation dialect.

How do I run a Rye script?

The built binary takes a script path as its argument, for example `bin/rye script.rye`, and running it with no argument starts the REPL instead. The tests are run from the info directory with `../bin/rye . test`, and the same binary generates the function reference with `../bin/rye . doc`.

Can Rye run in a browser?

Yes. The README describes a WebAssembly build with `GOOS=js GOARCH=wasm go build -tags "b_tiny" -o wasm/rye.wasm main_wasm.go`, or the helper script. The result is then served from a shell page, and the repository root holds a serve_wasm.rye file that does the serving.

Is Rye stable enough to depend on?

The README states the status as beta, with the core language design stable and the focus on improving the runtime, documentation and usability. The last push to the repository was on 2026-10-16 and the newest tagged release is v0.2.65 from 2026-10-12. The licence is BSD-3-Clause.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. README
  4. refaktor/rye on GitHub
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/refaktor-rye.svg)](https://hysenlabs.com/projects/refaktor-rye)

Was this useful?