Little Roblox typed command console for in-game admin commands, debug commands, and typed utilities.
Install · How It Works · Using It · Commands · API
Konsole is a typed compact command bar for Roblox games.
Konsole, gives you an in-game terminal for commands like kick, bring, tp, ranks, and your own custom commands. It handles suggestions, typed arguments, command history, result tables, client/server dispatch, ranks, and small UI details like two command panes and argument chips.
Put Konsole.rbxm in ReplicatedStorage/Packages/Konsole, then require it.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Konsole = require(ReplicatedStorage.Packages.Konsole)For roblox-ts/npm:
npm install @kyrorblx/konsoleimport Konsole = require("@kyrorblx/konsole");For Wally:
[dependencies]
Konsole = "kyrorblx/konsole@0.1.4"Konsole is shared, but the UI is client-side. The server hosts command execution. The client shows the command bar and forwards server commands through Konsole's remote bridge.
Konsole has three main pieces:
Kommand: stores command definitions, schemas, aliases, suggestions, and argument metadata.Dispatch: parses text, checks rank/cooldown, converts arguments, and runs the right client or server implementation.Render: creates the client UI, suggestions, history, result output, and the command input.
The usual setup is:
- Server calls
Konsole.host(). - Client calls
Konsole.show()orKonsole.toggle(). - Built-in commands register automatically.
- Server command definitions replicate to clients so suggestions and argument hints work.
- When a command has
server = "someServerName", the client forwards the text to the server.
Inline run commands can run where they are registered. Server commands should usually use server = "name" with Konsole.implement("name", callback) or pass implementations into Konsole.host(...).
Server setup:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Konsole = require(ReplicatedStorage.Packages.Konsole)
Konsole.host()Client setup:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Konsole = require(ReplicatedStorage.Packages.Konsole)
Konsole.show()By default, Konsole opens with T. You can change that:
Konsole.setActivationKeys({ Enum.KeyCode.Semicolon })You can also toggle manually:
Konsole.toggle()
Konsole.show()
Konsole.hide()
Konsole.focus()Konsole ships with a few small commands:
cmds: lists registered commands, rank, usage, and descriptionclear/cls: clears the active Konsole chat paneranks: lists known ranksbring: brings target players to youtp: teleports you to a target playerkick: kicks a playerban: bans players from the current serverunban: unbans a user ID from the current serverkill: kills a player
The ban command is server-local. It blocks players for the lifetime of that server, not permanently across all servers. If you want persistent bans, store ban state in a DataStore and implement your own banServer / unbanServer.
A command definition looks like this:
Konsole.define({
name = "setscore",
rank = 50,
aliases = { "score" },
description = "Sets the score.",
server = "setScoreServer",
args = {
{
name = "home",
type = "number",
required = true,
},
{
name = "away",
type = "number",
required = true,
},
},
})Then bind the server implementation:
Konsole.implement("setScoreServer", function(context, homeScore, awayScore)
print(context.entity, homeScore, awayScore)
return context.reply(`score set to {homeScore}-{awayScore}`)
end)Or pass implementations straight into host:
Konsole.host({
setScoreServer = function(context, homeScore, awayScore)
return context.reply(`score set to {homeScore}-{awayScore}`)
end,
})Commands are normalized to lowercase internally. Aliases are normalized too.
If a command has run and no server, it runs locally.
Konsole.define({
name = "pinglocal",
rank = 0,
description = "Runs on this client.",
run = function(context)
return context.reply("pong")
end,
})Client commands are useful for UI toggles, local debug views, camera tools, graphics settings, or anything that only affects one player.
If a command has server, Konsole forwards it to the server when typed by a client.
Konsole.define({
name = "announce",
rank = 50,
description = "Sends a server announcement.",
server = "announceServer",
args = {
{
name = "message",
type = "string",
required = true,
},
},
})
Konsole.implement("announceServer", function(context, message)
print(message)
return context.reply("announced")
end)The server is authoritative. Rank checks happen on the server before server commands run.
Arguments tell Konsole how to parse and display command inputs.
args = {
{
name = "target",
type = "player",
required = true,
suggestions = { "me" },
},
{
name = "reason",
type = "string",
required = false,
default = "No reason provided.",
},
}Built-in types:
string: plain textnumber: converted withtonumberboolean: acceptstrue,false,yes,no,on,off,1,0player: one playerplayers: one or more players
Player shortcuts:
me: the command callerallor*: every playerothers: every player except the caller
For player, the token must resolve to exactly one player. For players, it can resolve to many.
Konsole also uses argument metadata for the UI. When you type a command with args, it shows argument chips. Fixed-token args like number and boolean jump to the next chip when you press space. Bad argument types turn red while typing.
Suggestions come from command names, aliases, and argument providers.
For a static list:
{
name = "mode",
type = "string",
suggestions = { "easy", "normal", "hard" },
}For player arguments, Konsole automatically suggests player names plus me, all, and others.
Use Tab to accept a suggestion. Use Up and Down to move through suggestions. Use Left and Right to move between structured argument chips when your cursor is at the edge of a chip.
Commands can return:
nil: success- a string/number/etc: success message
- a result table
context.reply(...)context.err(...)
Basic success:
return context.reply("done")Basic error:
return context.err("no-target", "No target player.")Table result:
return {
ok = true,
kind = "table",
title = "Players",
message = "current server",
width = "wide",
columns = { "Name", "UserId" },
rows = {
{ Name = "kio", UserId = "123" },
},
}There are also helpers under Konsole.Result:
return Konsole.Result.ok("saved")
return Konsole.Result.err("bad-input", "That value is invalid.")
return Konsole.Result.table("Scores", { "Team", "Score" }, rows)
return Konsole.Result.status("State", {
{ Field = "Round", Value = "2" },
{ Field = "Alive", Value = "7" },
})Successful results show with a checkmark. Errors show with an x.
Every command gets a context.run(...) helper.
Konsole.define({
name = "resetmatch",
rank = 100,
server = "resetMatchServer",
})
Konsole.implement("resetMatchServer", function(context)
context.run("setscore 0 0")
context.run("bring all")
return context.reply("match reset")
end)context.run runs through the normal dispatch path, so ranks, arguments, cooldowns, and server implementations still apply.
Commands can have a built-in cooldown:
Konsole.define({
name = "daily",
rank = 0,
description = "Claims a daily reward.",
server = "dailyServer",
cooldown = 60,
})The cooldown is in seconds. If a player tries to run the command early, Konsole returns a cooldown error with the remaining time.
Cooldowns are tracked per command and per caller in memory. They reset when the server restarts.
Every command has a rank. If no rank is provided, it is rank 0.
Built-in rank names include:
player:0- higher built-in names can be inspected with
ranks
Set a rank manually:
Konsole.setRank(player.UserId, 100)Read a rank:
local rank = Konsole.getRank(player)Bind your own rank resolver:
Konsole.bindRanks(function(entity)
if entity and entity.UserId == game.CreatorId then
return 100
end
return nil
end)Return nil to fall back to the built-in rank store.
Konsole supports a second chat pane.
The second pane is useful when you want to compare outputs, keep one command result visible, or run commands without losing context in the first pane.
clear only clears the pane you typed it in. The public Konsole.clear() method clears the whole active client.
Konsole saves history, scroll position, and restored width when the UI is closed and reopened.
Konsole is intentionally small.
It opens as a compact pill near the bottom of the screen. When output appears, it expands into history. When command output is wider than the current panel, the panel grows to fit visible content. Command output slides upward when appended. Suggestions and argument hints animate in and out.
The command input uses structured chips for arguments so you can see what each value means while typing.
Useful keys:
T: default toggleTab: accept suggestionUp/Down: move through suggestionsLeft/Right: move between command/argument fields at the edgesEnter: submitEscape: close
Pass config overrides into Konsole.create(...).
local client = Konsole.create({
input = {
activationKeys = { Enum.KeyCode.Semicolon },
forceclose = true, -- outside click fully closes instead of only releasing input focus
},
panel = {
width = 280,
outputWidth = 380,
historyMaxHeight = 420,
},
color = {
panel = Color3.fromRGB(0, 0, 0),
inputText = Color3.fromRGB(255, 255, 255),
},
})Config groups:
fontpanellayoutmotioninputcolortransparencycommands
Common panel options:
width: base input widthoutputWidth: base width once history existsmaxWidth: maximum widthheight: collapsed input heighthistoryMaxHeight: max first-pane history heightstackHistoryMaxHeight: max second-pane history heightsuggestionHeightmaxSuggestionsbottomInsetdisplayOrder
Common motion options:
expandSmoothTimeopenSmoothTimeoutputSmoothTimetextFadeTimetextSlideOffsetitemSlideSmoothTimecollapseSmoothTimehintFadeTimehintSlideTime
Common color options:
panelinputTextpromptTextsuggPanelsuggTextsuccessRicherrorRichwarnRichmutedText
The direct Konsole.show() style uses one shared default client.
For more control:
local client = Konsole.create({
input = {
activationKeys = { Enum.KeyCode.F2 },
},
})
client:bindRun(function(text)
return Konsole.Dispatch.execute(text)
end)
client:setSuggestions(Konsole.Kommand.suggestions())
client:setSchemas(Konsole.Kommand.schemas())
client:show()Most games can use the default client. Create a client when you want a different config, custom runner, or isolated UI behavior.
Konsole.create(options?)
Konsole.host(serverImplementations?)
Konsole.define(definition)
Konsole.implement(name, callback)
Konsole.run(text)
Konsole.setRank(userId, rank)
Konsole.getRank(entity)
Konsole.bindRanks(resolver?)
Konsole.show()
Konsole.hide()
Konsole.toggle()
Konsole.focus()
Konsole.clear()
Konsole.destroy()
Konsole.setActivationKeys(keys)
Konsole.setEnabled(enabled)
Konsole.setActivationUnlocksMouse(enabled)
Konsole.setMouseUnlockDriver(getFn, setFn)
Konsole.getCursorTarget()Client methods returned by Konsole.create(...):
client:show()
client:hide()
client:toggle()
client:focus()
client:clear()
client:destroy()
client:bindRun(callback)
client:setSuggestions(list)
client:setSchemas(map)
client:setActivationKeys(keys)
client:setEnabled(enabled)
client:setActivationUnlocksMouse(enabled)
client:setMouseUnlockDriver(getFn, setFn)
client:getCursorTarget()Command definition shape:
type Definition = {
name: string,
rank: number | string?,
aliases: { string }?,
args: { Argument }?,
description: string?,
cooldown: number?,
server: string?,
run: ((context, ...any) -> any)?,
}Argument shape:
type Argument = {
name: string?,
type: string?,
default: any,
required: boolean?,
suggestions: ({ string } | string)?,
}Context shape:
type Context = {
entity: Player?,
kommand: Command,
text: string,
dispatch: Dispatch,
ranks: Ranks,
run: (text: any) -> any,
reply: (message: any?) -> Outcome,
err: (code: any?, message: any?) -> Outcome,
}
