Reference this skill when registering proxy-level commands on Velocity. Velocity provides SimpleCommand, RawCommand, and BrigadierCommand interfaces — each suited to different use cases.
When to Use This Skill
Adding /proxy-command that players can run on the proxy directly
Creating admin commands that work regardless of which backend server the player is on
Implementing commands with tab completion at the proxy level
API Quick Reference
Class / Method
Purpose
Notes
CommandManager#register(CommandMeta, Command)
Register a command
Get manager via server.getCommandManager()
CommandManager#metaBuilder(String)
Build command metadata
Set aliases and plugin reference
SimpleCommand
Simple string-args command interface
Easiest to implement
RawCommand
Gets the full raw argument string
For commands needing custom parsing
BrigadierCommand
Native Brigadier tree
Full argument types and client-side validation
SimpleCommand.Invocation
Wraps CommandSource + String[] args
CommandSource
The executor (Player or ConsoleCommandSource)
CommandManager#hasCommand(String)
Check if a command is registered
Code Pattern
package com.yourorg.proxyplugin.commands;
import com.velocitypowered.api.command.CommandMeta;
import com.velocitypowered.api.command.SimpleCommand;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import java.util.List;
import java.util.concurrent.CompletableFuture;
// SimpleCommand: the most common command type
public class HubCommand implements SimpleCommand {
private final ProxyServer server;
public HubCommand(ProxyServer server) {
this.server = server;
}
@Override
public void execute(Invocation invocation) {
if (!(invocation.source() instanceof Player player)) {
invocation.source().sendMessage(
Component.text("This command is only for players.").color(NamedTextColor.RED)
);
return;
}
server.getServer("lobby").ifPresentOrElse(
lobby -> player.createConnectionRequest(lobby).fireAndForget(),
() -> player.sendMessage(
Component.text("Lobby is offline.").color(NamedTextColor.RED)
)
);
}
@Override
public boolean hasPermission(Invocation invocation) {
return invocation.source().hasPermission("network.hub");
}
@Override
public CompletableFuture<List<String>> suggestAsync(Invocation invocation) {
// No tab completion needed for /hub
return CompletableFuture.completedFuture(List.of());
}
}
Register in main class:
CommandMeta meta = server.getCommandManager()
.metaBuilder("hub")
.aliases("lobby", "l")
.plugin(this)
.build();
server.getCommandManager().register(meta, new HubCommand(server));
Common Pitfalls
Not checking if source is Player before casting: Console can execute commands. Always instanceof check before casting invocation.source() to Player.
Blocking in execute(): execute() runs on Velocity's command thread. Synchronous database calls will block command processing for all players. Use CompletableFuture.supplyAsync() and schedule UI updates properly.
Registering without a plugin reference: Always call .plugin(this) on the CommandMeta builder. Without it, the command won't be cleaned up on plugin unload.
Version Notes
Velocity 3.3: SimpleCommand, RawCommand, BrigadierCommand all stable.
hasPermission(Invocation) is checked before execute() and before tab completion. Returning false hides the command from the player.
Related Skills
velocity-commands.md — SimpleCommand, RawCommand, BrigadierCommand deep dive
1---2name: commands-33description: Commands Skill — Velocity4---5# Commands Skill — Velocity67## Purpose8Reference this skill when registering proxy-level commands on Velocity. Velocity provides `SimpleCommand`, `RawCommand`, and `BrigadierCommand` interfaces — each suited to different use cases.910## When to Use This Skill11- Adding `/proxy-command` that players can run on the proxy directly12- Creating admin commands that work regardless of which backend server the player is on13- Implementing commands with tab completion at the proxy level1415## API Quick Reference1617| Class / Method | Purpose | Notes |18|---------------|---------|-------|19| `CommandManager#register(CommandMeta, Command)` | Register a command | Get manager via `server.getCommandManager()` |20| `CommandManager#metaBuilder(String)` | Build command metadata | Set aliases and plugin reference |21| `SimpleCommand` | Simple string-args command interface | Easiest to implement |22| `RawCommand` | Gets the full raw argument string | For commands needing custom parsing |23| `BrigadierCommand` | Native Brigadier tree | Full argument types and client-side validation |24| `SimpleCommand.Invocation` | Wraps `CommandSource` + `String[] args` | |25| `CommandSource` | The executor (`Player` or `ConsoleCommandSource`) | |26| `CommandManager#hasCommand(String)` | Check if a command is registered | |2728## Code Pattern2930```java31package com.yourorg.proxyplugin.commands;3233import com.velocitypowered.api.command.CommandMeta;34import com.velocitypowered.api.command.SimpleCommand;35import com.velocitypowered.api.proxy.Player;36import com.velocitypowered.api.proxy.ProxyServer;37import net.kyori.adventure.text.Component;38import net.kyori.adventure.text.format.NamedTextColor;3940import java.util.List;41import java.util.concurrent.CompletableFuture;4243// SimpleCommand: the most common command type44public class HubCommand implements SimpleCommand {4546 private final ProxyServer server;4748 public HubCommand(ProxyServer server) {49 this.server = server;50 }5152 @Override53 public void execute(Invocation invocation) {54 if (!(invocation.source() instanceof Player player)) {55 invocation.source().sendMessage(56 Component.text("This command is only for players.").color(NamedTextColor.RED)57 );58 return;59 }6061 server.getServer("lobby").ifPresentOrElse(62 lobby -> player.createConnectionRequest(lobby).fireAndForget(),63 () -> player.sendMessage(64 Component.text("Lobby is offline.").color(NamedTextColor.RED)65 )66 );67 }6869 @Override70 public boolean hasPermission(Invocation invocation) {71 return invocation.source().hasPermission("network.hub");72 }7374 @Override75 public CompletableFuture<List<String>> suggestAsync(Invocation invocation) {76 // No tab completion needed for /hub77 return CompletableFuture.completedFuture(List.of());78 }79}80```8182**Register in main class:**83```java84CommandMeta meta = server.getCommandManager()85 .metaBuilder("hub")86 .aliases("lobby", "l")87 .plugin(this)88 .build();8990server.getCommandManager().register(meta, new HubCommand(server));91```9293## Common Pitfalls9495- **Not checking if source is `Player` before casting**: Console can execute commands. Always instanceof check before casting `invocation.source()` to `Player`.9697- **Blocking in `execute()`**: `execute()` runs on Velocity's command thread. Synchronous database calls will block command processing for all players. Use `CompletableFuture.supplyAsync()` and schedule UI updates properly.9899- **Registering without a plugin reference**: Always call `.plugin(this)` on the `CommandMeta` builder. Without it, the command won't be cleaned up on plugin unload.100101## Version Notes102103- **Velocity 3.3**: `SimpleCommand`, `RawCommand`, `BrigadierCommand` all stable.104- `hasPermission(Invocation)` is checked before `execute()` and before tab completion. Returning `false` hides the command from the player.105106## Related Skills107108- [velocity-commands.md](velocity-commands.md) — SimpleCommand, RawCommand, BrigadierCommand deep dive109- [../events/SKILL.md](../events/SKILL.md) — Velocity event system110- [../OVERVIEW.md](../OVERVIEW.md) — Velocity platform setup
Run npx skillmds@latest add mrpippi/commands-3 in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Commands Skill — Velocity It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
MrPippi (@mrpippi) published this skill. Their other Agent Skills are listed on their SkillMD profile.