Lua runner with rich builtin stdlib ("lunascript")
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Ondřej Hruška 0a1bf00701 add os.args() to stdlib 22 hours ago
.claude add sqlite module 4 weeks ago
assets Rework http to not reinvent the wheel for cookies, add fs.getScriptDir() 2 weeks ago
docs add os.args() to stdlib 22 hours ago
lua add os.args() to stdlib 22 hours ago
src add os.args() to stdlib 22 hours ago
tmp expand tui with shorthand markup etc 2 weeks ago
.gitignore feat: add standard library — math, table, utils, os, log 4 weeks ago
.luarc.json fix up lua lib and language server config, add stubs, move demos 2 weeks ago
.stylua.toml add require support 2 weeks ago
Cargo.lock rebrand to "luna" 24 hours ago
Cargo.toml rebrand to "luna" 24 hours ago
Makefile Rework http to not reinvent the wheel for cookies, add fs.getScriptDir() 2 weeks ago
README.md adjust the permission system to also protect network access 23 hours ago

README.md

Luna

Luna embeds a Lua interpreter and adds a standard library and IO access, so a script can reach the outside world — today an HTTP client, SQLite and interactive terminal prompts, with more of the surface below planned — without additional setup.

luna file.lua   # run a script
luna            # start an interactive REPL

Run luna with a script path to execute it, or with no arguments to start an interactive REPL.

The REPL

Running luna with no arguments starts a read-eval-print loop in the same sandboxed environment used for scripts, with the full standard library available. It is convenient for trying out the library or exploring data.

  • Bare expressions print their value (1 + 12); tables are pretty-printed with utils.dump.
  • Statements that span several lines (a for loop, a function body) are detected as incomplete and keep reading until they parse.
  • Async calls such as os.sleep, http.get, and task.join suspend and resume just as they do in a script — each entry runs on the async executor.
  • Line editing and history are provided, with history persisted to ~/.luna_history. Press Ctrl-D to exit (os.exit is not available in the sandbox).

Each entry is compiled as its own chunk, so a local declared on one line is not visible on the next — assign to a global (drop the local) to keep a value across entries.

What it is

Luna is not a Lua implementation; it embeds Lua 5.5 (via mlua) and adds the parts stock Lua omits. Plain Lua ships almost no standard library and no way to reach the outside world without C modules and a build toolchain. Luna provides a standard library written partly in Rust and partly in Lua, together with IO access.

The result is a single binary that runs a .lua file. There is no package manager, build step, or project scaffolding.

The standard library

The standard library is the main purpose of Luna. Available today:

  • Networking — HTTP client (WebSocket and MQTT are planned), guarded by a per-script, per-origin permission system (--allow-net and --no-net override it).
  • SQLite — access to embedded SQLite databases.
  • Filesystem — whole-file read/write and directory listing via fs, guarded by the same permission system per folder (--allow-fs and --no-fs override it; interactive grants are recorded in access.json, and --sandbox denies both files and network).
  • Terminal UI — interactive prompts (confirm, text, select, password, number, date), styled/colored output, and terminal control (cursor addressing, alternate screen, scroll regions) via tui.
  • Core helpersmath, table, and utils extensions, structured log, os time helpers, and task.join concurrency.

Planned:

  • Filesystem ergonomics — glob/walk on top of the existing fs core.
  • TUI widgets & input — progress bars, tables, and raw key/mouse events on top of the existing terminal control.

The intent is for the common case to be a single call rather than a multi-step setup.

How it works

  • Embeds Lua 5.5 via mlua, on an async core (tokio) so IO-heavy scripts don't block.
  • A single self-contained binary. No LuaRocks, no make, no virtualenv.
  • Scripts run in a sandboxed environment modeled on Luau's safe environment: io, package, and debug are not loaded; os is trimmed to its time functions; the bytecode/chunk-loading escape hatches (load, loadfile, dofile, string.dump) are removed. The library Luna provides is the supported way to reach the outside world.
  • A leading #! shebang line is skipped (after an optional UTF-8 BOM), so scripts can be made executable directly. Script files need not be valid UTF-8 — Lua source is byte-oriented.
  • Scripts can be split into files with a sandboxed require: modules are looked up next to the main script (symlinks resolved, so an executable script symlinked into ~/.local/bin finds its files) and in $LUNA_INCLUDE_PATHS, which can also be set in a .env beside the script.

Building

cargo build --release
# binary at target/release/luna

cargo run -- lua/demo/test.lua   # run a script during development

Requires a Rust toolchain (2024 edition). Lua is vendored and built from source, so no system Lua is needed.