Creating commands
Declare a command the way players type it. WYSIWYG.
Endstone commands are declared as usage strings: you write the command the way a player types it, and Endstone parses that string to build the argument structure and wire up Bedrock's native, client-side tab-completion for you. What you write is what the player sees.
Why a usage string
Most server frameworks make you trade one thing for another:
- Brigadier-style builders (Bukkit/Paper) have you assemble a tree of argument nodes by hand, nesting builder calls inside builder calls. It's powerful, but verbose, and the shape of the command is buried in the code.
- Nukkit-style registration keeps the code flat, but you lose Bedrock's client-side autocomplete - players get no parameter hints as they type.
Endstone takes neither path. You declare a single line - /give <player: target> <item: str> [amount: int] - and Endstone parses it into typed parameters, registers them so the Bedrock client shows native tab-completion and parameter hints, and hands your handler the parsed arguments. No nested builders, no lost autocomplete: the usage string is the source of truth.
How you attach that string to a command differs by language - see your track's setup guide for the exact call.
Parameters
A usage string is the command name followed by zero or more parameters. There are two kinds:
| Kind | Description | Syntax |
|---|---|---|
| Mandatory | Must be provided | <name: type> |
| Optional | Can be omitted | [name: type] |
So /hello [msg: message] declares one optional msg parameter of type message; switch the brackets to /hello <msg: message> to make it mandatory. Parameters read left to right, exactly as the player types them.
Overloads
A command can declare multiple usage strings, and each one is an overload. The client suggests whichever overloads match what the player has typed so far - the same way vanilla commands like /give offer different forms. Endstone merges them into a single autocomplete tree.
Built-in types
Each parameter has a type that drives both validation and the client's suggestions. Endstone ships these out of the box:
| Type | Alias | Description | Example |
|---|---|---|---|
int | An integer | 10 | |
float | A floating-point number | 3.14 | |
bool | A boolean | true | |
target | actor, entity, player | A target selector | @e, @r, PlayerName |
str | string | A string, terminated by a space | Hello |
block_pos | vec3i | A 3D integer position | 1 2 3 |
pos | vec3, vec3f | A 3D float position | 1.0 2.0 3.0 |
message | Everything until the end of the line | Hello World! | |
json | A JSON string | {"key": "value"} | |
block | A block type | wood | |
block_states | Block states | ["wood_type"="birch","stripped_bit"=true] | |
entity_type | An entity type | minecraft:creeper |
Because the message type captures everything up to the end of the line, it must be the last parameter in a usage string - Endstone refuses to register a command that places any parameter after a message.
Enum parameters
To accept one of a fixed set of values, use an enum parameter. There are two ways to write one.
Short form
List the values right inside the parameter brackets, separated by |, with no name or type:
- Mandatory:
<value1|value2|value3> - Optional:
[value1|value2|value3]
For example, /home <add|list|del> lets the player pick add, list, or del, and the client suggests exactly those. Endstone generates the parameter name and the enum type for you, so this is the quickest way to a choice parameter - prefer it for up to about five values.
Full form
The Bedrock client only spells out the inline add|list|del hint while the set is small. Past about five values it stops listing them and shows the parameter as <name: EnumType> instead - and with the short form that name is the one Endstone auto-generated by concatenating the command name and every value (/home <add|list|del> becomes HomeAddListDel), which reads as noise to the player. Past about five values, name the type yourself so the hint stays meaningful: put the values in parentheses, then give the parameter a name and an enum type:
- Mandatory:
(value1|value2|value3)<name: EnumType> - Optional:
(value1|value2|value3)[name: EnumType]
For example, /warp (home|spawn|shop|mine|nether|end)<destination: WarpTarget> declares a destination parameter of type WarpTarget. A named type stays readable and can be reused across commands.
Enum types behave like string-literal unions in TypeScript or Python: a named set of allowed constants. Because the client autocompletes them, players never have to guess the valid values.