# 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 ```teal local debugapi = 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 `_`, and registers `` 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`](/modules/debug/#tecs.debug.ArgSpec) | record | Declares one argument. | | [`Command`](/modules/debug/#tecs.debug.Command) | type | Declares one command. | | [`Registry`](/modules/debug/#tecs.debug.Registry) | type | Holds the commands one world has declared. | | [`Result`](/modules/debug/#tecs.debug.Result) | record | Reports what one command did. | | [`Schema`](/modules/debug/#tecs.debug.Schema) | record | Declares a command's arguments. | | [`Subcommand`](/modules/debug/#tecs.debug.Subcommand) | record | Declares one verb under a command. | ### Functions | Function | Kind | Description | | --- | --- | --- | | [`bindRenderer`](/modules/debug/#tecs.debug.bindRenderer) | Static | Tells the commands which renderer draws this world. | | [`ensure`](/modules/debug/#tecs.debug.ensure) | Static | Builds the world's command registry, or returns the one it already has. | | [`of`](/modules/debug/#tecs.debug.of) | Static | Returns the registry installed in world. | | [`register`](/modules/debug/#tecs.debug.register) | Static | Registers a game's own command and projects it onto the debug server. | ### Values | Value | Type | Description | | --- | --- | --- | | [`SECTIONS`](/modules/debug/#tecs.debug.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. ```teal 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. ```teal 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. ```teal tecs.debug.ArgSpec.default: any ``` #### tecs.debug.ArgSpec.help field Caller-writable. Describes the argument in generated help and in the MCP tool schema. ```teal tecs.debug.ArgSpec.help: string ``` #### tecs.debug.ArgSpec.forward field Caller-writable. Names the synthetic argument this argument feeds its value into. ```teal 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. ```teal 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. ```teal 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`. ```teal tecs.debug.ArgSpec.enum: {string} ``` #### tecs.debug.ArgSpec.min field Caller-writable. Bounds a number argument from below, inclusively. ```teal tecs.debug.ArgSpec.min: number ``` #### tecs.debug.ArgSpec.max field Caller-writable. Bounds a number argument from above, inclusively. ```teal 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. ```teal tecs.debug.ArgSpec.rest: boolean ``` ### tecs.debug.Command type Declares one command. ```teal type tecs.debug.Command = debugtypes.Command ``` ### tecs.debug.Registry type Holds the commands one world has declared. ```teal type tecs.debug.Registry = registry.Registry ``` ### tecs.debug.Result record Reports what one command did. ```teal 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. ```teal 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. ```teal 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`. ```teal 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. ```teal tecs.debug.Result.data: {string: any} ``` ### tecs.debug.Schema record Declares a command's arguments. ```teal 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. ```teal 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. ```teal tecs.debug.Schema.positional: {string} ``` ### tecs.debug.Subcommand record Declares one verb under a command. ```teal 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 `_`, so this string is part of an externally typed surface once it ships. Required. ```teal 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. ```teal 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. ```teal 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. ```teal tecs.debug.Subcommand.agentHelp: string ``` #### tecs.debug.Subcommand.schema field Caller-writable. Declares the arguments. Omitted means the verb takes none. ```teal 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. ```teal 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. ```teal 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. ```teal 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. ```teal tecs.debug.Subcommand.destructive: boolean ``` #### tecs.debug.Subcommand.run Static Caller-writable. Runs the verb. Required. ```teal 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. ```teal function tecs.debug.bindRenderer( world: types.World, renderer: Renderer ) ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `world` | [`types.World`](/modules/ecs/#tecs.World) | The caller supplies the world the renderer draws. | | `renderer` | [`Renderer`](/modules/gfx/#tecs.gfx.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. ```teal function tecs.debug.ensure(world: types.World): registry.Registry ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `world` | [`types.World`](/modules/ecs/#tecs.World) | The caller supplies the world the commands read and write. | #### Returns | Type | Description | | --- | --- | | [`registry.Registry`](/modules/debug/#tecs.debug.Registry) | The world's registry. | ### tecs.debug.of Static Returns the registry installed in `world`. ```teal function tecs.debug.of(world: types.World): registry.Registry ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `world` | [`types.World`](/modules/ecs/#tecs.World) | The caller supplies a world with or without a registry. | #### Returns | Type | Description | | --- | --- | | [`registry.Registry`](/modules/debug/#tecs.debug.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. ```teal function tecs.debug.register( world: types.World, command: debugtypes.Command ) ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `world` | [`types.World`](/modules/ecs/#tecs.World) | The caller supplies a world `ensure` has already run on. | | `command` | [`debugtypes.Command`](/modules/debug/#tecs.debug.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"`. ```teal tecs.debug.SECTIONS: {string} ```