Consuming a @client command at runtime
The @client tag turns a CommandRunner command into a runtime-deliverable module. The script gets relocated (or mirrored) into ReplicatedStorage.CommandRunnerRuntime.<name> so any LocalScript can require it.
This page walks the full pattern end-to-end.
1. Tag the command
In the command's source:
return {
Tags = { "@client" },
Arguments = {
Speed = { Type = "number", Default = 16, Min = 1 },
},
Run = function(props, arguments)
local char = props.FirstSelected
if char and char:IsA("Model") then
local hum = char:FindFirstChildOfClass("Humanoid")
if hum then
hum.WalkSpeed = arguments.Speed
end
end
end,
}
Save the command. CommandRunner's reconcile sweep relocates the script to:
ReplicatedStorage
└── CommandRunnerRuntime
└── SetWalkSpeed ← the script now lives here
└── Types
If you also tagged it @server, the canonical stays in ServerStorage.CommandRunnerScripts and a clone is delivered to the same ReplicatedStorage location. See tags & runtime delivery for the routing table.
2. Build a props stand-in
The plugin's props table is constructed inside the plugin context. At runtime, that context doesn't exist. There's no Studio Selection, no plugin global, no ChangeHistoryService recording.
You need to construct a stand-in that satisfies whatever fields your specific command uses. There's no canonical "make me a runtime props" helper, different commands need different fields.
A minimal stand-in for the example above:
local function makeProps(args, target)
return {
Arguments = args,
Selected = { target },
FirstSelected = target,
-- The ones we don't use can be no-ops or omitted entirely
-- as long as the command never touches them. Keep what's used.
SendNotification = function(_self, msg)
print("[CommandRunner runtime]", msg)
end,
SetSelection = function(_self, _list) end,
FocusView = function(_self, _objects, _padding) end,
}
end
3. Require and invoke
From a LocalScript:
-- StarterPlayer/StarterPlayerScripts/MyConsumer (LocalScript)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local runtime = ReplicatedStorage:WaitForChild("CommandRunnerRuntime")
local SetWalkSpeed = require(runtime:WaitForChild("SetWalkSpeed"))
local function makeProps(args, target)
return {
Arguments = args,
Selected = { target },
FirstSelected = target,
SendNotification = function(_, msg) print("[runtime]", msg) end,
}
end
Players.LocalPlayer.CharacterAdded:Connect(function(char)
SetWalkSpeed.Run(makeProps({ Speed = 24 }, char))
end)
That's the full pattern.
What about per-argument Run callbacks?
Per-argument Run callbacks (the kind that fire when the user types into a string field or clicks a button) are part of the plugin UI, not the runtime. They never fire at runtime. There's no UI to drive them. Don't put load-bearing logic in them; they're for plugin-time interactivity only.
What about OnExecuted?
Same, OnExecuted is fired by the plugin after Run returns. At runtime, you control the call. If you want the post-step, just call it yourself:
local result = SetWalkSpeed.Run(props)
if SetWalkSpeed.OnExecuted then
SetWalkSpeed.OnExecuted(props, props.Arguments, result)
end
What about AutoRecordChanges, Debug, Tags, DisableExecuteButton?
All plugin-only. At runtime, ignore them, they're metadata for the plugin, not flags your runtime code should consult.
Caveat: edits during play test
@client-only commands survive play-test edits cleanly. The canonical IS the ReplicatedStorage script, so editing it during play test and choosing "Save edits" persists.
@client + @server (dual-tagged) commands are clobbered on widget toggle. The plugin re-clones the ServerStorage canonical to the ReplicatedStorage mirror and overwrites your in-play edits. Edit the ServerStorage canonical instead; the mirror updates automatically.
This matters when you're iterating on a runtime-delivered command during a play-test session. If you find yourself editing the ReplicatedStorage copy and losing changes, that's the dual-tag mirror behavior. Drop @server from the tag list, or edit the ServerStorage copy.