On this page
  1. tecs.debug
  2. Getting the commands
  3. Adding one
  4. Results and failures
  5. Command names are a compatibility surface
  6. Module contents
    1. Types
    2. Functions
    3. Values
  7. Types
    1. ArgSpec
    2. Command
    3. Registry
    4. Result
    5. Schema
    6. Subcommand
  8. Functions
    1. bindRenderer
    2. ensure
    3. of
    4. register
  9. Values
    1. SECTIONS

tecs.debug

Debugger commands, and the tools they project to.

A command is declared once. Its argument schema types both a typed command line and a JSON tool call, its action returns one structured result, and the debug server advertises it with an input schema, an output schema and safety hints that were all derived from that single declaration. Nothing about a command is written twice, so the two surfaces cannot disagree.

Getting the commands

tecs.io.mcp does not install them. An application with mcpPort set calls ensure for its own world, so every session that has a debug server has the whole command surface. A headless tool calls ensure itself.

Adding one

local debugapi <const> = require("tecs.debug")

debugapi.ensure(world)
debugapi.register(
    world,
    {
        name = "wave",
        section = "Custom",
        shortHelp = "report the wave the game is on",
        agentHelp = "Reports the current wave number and how many enemies are left in it. "
            .. "Call it to check progress before spawning or despawning anything.",
        readOnly = true,
        outputSchema = {
            ["type"] = "object",
            properties = {
                wave = {["type"] = "integer"},
                remaining = {["type"] = "integer"},
            },
            required = {"wave", "remaining"},
        },
        run = function(_values: {string: any}): debugapi.Result
            return {
                message = "wave " .. tostring(state.wave),
                data = {
                    wave = state.wave, remaining = state.remaining
                },
            }
        end,
    }
)

That registers the tool wave. A command with subcommands registers one tool per verb, named <command>_<verb>, and registers <command> as well when it carries a run of its own.

Results and failures

Result.data is the tool call's structured content, and Result.message travels beside it under the key message. A result with ok = false raises its code and message through the tool call, so an agent reads a failure the way it reads any other tool error rather than by inspecting a field.

Declare outputSchema on anything a game ships. It is what lets an agent know the shape of an answer before it makes the call, and it is what the reference renders.

Command names are a compatibility surface

A tool name is generated from a command name and a verb name, so renaming either renames a tool that an agent already calls. Choose both once.

Requiring this module as debug shadows Lua's own debug library. A module that needs both binds this one as debugapi.

Module contents

Types

Type Kind Description
ArgSpec record Declares one argument.
Command type Declares one command.
Registry type Holds the commands one world has declared.
Result record Reports what one command did.
Schema record Declares a command's arguments.
Subcommand record Declares one verb under a command.

Functions

Function Kind Description
bindRenderer Static Tells the commands which renderer draws this world.
ensure Static Builds the world's command registry, or returns the one it already has.
of Static Returns the registry installed in world.
register Static Registers a game's own command and projects it onto the debug server.

Values

Value Type Description
SECTIONS {string} Read-only. Groups commands in help and in the generated reference, in the order they are presented.

Types

tecs.debug.ArgSpec record

Declares one argument.

record tecs.debug.ArgSpec
    required: boolean
    default: any
    help: string
    forward: string
    synthetic: {string}
    kind: string
    enum: {string}
    min: number
    max: number
    rest: boolean
end

tecs.debug.ArgSpec.required field

Caller-writable. Requires the argument to hold a value once parsing finishes.

tecs.debug.ArgSpec.required: boolean

tecs.debug.ArgSpec.default field

Caller-writable. Supplies the value used when the argument is absent, and infers the value type when kind is omitted. A forwarding argument never receives its default, which only types it.

tecs.debug.ArgSpec.default: any

tecs.debug.ArgSpec.help field

Caller-writable. Describes the argument in generated help and in the MCP tool schema.

tecs.debug.ArgSpec.help: string

tecs.debug.ArgSpec.forward field

Caller-writable. Names the synthetic argument this argument feeds its value into.

tecs.debug.ArgSpec.forward: string

tecs.debug.ArgSpec.synthetic field

Caller-writable. Lists the source argument names this synthetic argument accepts, and its presence marks the argument synthetic, so users neither name it nor see it.

tecs.debug.ArgSpec.synthetic: {string}

tecs.debug.ArgSpec.kind field

Caller-writable. States the value type explicitly, as "number", "boolean", "string", "list", "table" or "rows". Omitting it infers the type from default, so set it for an optional typed argument that has no default, such as a number that leaves the current value unchanged when absent. A "list" is a comma-separated string on the command line and a JSON string array over MCP. A "table" is a brace-balanced Lua expression on the command line and a JSON object over MCP. A "rows" argument is that same expression on the command line and a JSON array of objects over MCP, so an action receives either a string or a table and handles both.

tecs.debug.ArgSpec.kind: string

tecs.debug.ArgSpec.enum field

Caller-writable. Restricts a string argument to these values, and projects to a JSON Schema enum.

tecs.debug.ArgSpec.enum: {string}

tecs.debug.ArgSpec.min field

Caller-writable. Bounds a number argument from below, inclusively.

tecs.debug.ArgSpec.min: number

tecs.debug.ArgSpec.max field

Caller-writable. Bounds a number argument from above, inclusively.

tecs.debug.ArgSpec.max: number

tecs.debug.ArgSpec.rest field

Caller-writable. Makes the slot consume every remaining token as free text, joined with single spaces, where a quoted span keeps its inner spacing. The argument must be the last positional slot and must be string-, table- or rows-typed.

tecs.debug.ArgSpec.rest: boolean

tecs.debug.Command type

Declares one command.

type tecs.debug.Command = debugtypes.Command

tecs.debug.Registry type

