Skip to content

Core

The top-level functions on the rune table. For a task-oriented introduction, see Scripting Basics.

rune.send(text) -- process aliases and expansion, then send
rune.send_raw(text) -- straight to the socket, no processing
rune.echo(text) -- print to the local display only
rune.connect(address) -- "host:port", optional tls:// scheme
rune.disconnect() -- close the connection
rune.load(path) -- run a Lua script; true, or nil + error
rune.reload() -- tear down the VM, re-run core + user scripts
rune.quit() -- exit the client
rune.config_dir -- path to the config directory (data, not a function)
rune.version -- client version string
rune.debug -- set true to enable rune.dbg output
rune.dbg(msg) -- print msg, but only while rune.debug is true

rune.echo prints locally and never touches the server — pair it with rune.style for colored messages. rune.reload tears down the Lua VM and re-runs the core plus your scripts; rune.session state survives it.

rune.send(text)
  • text (string) — input to process exactly as if you had typed it.

The full input pipeline: ; splits the text into separate commands, #N repeats expand, and each command runs through aliases before going to the server. Repeats are anchored at command position — #3 north repeats, but say #3 cheers is chat text and passes through untouched. Alias expansions are processed recursively (nested aliases work), with a depth limit to catch loops.

rune.send("#2 {get bread bag;eat bread}") -- get/eat, twice
rune.send_raw(text) -> true | nil, err
  • text (string) — sent to the server as-is: no aliases, no ; splitting, no #N repeats.

Returns true, or nil plus an error message (which is also echoed) when the send fails — typically because you’re disconnected. This is what alias and trigger string actions ultimately call.

rune.connect(address)
  • address (string) — host:port with an optional scheme prefix:
Form Connection
host:port Plain telnet (default)
tls://host:port TLS, certificate verified
tls+insecure://host:port TLS, no verification (self-signed certs)

The full address, scheme included, is what rune.state.address reports and what the core stores for /reconnect. Connecting is asynchronous — the "connecting" and "connected" hook events report progress.

rune.connect("tls://mud.example.com:4000")
rune.load(path) -> true | nil, err
  • path (string) — path to a Lua script; ~ expands to your home directory.

Runs the script immediately and returns true, or nil plus an error message. While the script runs, its directory temporarily joins package.path, so it can require() files relative to its own location:

~/.config/rune/
├── init.lua -- main script
├── combat.lua -- require("combat")
└── utils/
└── helpers.lua -- require("utils.helpers")
-- In init.lua:
local combat = require("combat") -- loads combat.lua
local helpers = require("utils.helpers") -- loads utils/helpers.lua

Standard Lua require() semantics apply: modules are cached after the first load, and should return a table of exports.

rune.config_dir and rune.version are plain strings set by the client. rune.config_dir reflects --config-dir, RUNE_CONFIG_DIR, or the platform default, in that order. Set rune.debug to true to make rune.dbg print messages with a [dbg] prefix. When it is false, rune.dbg does nothing:

rune.debug = true
rune.dbg("trigger fired for " .. name)

Related: Scripting Basics · State & Lines · rune.alias · Storage