# Rye

Rye is a general-purpose language written in pure Go (no CGO), maintained by the refaktor org. It's distributed both as a standalone interpreter and as a Go library you can import to embed in your own application. The website is [ryelang.org](https://ryelang.org/) and the canonical blog is [[ryelang-blog]].

The unusual design choice: Rye has no reserved forms. There is no hardcoded `if`, `fn`, `loop`, or arithmetic in the evaluator. Every active word is a library-level function. The base evaluator can only load source text into blocks of Rye values and bind values to words (different word types — `set-words`, `mod-words` — are part of the syntax). Everything else is added by registering builtins.

This is what makes the [[whitelist-capability-config]] story work. When you embed Rye in a Go app, the config author starts with nothing and you decide one `RegisterBuiltinsFilter` at a time what they can do.

## Word types and syntax notes

Rye has multiple word kinds carrying meaning in the syntax itself:

- `name:` — set-word, binds a value to a name (const by default)
- `name::` — mod-word, rebinds an existing name
- `Name` — capitalized, generic method dispatch
- `_+`, `_*` — underscore prefix marks an "op-word", an operator-style call
- Block delimiters `{ ... }` create a block of values, `( ... )` groups expressions

The language is not whitespace-sensitive but does require spaces between *every* token, including around parens. The article walkthrough config looks visually like YAML but evaluates as code.

## Embedding API

The Go side uses three packages:

```go
import (
    "github.com/refaktor/rye/env"
    "github.com/refaktor/rye/evaldo"
    "github.com/refaktor/rye/loader"
)

ps := env.NewProgramState()
blk := loader.LoadString(raw, false, ps)
// type-check blk for env.Error, then:
evaldo.EvalBlock(ps, blk.(env.Block))
// inspect ps.Ctx for bound names, ps.Res for the last result
```

Capability registration is two functions:

- `evaldo.RegisterBuiltinsFilter(ps, []string{"if", "_+", "any"})` — whitelist from the built-in pool
- `ps.RegisterBuiltin(name, arity, doc, fn)` — add a custom Go function as a Rye word

Execution caps live on the program state: `ps.MaxCallDepth`, `ps.MaxOps`. Default zero = unlimited.

## Live REPL

`enter-console` is a registerable builtin that drops the running Go process into a Rye REPL with the current evaluation context populated. From there you can list bindings (`lc`), inspect values (`probe`), or rebind via mod-words. On `Ctrl-c`, the host process continues evaluating with the modified context. Useful for config debugging in development; you'd remove the registration in production.

## Comparison with Starlark

Both are languages designed for embedding. Starlark is more mature, Python-shaped, and used at scale by Bazel, Buck, and friends. Differences the Rye author calls out:

- Starlark gives you `if`, `for`, `def` unconditionally — you can't take them away
- Starlark's modules are mostly all-or-nothing
- Rye lets you grant `_+` without `_*`, `if` without `loop`
- Rye aims to be a general-purpose language; Starlark is intentionally a config DSL

## Status and caveats

The author calls Rye "a language in development" and the closing of [[ryelang-whitelist-config]] explicitly says "this is capability control, an exploration, not a security sandbox or something you should go and use today." Rye code runs in your process; unsafe builtins escalate immediately. The interesting bit is the design pattern, not the production-readiness pitch.

Repo: [github.com/refaktor/rye](https://github.com/refaktor/rye). Pure Go, no CGO dependencies. License on the repo.

## Related

- [[ryelang-whitelist-config]] — the article that explains the capability-registration pattern
- [[whitelist-capability-config]] — the general concept
- [[ryelang-blog]] — blog entity for future article tracking
