Fabric commands
Complete reference for Brigadier command system in Fabric Minecraft 1.20.1 — command tree construction, argument types, tab-completion suggestions, permission levels, server/client command registration, and CommandRegistrationCallback. Use this skill whenever the user asks about adding a command, Brigadier, CommandRegistrationCallback, argument types (IntegerArgumentType, StringArgumentType, EntityArgumentType, etc.), command permissions, op level, tab completion, or ServerCommandSource. Triggers on: "command", "brigadier", "CommandRegistrationCallback", "argument type", "tab complete", "command permission", "op level", "/mycommand", "ServerCommandSource", "CommandContext", "literal", "executes", "requires", "suggests". Part of the fabric-mc-modding skill family.From its SKILL.md
npx -y skills add PSB1234/Fabric-Minecraft-Skill-1.20.1 --skill fabric-commandsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
9.9 KB, ~2.0k tokens by cl100k_base, as published. Nobody here has run it
Fabric Commands — 1.20.1 Reference
Registration
All commands are registered via CommandRegistrationCallback in onInitialize():
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// environment = INTEGRATED (single-player), DEDICATED (server), or ALL
if (environment.dedicated) {
// only on dedicated server
}
MyCommands.register(dispatcher, registryAccess);
});
Basic Command Structure
dispatcher.register(
CommandManager.literal("hello") // command name
.requires(src -> src.hasPermissionLevel(0)) // who can run it (0 = everyone)
.executes(ctx -> {
ctx.getSource().sendFeedback(
() -> Text.literal("Hello, world!"), false); // false = don't log to ops
return 1; // return 1 = success, 0 = failure
})
);
Arguments
Integer
.then(CommandManager.argument("count", IntegerArgumentType.integer(1, 64))
.executes(ctx -> {
int count = IntegerArgumentType.getInteger(ctx, "count");
return 1;
})
)
String
CommandManager.argument("name", StringArgumentType.word()) // single word
CommandManager.argument("msg", StringArgumentType.string()) // quoted or single word
CommandManager.argument("text", StringArgumentType.greedyString()) // rest of input
Boolean, Float, Double, Long
BoolArgumentType.bool() BoolArgumentType.getBool(ctx, "flag")
FloatArgumentType.floatArg() FloatArgumentType.getFloat(ctx, "value")
DoubleArgumentType.doubleArg() DoubleArgumentType.getDouble(ctx, "value")
LongArgumentType.longArg() LongArgumentType.getLong(ctx, "value")
Minecraft-specific Arguments
// Player (online players only)
EntityArgumentType.player()
EntityArgumentType.players() // supports @a, @r, etc.
EntityArgumentType.entity() // any entity
EntityArgumentType.entities()
// Get value:
ServerPlayerEntity player = EntityArgumentType.getPlayer(ctx, "player");
Collection<ServerPlayerEntity> players = EntityArgumentType.getPlayers(ctx, "players");
// Block position
BlockPosArgumentType.blockPos()
BlockPos pos = BlockPosArgumentType.getBlockPos(ctx, "pos");
// Block state
BlockStateArgumentType.blockState(registryAccess)
BlockStateArgument state = BlockStateArgumentType.getBlockState(ctx, "block");
// Item stack
ItemStackArgumentType.itemStack(registryAccess)
ItemStackArgument item = ItemStackArgumentType.getItemStackArgument(ctx, "item");
// Identifier / ResourceLocation
IdentifierArgumentType.identifier()
Identifier id = IdentifierArgumentType.getIdentifier(ctx, "id");
// Vec3 / Vec2 position
Vec3ArgumentType.vec3()
Vec3d vec = Vec3ArgumentType.getVec3(ctx, "pos");
// Rotation
RotationArgumentType.rotation()
// NBT
NbtCompoundArgumentType.nbtCompound()
NbtTagArgumentType.nbtTag()
Multi-Level Command Tree
dispatcher.register(
CommandManager.literal("mymod")
.then(CommandManager.literal("give")
.then(CommandManager.argument("player", EntityArgumentType.player())
.then(CommandManager.argument("count", IntegerArgumentType.integer(1, 64))
.executes(ctx -> executeGive(ctx, 1)) // optional count
)
.executes(ctx -> executeGive(ctx, 1)) // no count → default 1
)
)
.then(CommandManager.literal("reload")
.requires(src -> src.hasPermissionLevel(4)) // op only
.executes(ctx -> executeReload(ctx))
)
.then(CommandManager.literal("status")
.executes(ctx -> executeStatus(ctx))
)
);
Permission Levels
.requires(source -> source.hasPermissionLevel(level))
| Level | Who |
|---|---|
| 0 | All players |
| 1 | Bypass spawn protection |
| 2 | Cheats / /gamemode — typical mod commands |
| 3 | /kick, /ban |
| 4 | /stop, /op — server admin |
Check if source is a player (not console):
.requires(source -> source.getEntity() instanceof PlayerEntity)
Sending Feedback
ServerCommandSource src = ctx.getSource();
// To the command sender only
src.sendFeedback(() -> Text.literal("Done!"), false);
// To the sender and log to ops (true = broadcast to ops)
src.sendFeedback(() -> Text.literal("Reloaded."), true);
// Error message (shown in red)
src.sendError(Text.literal("Something went wrong."));
// Throw a command exception (shown as error, stops execution)
throw new SimpleCommandExceptionType(Text.literal("Invalid arg")).create();
Custom Tab-Completion Suggestions
CommandManager.argument("color", StringArgumentType.word())
.suggests((ctx, builder) -> {
// Static list
Stream.of("red", "green", "blue")
.filter(s -> s.startsWith(builder.getRemaining()))
.forEach(builder::suggest);
return builder.buildFuture();
})
Or using SuggestionProvider:
private static final SuggestionProvider<ServerCommandSource> MY_SUGGESTIONS =
(ctx, builder) -> {
// Dynamic suggestions from server state
ctx.getSource().getServer().getPlayerManager()
.getPlayerList().stream()
.map(p -> p.getName().getString())
.filter(n -> n.startsWith(builder.getRemaining()))
.forEach(builder::suggest);
return builder.buildFuture();
};
CommandManager.argument("name", StringArgumentType.word())
.suggests(MY_SUGGESTIONS)
Accessing the Server / World from a Command
ctx.getSource().getServer() // MinecraftServer
ctx.getSource().getWorld() // ServerWorld (where the command was run)
ctx.getSource().getPlayer() // ServerPlayerEntity (throws if console)
ctx.getSource().getPlayerOrThrow() // same but with exception type
ctx.getSource().getPosition() // Vec3d position of source
ctx.getSource().getEntity() // Entity or null (null if console)
Client-Side Commands (Single Player)
Register using ClientCommandRegistrationCallback from Fabric API (client-only):
// In onInitializeClient():
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
dispatcher.register(
ClientCommandManager.literal("client_cmd")
.executes(ctx -> {
MinecraftClient client = MinecraftClient.getInstance();
// client-side only logic
return 1;
})
);
});
Command Aliases
Register the same handler under multiple names:
LiteralArgumentBuilder<ServerCommandSource> cmd =
CommandManager.literal("mymod").executes(ctx -> { return 1; });
dispatcher.register(cmd);
dispatcher.register(CommandManager.literal("mm") // alias
.redirect(dispatcher.getRoot().getChild("mymod")));
Full Example: /mymod tp <player> <pos>
dispatcher.register(
CommandManager.literal("mymod")
.then(CommandManager.literal("tp")
.requires(src -> src.hasPermissionLevel(2))
.then(CommandManager.argument("target", EntityArgumentType.player())
.then(CommandManager.argument("pos", BlockPosArgumentType.blockPos())
.executes(ctx -> {
ServerPlayerEntity target = EntityArgumentType.getPlayer(ctx, "target");
BlockPos pos = BlockPosArgumentType.getBlockPos(ctx, "pos");
target.teleport(ctx.getSource().getWorld(),
pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5,
target.getYaw(), target.getPitch());
ctx.getSource().sendFeedback(
() -> Text.literal("Teleported " + target.getName().getString()), true);
return 1;
})
)
)
)
);
Common Mistakes
- Argument order matters — Brigadier parses greedily; put
greedyStringlast. getPlayer()throws on console — usegetEntity()+ instanceof check if the command can be run by console.- Permission check on wrong node —
.requires()applies to that node and all children. Put it on theliteralroot. - Suggestions not filtering — always filter with
builder.getRemaining()prefix check. - Command not registered —
CommandRegistrationCallback.EVENT.register(...)must be insideonInitialize().
Further Reading
- Brigadier docs: https://github.com/Mojang/brigadier
- Fabric commands guide: https://docs.fabricmc.net/develop/commands/basics
- Argument types reference: https://docs.fabricmc.net/develop/commands/arguments
References
| File | When to load |
|---|---|
references/argument-types.md | Complete Brigadier argument type table (all vanilla types, retrieval methods, custom types, suggestions, dynamic tab-complete, CommandSyntaxException) |
Related Skills
fabric-mc-modding— project setupfabric-config— exposing config via commandsfabric-events— CommandRegistrationCallback is a Fabric event
What ships with it: 1 file
7.0 KB alongside SKILL.md
references/
- argument-types.md7.0 KB