Skip to content

Migrating from Other Clients

Rune has no in-client command language: scripting is Lua. Aliases, triggers, and timers live in ~/.config/rune/init.lua (auto-loaded at startup), and the edit loop is: change the file, /reload, keep playing. /lua <code> runs one-liners without touching a file.

A trigger you’d write like this in TinTin++:

#action {%1 attacks you} {flee}

looks like this in init.lua:

rune.trigger.regex("(\\w+) attacks you", "flee")
TinTin++ Rune equivalent
#alias {k} {kill} rune.alias.exact("k", "kill"); typed args are appended, so k rat sends kill rat
#alias {gr %1} {get %1;wear %1} rune.alias.regex("^gr (.+)$", "get %1;wear %1")
#action {%1 attacks you} {flee} rune.trigger.regex("(\\w+) attacks you", "flee")
#gag {spam line} rune.trigger.contains("spam line", nil, { gag = true })
#highlight {gold} {yellow} rune.trigger.contains("gold", function(m, ctx) return rune.style.yellow(ctx.line:clean()) end)
#substitute a trigger action returning the rewritten string
#tick / #ticker rune.timer.every(60, "save", { name = "tick" })
#delay {5} {stand} rune.timer.after(5, "stand")
#var plain Lua variables (rune.session/rune.store for state that must survive /reload/restarts)
#if, #math, #loop Lua (if, arithmetic, for)
#showme rune.echo(text)
#split rune.ui.layout{...} + bars
#session x host port /connect host port, /world add for bookmarks
#read file.tin /load file.lua
#write your scripts are already files
#3 north works as-is: #3 north, #3 {kill rat;loot}
; separator works as-is: kill rat;loot

The scripting language is the same; the API names differ:

Mudlet Rune equivalent
send("kill rat") rune.send("kill rat")
echo("text") / cecho(...) rune.echo(text), colored via rune.style.*
matches[2] (first capture) matches[1]; there is no whole-match slot
tempTimer(5, code) rune.timer.after(5, action)
tempRegexTrigger(pattern, code) rune.trigger.regex(pattern, action)
script editor window your $EDITOR; Ctrl+E edits the input line in it too

Regex aliases and triggers substitute %1, %2, and so on from captures in string actions, so most one-liners port verbatim. Function actions receive (matches, ctx) when you need logic:

rune.trigger.regex("^(\\w+) tells you '(.+)'$", function(matches)
rune.echo(rune.style.cyan("TELL from " .. matches[1]))
end)

; chaining, #N repeats, /commands, up-arrow history, Ctrl+R history search, and tab completion all behave the way terminal-client muscle memory expects.

Everything lives under ~/.config/rune/ — the full path table is in Installation. Your scripts go in init.lua; bookmarks and durable state in store.json.

Full signatures for every rune.* namespace: API reference.

Triggers is where most ports start — match modes, captures, gagging, and rewriting in rune’s terms.