Moud

Server console#

The server console reaches the servers your fleet runs for a published game. It shows a server's log as it is written and runs the admin commands your server scripts declared. It can also run Luau on a server, once you turn that on for yourself.

Owners and developers of the game can use it, and creator keys with the console scope. Analytics and moderator members cannot, and neither can website reviewers.

In the editor#

Open Window > Server Console in a place you published. The panel lists the game's running servers; pick one from the dropdown. Each entry shows the place, the server id, how many players are on it, and whether it runs the beta or is reserved.

The log follows the server's own console output, prints and warnings of server scripts included. Filter narrows the lines shown. Type a command in the line at the bottom and press Enter; the Commands dropdown lists what the server's scripts declared, with their descriptions. Up and down recall earlier lines.

Declaring admin commands#

A server script declares a command with game.admin:command. The handler gets the words typed after the command name and who ran it. What it returns comes back as the reply:

luau
-- server/main.luau
local saves = store("players")

local function playerNamed(name: string): Player?
    for _, player in game.players:list() do
        if player.name == name then return player end
    end
    return nil
end

game.admin:command("coins", "coins <name> <amount>", function(args, caller)
    local player = playerNamed(args[1] or "")
    local amount = math.floor(tonumber(args[2]) or 0)
    if not player then return "nobody called " .. tostring(args[1]) .. " is on this server" end
    if amount == 0 then return "give a whole number of coins" end

    local total = saves:update(player.id, function(old)
        old = old or { coins = 0 }
        old.coins += amount
        return old
    end).coins
    return player.name .. " has " .. total .. " coins, given by " .. caller.name
end)

game.admin:command("kick", "kick <name> <reason>", function(args)
    local player = playerNamed(args[1] or "")
    if not player then return "nobody called " .. tostring(args[1]) .. " is on this server" end
    player:kick(args[2] or "Kicked by a moderator")
    return "kicked " .. player.name
end)

coins "Steve Two" 50 in the console gives Steve Two fifty coins in their save, through update so a purchase landing at the same moment is not lost, and the reply says how many they have now. kick Steve "spamming chat" sends Steve back to the menu with that message.

Words are split on spaces, and a part in double quotes stays one word, so coins "Steve Two" 50 gives args as { "Steve Two", "50" }. caller.name is the creator's name and caller.id their account id. A handler may wait, like any script function; the console waits up to 20 seconds for the reply. An error in the handler comes back as the reply and shows in the server's log.

Call
game.admin:command(name, description, handler) declares a command, a second call with the same name replaces it
game.admin:remove(name) removes one
game.admin:commands() the declared commands, each { name, description }

A name starts with a letter and has up to 32 letters, digits, _ or -. A server declares up to 200 commands. Commands only run on the server, and they go away with the script that declared them. Nothing reaches a command except through the console, so a player can never run one.

The script console#

Running Luau on a live server is off by default. Allow Luau in the panel turns it on for you on this game. It stays off for every other member until they turn it on too, and a creator key can never use it. Once it is on, a Luau toggle next to Commands switches the line to Luau. Each line runs in the server's scripts the same way the editor's command bar runs it on a server you host. Prints go to the server's log, errors come back as the reply.

Every call is logged#

Moud keeps a line for every console call: who made it, with a key or signed in, the server, the kind of call, the command or Luau it sent, and how it went. Refused calls are logged too. GET /creator/games/<slug>/console/log lists the latest 100 for anyone who may use the console. Lines older than 90 days are removed, RETAIN_CONSOLE_DAYS changes that on a self-hosted catalog.

From a key#

The same calls work with a creator key that has the console scope, all under /v1:

Call
GET /creator/games/<slug>/console the running servers, and whether the script console is on for you
POST /creator/games/<slug>/console with op logs and server the newest log lines and next, send next back as after to get only what came since
POST /creator/games/<slug>/console with op commands the declared commands
POST /creator/games/<slug>/console with op command and line runs a command, the answer has reply
POST /creator/games/<slug>/console with op script and line runs Luau, never with a key
POST /creator/games/<slug>/console/scripts with enabled turns the script console on or off, signed in only
curl -H "Authorization: Bearer moud_ck_..." -H "content-type: application/json" \
  -d '{"server":"3f2a-91c0-77de","op":"command","line":"coins Steve 50"}' \
  https://<catalog>/v1/creator/games/my-game/console

A person or key makes up to 120 console calls a minute on a game, 20 of them commands or Luau, and a server takes 60 commands a minute from everyone together. Past that the answer is 429 with retry-after. A command is at most 2000 letters, Luau at most 16000.

A command or a line of Luau runs on the server's next tick. When the fleet running the server is not connected to the catalog the answer is 503, and when the server does not answer in time it is 504.