Skip to content

Operator

luau
local Operator = require(game:GetService("ServerStorage").Operator)

The package entry point. This is the only require you need. Every public module and type is reachable from here or from the handle Start returns.

luau
local Operator = require(game:GetService("ServerStorage").Operator)
local Command, Types = Operator.Command, Operator.Types

Properties

PropertyTypeMeaning
Operator.Versionstringthe package version, as shown in the Discord sink footer
Operator.CommandCommandthe command builder
Operator.TypeTypethe argument type builder
Operator.TypesTypesthe nine built-in argument types
Operator.PacksPacksthe default command packs
Operator.AuditAuditthe audit log module
Operator.ActionLogActionLogthe log panel's store
Operator.RegistryRegistrycommand and type registration
Operator.DispatcherDispatcherparsing, binding and running
Operator.RolesRolesrole resolution
Operator.LogLogbuilds the logger Operator writes through
Operator.SuggestionCacheSuggestionCachecaches an argument type's suggestions
Operator.LogRecordLogRecordthe log panel's record shapes
Operator.ParsingParsingTokenizer, Parser, Binder
Operator.SinksDiscord{ Discord = ... }

Start builds Audit, Registry, Dispatcher and Roles for you and puts the instances on the handle. Reach for the modules only when you are assembling the pieces yourself.

Internal paths are not public

Operator.Server.*, Operator.Shared.* and Operator.Client.* still resolve, and existing code that requires them keeps working. They are not part of the public API and may move in a minor release. Anything not in the table above is internal: Transport, Delivery, ClientReport, LogChannel, LocalDispatch, ClientContext, Protocol, Serializer, Util and Maid.

Types

Every type a consumer annotates against is exported from the root, so Operator. is the only prefix you need:

Writing a commandWriting an argument typeResults and roles
Builder<A>ArgType<T>Result
CommandAnyArgTypeStatus
ContextTypeBuilder<T>RoleDefinition
ClientContextSuggestionOptionsRoleConfig
ActionSuggestionCacheRoleProvider
ActionTargetRoleSet
GuardFn
Argument, Flag, ArgOptions
AuditLog panelConfig and handleAdapters
AuditRecordLogPanelRecordConfigLogger
AuditQueryLogPanelQueryAuditConfigLogSink
AuditSinkLogPanelPageLogsConfigLogLevel
AuditEntryLogPanelStreamClientConfigSerializerAdapter
AuditSourceActionLogHandle
AuditRegistry, Dispatcher, Roles
luau
local function onDenied(record: Operator.AuditRecord) end
local function myGuard(context: Operator.Context): (boolean, string?) end

Functions

Operator.Start

luau
Operator.Start(config: Config?): Handle

Validates the config, builds the registry, dispatcher, roles, audit and transport, and starts delivering the console. Returns the handle.

Idempotent. A second call logs a warning and returns the same handle. It never double-registers, double-mounts, or re-delivers a bundle.

Config is validated before anything is built. A misspelled key, a wrong-typed value or an unknown pack name raises an error naming the offending key and what was expected.

luau
Operator.Start({
	Commands = script.Parent.Commands,
	DefaultCommands = { "debug", "moderation" },
	Roles = {
		owner = { UserIds = { 1234567 }, Inherits = { "moderator" } },
		moderator = { GroupId = 7654321, MinRank = 200 },
	},
})

Operator.Start({}) is valid and gives a console for the place owner only.

Types

Config

luau
type Config = {
	Commands: Instance?,
	ClientCommands: Instance?,
	Types: Instance?,
	Guards: Instance?,
	DefaultCommands: { string }?,
	Roles: RoleConfig?,
	Audit: AuditConfig?,
	Logs: LogsConfig?,
	Client: ClientConfig?,
	Logger: any?,
	Serializer: any?,
}
FieldDefaultMeaning
Commandsnonean Instance whose descendant ModuleScripts are your commands
ClientCommandsnonean Instance holding your client commands
Typesnoneyour argument types; also delivered to authorised clients
Guardsnonemodules returning a guard function, or { guard, path }
DefaultCommandsnonewhich built-in packs to enable
Rolesplace owner onlyrole definitions, see Roles
Auditenabledsee AuditConfig
Logsenabledsee LogsConfig
ClientUI on, F2see ClientConfig
Loggerwarnings to outputa sink function, or a table with info/warn/error
Serializerpass-throughserialize / deserialize for remote payloads

AuditConfig

luau
type AuditConfig = {
	Enabled: boolean?,
	BufferSize: number?,
	DiscordWebhook: any?,
	DiscordSend: (string | (any) -> boolean)?,
	DiscordFooterIcon: string?,
}

LogsConfig

luau
type LogsConfig = {
	Enabled: boolean?,
	BufferSize: number?,
	Permission: string?,
}
FieldDefaultMeaning
Enabledtrueset false and the log panel reports logging is off
BufferSize200moderation actions kept in memory
Permissionnonea role required to read logs; by default, anyone who can run logs

ClientConfig

luau
type ClientConfig = {
	UI: boolean?,
	Mount: Instance?,
	ActivationKey: EnumItem?,
	Theme: (string | { [string]: Color3 })?,
	HistoryLimit: number?,
	Icon: (string | boolean)?,
}
FieldDefaultMeaning
UItruewhether the built-in console is delivered
Mountnonea ModuleScript of yours to mount instead; implies UI = false
ActivationKeyEnum.KeyCode.F2the toggle key
Theme"signal"signal, operator, iris, or a table of token overrides
HistoryLimit500console lines kept; 0 means uncapped
Iconthe >_ glyphthe topbar icon image, or false for none

Setting both Mount and UI = true is an error rather than a silent choice between them.

Handle

What Start returns.

MemberTypeUse
registryRegistryregister commands or types after startup
dispatcherDispatcherrun commands from server code, add guards
rolesRolesquery or invalidate a player's roles
auditAudit?query the log, add sinks; nil when Audit.Enabled is false
logsActionLog?the log panel store; nil when Logs.Enabled is false
transportTransportdelivery internals; prefer refresh and refreshAll
refresh(player)(Player) -> ()re-evaluate access for one player
refreshAll()() -> ()re-evaluate everyone
stop()() -> ()tear everything down
luau
local operator = Operator.Start({ DefaultCommands = { "debug" } })

operator.registry:registerCommand(myCommand)
operator.refresh(player)

stop() stops the transport, destroys the roles cache and closes the audit sinks, and lets a later Start run again.

Packs

luau
Packs.names(): { string }
Packs.load(registry: Registry, names: { string }, services: Services?): number
luau
type Services = {
	registry: any,
	canRun: ((player: Player, command: any) -> boolean)?,
}

Packs.load returns how many commands it registered. canRun is only used by help, so it can list just the commands that player may run. Naming a pack that does not exist is an error listing the ones that do, and nothing is registered.

Most setups never call this directly. DefaultCommands on Start does it for you.

Exported types

Re-exported so a consumer never needs an internal path:

TypeFrom
Builder<A>, Command, Context, GuardFn, Argument, Flag, ArgOptionsCommand
ArgType<T>, AnyArgType, TypeBuilder<T>, SuggestionOptionsType
Result, StatusDispatcher
LogsConfigthis page
RoleDefinition, RoleConfig, RoleProviderRoles

Internal paths are not public

Operator.Server.* and Operator.Shared.* are reachable but not part of the public surface, and may move in a minor release. The public surface is what require(Operator) returns.

Released under the MIT Licence.