Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

shell Module

Public Luau surface over the __shell Internal FFI namespace — same emulated Unix shell that powers the MCP bash tool.

Purpose

Wrap the raw __shell.* FFI namespace in a typed Luau table that gets auto-injected as _G.shell via the prelude. 60+ POSIX-style builtins (ls, cat, grep, find, echo, sed, awk, ...) run against the virtual scene filesystem. Pipes, redirects, variables, and control flow all work; shell.run returns the result table, shell.runAsync returns a promise.

Where the command runs

shell.run runs the command on the calling thread — cheap, since the VFS is in memory, and an ls or a cat costs microseconds.

Four builtins — run, luau, zm, zero — execute Luau, which the engine runs on its frame loop, and the calling thread is that frame loop. From a coroutine shell.run queues such a command to run off the frame loop and yields until it finishes, so the caller still gets one result table. From a thread that cannot yield it comes back as a result whose stderr says so and names shell.runAsync.

That handoff runs the whole command line from the start, so it is taken only for a line where every command reached one of those four builtins. A line that mixes them with a command that already ran — zm add x; echo done >> log — returns the same refusal instead, since running the line again would repeat the echo. Issue such a line through shell.runAsync + task.await, which runs off the frame loop from the first command.

Finding out what a builtin reads

help with no argument lists every builtin the shell carries, and a builtin's own --help prints its usage. awk --help prints the grammar the awk builtin parses: its options, the statements (print, printf, assignment and the compound forms += -= *= /= %= ^=, if / else, while, do ... while, the three-clause for, break, continue, next, exit), the operators (arithmetic, ++ and -- in prefix and postfix position, comparison, logical, ~ and !~, concatenation by juxtaposition, $expr), the variables (NR, NF, FS, OFS, ORS, OFMT, CONVFMT) and the functions it carries: the string set (length, substr, index, split, sub, gsub, match, sprintf, tolower, toupper) and the arithmetic set (int, sqrt, log, exp, sin, cos, atan2, rand, srand). An argument outside an arithmetic function's domain answers a value with no finite decimal form and names itself on stderr, leaving the program running. srand seeds the stream rand draws from and reports the seed it was running from, so a program that names a seed replays its own sequence.

Usage

-- Returns the result table once the command has completed
local r = shell.run("ls /zero/source")
print(r.stdout)
if not r.ok then warn(r.stderr, r.exitCode) end

-- Async — returns a promise; the resolved value is a JSON string
local json = task.await(shell.runAsync("find /zero -name '*.luau'"))

Exports

  • shell.run(command) -> ShellResult — returns { stdout, stderr, exitCode, ok }.
  • shell.runAsync(command) -> string — async promise ID resolving to the JSON-encoded result string.