Operator: A typed command console with permissions and auditing built in

Documentation · GitHub · Discord

Operator is a command console and admin framework for Roblox, written in pure Luau.

  • Permissions are built in. Roles are configuration, not a hook you have to write.
  • Nothing reaches a player who isn’t allowed it. No modules, no remote, no way to tell it’s installed.
  • One require and one call on the server. There’s no client script to set up.
  • Arguments arrive as a typed table, so your editor knows what’s in them.
  • Define your own argument types with validation and autocomplete.
  • Every command is logged, with an optional Discord webhook.
External Media

Here’s a command:

local Operator = require(game.ServerStorage.Operator)
local Command = Operator.Command
local Types = Operator.Types

export type KickArgs = { target: Player, reason: string }

local kick = Command.new("kick") :: Command.Builder<KickArgs>
kick:description("Kick a player")
    :arg(Types.Player, "target", "Player to kick")
    :arg(Types.String, "reason", "Reason shown to the player")
    :permission("moderator")
    :run(function(ctx, args)
        args.target:Kick(args.reason)
        ctx:reply(`Kicked {args.target.Name}`)
    end)

And here’s the entire setup:

Operator.Start({
    Commands = script.Parent.Commands,
    DefaultCommands = { "debug", "moderation" },

    Roles = {
        owner = { UserIds = { 1234567 }, Inherits = { "moderator" } },
        moderator = { GroupId = 7654321, MinRank = 200 },
    },
})

That’s it. Press F2 in game and you have a console.

Why I built it

I’ve used Cmdr across a few games and it’s excellent, but two things kept costing me time.

Permissions are entirely yours to write. Cmdr blocks every command until you set up a BeforeRun hook, and that hook is a raw callback you write from scratch in every project. There’s no concept of a role anywhere in it. In Operator, roles are part of the config, they support group ranks and user IDs, and if you configure nothing you get a console for the place owner and nobody else.

The console announces itself to everyone. Cmdr parents itself into replicated storage on require, so every player in the server can see it exists, and unauthorised players still see every command in autocomplete. Operator installs to ServerStorage only. When a player passes the permission check, the server clones the interface into their PlayerGui and creates their remote there. A player with no permissions receives nothing at all, and their PlayerGui contains no trace of it.

Command implementations never reach any client either. The client gets a manifest of what it may run, and the server re-validates every dispatch from scratch.

What else is in there

Audit logging that isn’t an afterthought. Every dispatch produces a record with the executor, the command, resolved arguments, targets, timestamp and job ID, all stamped server side. There’s a searchable log panel in the console, and an optional Discord sink that posts a proper embed. Client commands can report themselves too, and those records are clearly marked as client reported, because they’re the client’s word and not verified.

Client commands. Some commands only make sense on the client, like toggling a debug overlay. Declare :runClient() and it runs locally with no remote round trip and no server handler.

Themes. Three ship, all dark. You can also pass your own colour table and override any of the twelve tokens. Layout isn’t configurable.

Touch support. Keyboardless devices get a topbar icon and larger tap targets.

Editor support. Doc comments and real return types throughout, so hovering a function tells you what it does and typos in your argument table get caught before you run.

Why you might not want it

Being honest about this, because I’d rather you find out now than after installing.

  • It ships 14 commands, not 400. Three small packs. If you want a big ready made moderation and fun suite, this isn’t that. You write your own library.
  • You can’t restyle the interface. Colours are yours, layout and spacing are not. If you need a different interface, there’s a documented hook for mounting your own.
  • Everything is code. Commands, argument types and guards are all Luau. There’s no in-game builder or config file route.
  • Moderation history doesn’t survive a restart. The log panel is per server and in memory by design. Durable history means attaching your own audit sink.
  • It’s v0.2.0. Early days. The public API can still change in a minor version until 1.0.

Links

Grab the .rbxm from the GitHub release rather than the toolbox. Admin consoles are a popular thing to backdoor, and I’d rather you took it from somewhere you can read the source.

Credits

Operator’s console interface takes its visual design and interaction model from Centurion by Paradoxum, which is a great piece of work and the reason the console looks as good as it does. Cmdr by evaera is the prior art the whole category rests on, and a lot of what Operator does differently exists because I spent years using Cmdr and knew what I wanted to change. The interface is built on Vide by centau, and the topbar icon uses TopbarPlus.

Closing

This started because I was porting my commands between games for the third time and got tired of rewriting the same permission hook. It ended up considerably bigger than that.

It’s v0.2.0 and I’m sure there are rough edges I haven’t hit yet, so if you run into something please open an issue on GitHub or drop into the Discord and I’ll take a look. Feedback on the API is especially welcome right now, while changing it is still cheap.

Cheers,
cb12438

1 Like