Holds the commands one world has declared.

type tecs.debug.Registry = registry.Registry

tecs.debug.Result record

Reports what one command did.

record tecs.debug.Result
    ok: boolean
    code: string
    message: string
    data: {string: any}
end

tecs.debug.Result.ok field

Caller-writable. Reports whether the command did what it was asked. Omitted counts as success. False raises the command's message through the tool call rather than answering with it.

tecs.debug.Result.ok: boolean

tecs.debug.Result.code field

Caller-writable. Names the failure in a word an agent can match on, such as no_match or invalid_ref. Required when ok is false and ignored otherwise.

tecs.debug.Result.code: string

tecs.debug.Result.message field

Caller-writable. Summarizes the outcome for a person in one line. A successful command carries it beside its data under the key message.

tecs.debug.Result.message: string

tecs.debug.Result.data field

Caller-writable. Carries the structured answer, which is what the tool call returns and what outputSchema describes. Omitted answers with the message alone.

tecs.debug.Result.data: {string: any}

tecs.debug.Schema record

Declares a command's arguments.

record tecs.debug.Schema
    args: {string: ArgSpec}
    positional: {string}
end

tecs.debug.Schema.args field

Caller-writable. Maps each argument name to the spec that types it.

tecs.debug.Schema.args: {string: ArgSpec}

tecs.debug.Schema.positional field

Caller-writable. Lists the argument names bound by position, in order. A slot may name a synthetic argument.

tecs.debug.Schema.positional: {string}

tecs.debug.Subcommand record

Declares one verb under a command.

record tecs.debug.Subcommand
    name: string
    aliases: {string}
    shortHelp: string
    agentHelp: string
    schema: cmdargs.Schema
    examples: {string}
    outputSchema: {string: any}
    readOnly: boolean
    destructive: boolean

    run: function({string: any}): Result
end

tecs.debug.Subcommand.name field

Caller-writable. Names the verb. The projected tool is <command>_<name>, so this string is part of an externally typed surface once it ships. Required.

tecs.debug.Subcommand.name: string

tecs.debug.Subcommand.aliases field

Caller-writable. Names other spellings that dispatch to this verb on a typed command line. Aliases are never projected as tools.

tecs.debug.Subcommand.aliases: {string}

tecs.debug.Subcommand.shortHelp field

Caller-writable. Says what the verb does in one line, lowercase and without a trailing period. Required.

tecs.debug.Subcommand.shortHelp: string

tecs.debug.Subcommand.agentHelp field

Caller-writable. Says what an agent needs: when to call this, what it changes, what it answers with, and what to call next. The projected tool description falls back to shortHelp, which is written to fit one line rather than to brief an agent.

tecs.debug.Subcommand.agentHelp: string

tecs.debug.Subcommand.schema field

Caller-writable. Declares the arguments. Omitted means the verb takes none.

tecs.debug.Subcommand.schema: cmdargs.Schema

tecs.debug.Subcommand.examples field

Caller-writable. Shows complete command lines that work, for the generated reference and the usage output.

tecs.debug.Subcommand.examples: {string}

tecs.debug.Subcommand.outputSchema field

Caller-writable. Describes Result.data as a JSON Schema. The projection advertises it as the tool's outputSchema, so an agent knows the shape of the answer before making the call.

tecs.debug.Subcommand.outputSchema: {string: any}

tecs.debug.Subcommand.readOnly field

Caller-writable. Declares that the verb only reads. Omitted derives the answer from the verb: list, info, status and get read.

tecs.debug.Subcommand.readOnly: boolean

tecs.debug.Subcommand.destructive field

Caller-writable. Declares that the verb destroys something a caller cannot get back. Omitted derives the answer from the verb.

tecs.debug.Subcommand.destructive: boolean

tecs.debug.Subcommand.run Static

Caller-writable. Runs the verb. Required.

function tecs.debug.Subcommand.run({string: any}): Result
Arguments
Name Type Description
#1 {string : any}
Returns
Type Description
Result

Functions

tecs.debug.bindRenderer Static

Tells the commands which renderer draws this world.

Commands that read or draw through the renderer answer with a failure until something calls this, since a world alone does not name one.

function tecs.debug.bindRenderer(
    world: types.World, renderer: Renderer
)

Arguments

Name Type Description
world types.World The caller supplies the world the renderer draws.
renderer Renderer The caller supplies the renderer, or nil to unbind.

Returns

None.

tecs.debug.ensure Static

Builds the world's command registry, or returns the one it already has.

Registering the engine's own commands projects each of them onto the debug server, so a session that calls this once has the whole surface. Calling it again answers with the same registry and registers nothing further.

function tecs.debug.ensure(world: types.World): registry.Registry

Arguments

Name Type Description
world types.World The caller supplies the world the commands read and write.

Returns

Type Description
registry.Registry The world's registry.

tecs.debug.of Static

Returns the registry installed in world.

function tecs.debug.of(world: types.World): registry.Registry

Arguments

Name Type Description
world types.World The caller supplies a world with or without a registry.

Returns

Type Description
registry.Registry The world's registry, or nil before ensure has run.

tecs.debug.register Static

Registers a game's own command and projects it onto the debug server.

Raises when the world has no registry, and raises on a malformed declaration: a command is written once and called forever, so a mistake in one belongs at the call that made it.

function tecs.debug.register(
    world: types.World, command: debugtypes.Command
)

Arguments

Name Type Description
world types.World The caller supplies a world ensure has already run on.
command debugtypes.Command The caller supplies a complete declaration.

Returns

None.

Values

tecs.debug.SECTIONS variable

Read-only. Groups commands in help and in the generated reference, in the order they are presented. A command that names no section groups as "Custom".

tecs.debug.SECTIONS: {string}