Skip to main content
Glama

Playtest control

playtest
Destructive

Control live game-testing sessions in Roblox Studio: start, stop, add players, wait for conditions, install controllers, hotpatch scripts, and push changes without losing runtime state.

Instructions

Control the live playtest and the in-engine runtime. Keep ONE playtest alive; a restart costs ~3 s and loses play-DM state.

  • start {mode: play|run|multiplayer, players}: waits for the runtimes → {running, mode, players, peers, started_ms}. multiplayer spawns a server DM plus players (1-8, default 2) client Studios (client:1..N; slow → job handle). no_peer: turn on "Load User Plugins In Run Modes" / install the plugin (test still running: Stop in Studio).

  • stop → {stopped_ms}. status → {running, mode, players, peers, elapsed_s, controllers}. add_players {count} (multiplayer).

  • run_until {dm, predicate | predicate_file, timeout_ms ≤ 120000, interval_ms, args}: Luau predicate evaluated in-engine each Heartbeat until truthy → {result: true|'timeout', value, elapsed_ms, checks}.

  • install {dm, name, code | code_file, persist}: code returns { load = function(ctx) … end, unload = function() … end }. ctx: S, assert(name,cond,detail), milestone, emit, log, onHeartbeat, onEvent, every, after, player, character(), input.*, moveTo (straight line), pathTo (pathfinding), state(), storage. Same name replaces; asserts/milestones → /events. persist: kept by the bridge, re-installed whenever that DM appears in a later playtest.

  • uninstall {dm, name} (drops the persisted entry). list → controllers on all peers + persisted.

  • hotpatch {dm, path, source | source_file, restart}: writes a script Source in the live DM and restarts it, playtest kept (ModuleScript: re-require needed).

  • push {paths, dm, parent, replace}: copies edit-DM instances into the live DM at their own paths (or under parent) → {dm, paths, count, bytes, replaced, skipped?, replicated}; replace (default true) removes a same-name, same-class sibling first (never Terrain, the camera, a character); ephemeral, not undoable. dm: 'server' | 'client' | 'client:N'. *_file = absolute path the bridge reads (never heredoc Luau). Slow actions return {job_id, status:'running'} after wait_ms; use job.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dmNoTarget DataModel: 'edit' (default) | 'server' | 'client' (lowest-numbered) | 'client:N'
argsNoAvailable to the program as ARGS
codeNoinstall: Luau returning { load = function(ctx) … end, unload = function() … end }
modeNostart: default play
nameNoinstall/uninstall: controller name
pathNohotpatch: script path, e.g. ServerScriptService.Main
countNoadd_players: clients to add to the running multiplayer test, 1-8 (default 1)
pathsNopush: edit-DM instance paths to serialize into the live DM
actionYes
parentNopush: parent path in the target DM (default: each instance lands at its own edit-DM path)
sourceNohotpatch: full new source
persistNoinstall: keep it in the bridge and re-install whenever that DM appears in a later playtest
playersNostart (multiplayer): client Studio processes to spawn, 1-8 (default 2)
replaceNopush: destroy a same-named sibling at the target parent first (default true); false keeps both
restartNohotpatch: toggle Disabled to restart the script (default true)
sessionNoStudio session GUID or unique prefix (default: the active hub; required for writes when several Studios are connected)
wait_msNoWait this long for completion before returning a {job_id,status:"running"} handle (default 25000)
code_fileNoinstall: instead of code: absolute path of a file holding the Luau (read by the bridge; UTF-8, BOM ok, ≤ 4 MB). No shell/JSON escaping touches it
predicateNorun_until: Luau expression or chunk; truthy ends the wait
timeout_msNorun_until/push: default 30000, max 120000
interval_msNorun_until: 0 = every Heartbeat (default)
source_fileNohotpatch: instead of source: absolute path of a file holding the Luau (read by the bridge; UTF-8, BOM ok, ≤ 4 MB). No shell/JSON escaping touches it
predicate_fileNorun_until: instead of predicate: absolute path of a file holding the Luau (read by the bridge; UTF-8, BOM ok, ≤ 4 MB). No shell/JSON escaping touches it

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.1.0

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true, and the description elaborates on this: 'push ... ephemeral, not undoable' and 'replace (default true) removes a same-name, same-class sibling first (never Terrain, the camera, a character)'. It also discloses the restart cost (~3 s), state loss ('loses play-DM state'), persistence semantics ('persist: kept by the bridge, re-installed whenever that DM appears in a later playtest'), and async behavior ('Slow actions return {job_id, status:"running"} after wait_ms; use `job`'). This goes well beyond the annotations, which only say destructiveHint=true. The only minor gap is that it doesn't explicitly state that start/stop are also destructive in the sense of ending a running playtest, but the 'Keep ONE playtest alive' warning covers that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured: it opens with the most important constraint ('Keep ONE playtest alive'), then groups actions with their parameters in a compact notation. Every sentence carries information: the restart cost, the no_peer workaround, the predicate semantics, the persist behavior, the push replacement rules, and the async job handle note. It loses one point because the density makes it somewhat hard to parse at a glance – the action-parameter groupings are packed into a single paragraph without line breaks, and an agent might need to re-read to extract the exact parameter list for a given action. Still, it is far from verbose and front-loads the critical warning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 23 parameters, no output schema, and a complex multi-action surface, the description covers the essential behavioral context: what each action does, which parameters apply, what the return values look like (e.g., {running, mode, players, peers, started_ms}), and the async job handle pattern. It also covers edge cases like no_peer, persist, and replace. It doesn't fully document every return shape for every action (e.g., status returns {running, mode, players, peers, elapsed_s, controllers} but stop only shows {stopped_ms}), and it doesn't explain the `args` parameter's role in run_until beyond 'available to the program as ARGS'. Given the tool's complexity, these are minor gaps; the description is remarkably complete for a 23-parameter tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 96%, so the schema already documents most parameters. The description adds meaning by grouping parameters with their actions (e.g., 'start {mode: play|run|multiplayer, players}', 'run_until {dm, predicate | predicate_file, timeout_ms ≤ 120000, interval_ms, args}'), which clarifies which parameters apply to which action. It also adds constraints not fully in the schema, such as 'players (1-8, default 2)' and 'timeout_ms ≤ 120000'. The description doesn't repeat every schema description, but it adds the action-parameter mapping that the flat schema lacks. A 4 is appropriate because the schema does most of the work, but the description adds meaningful grouping and defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb and resource: 'Control the live playtest and the in-engine runtime.' It then enumerates each action (start, stop, status, run_until, install, uninstall, list, hotpatch, push) with its specific purpose, which distinguishes it from sibling tools like observe, look, run, input, events, skills, job, and cloud. The scope is unambiguous: this is the tool for managing playtests and the live DM runtime, not for observing or running code in other contexts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage guidance: 'Keep ONE playtest alive; a restart costs ~3 s and loses play-DM state.' It also gives conditional guidance for multiplayer ('no_peer: turn on "Load User Plugins In Run Modes" / install the plugin'), for run_until ('Luau predicate evaluated in-engine each Heartbeat until truthy'), and for push ('replace (default true) removes a same-name, same-class sibling first'). It names alternatives implicitly by listing all actions and their parameters, and the sibling list shows this is the only playtest control tool. The description also warns about slow actions returning job handles, which tells the agent when to expect async behavior.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools