# Changelog

What changed in each release, written for people using the server rather than for people reading the diff.

## 1.0.0

### Added

- New panel design, Threadline. A line you type opens a thread, and every call and reply it causes hangs under it. Each call row shows a small latency bar. The activity band is one row, 18px shorter, and shows a live timer for the running call. The header uses icon buttons, and a row of theme dots replaces the theme drawer on the right edge.
- Electro theme, which replaces Sonar: a charged core with lightning arcs that strike faster as the session works. A saved Sonar choice switches to Electro.
- 18 more agents for `chat on`: Kimi Code, Cline, Kilo Code, Auggie, Qoder, Continue, Kiro, Mistral Vibe, Grok CLI, OpenHands, Hermes, OpenClaw, Warp Oz, Rovo Dev, Forge, pi, Letta Code and Trae Agent. That makes 31. The new adapters follow each vendor's documentation and haven't all been run yet, so please report any that misbehave.
- `terrain op="materials"` lists, sets and resets custom terrain material slots (Custom Terrain Materials, launched Oct 2026).
- `audio op="speech"` turns text into voice-line audio assets (Studio beta, Oct 2026).
- `universe op="logs"` shows server stack frames as script paths and line numbers that `script_read` can open, when Roblox provides them.

### Changed

- History bars slide in and grow in every theme, instead of jumping.
- The activity band stops redrawing while the panel is closed, and redraws at 15fps once the session has gone quiet.
- Dependencies updated (MCP SDK 1.32.2), with 4 security fixes in transitive dependencies.

### Fixed

- Long log lines no longer run past the panel's right edge, under the scrollbar.

## 0.9.5

### Added

- `viewport op="uisnap"`: snapshot a UI's layout, colours, fonts, text, images and modifiers, then call again with `compareTo` to see what was added, removed or changed, property by property. Works on the playtest client too.
- `playtest` warns when Workspace is large enough to make Studio 743+ freeze for a minute or more on Stop, names the heaviest children and AnimSaves, and waits the freeze out instead of reporting a failed stop.

### Changed

- Playtest screenshots now show BillboardGuis and ProximityPrompts, which Roblox's capture API leaves out. They are redrawn for the one frame of the shot; the caption says how many.
- `script_edit` requires `revision` for line-range and whole-source edits (`NEEDS_REVISION`), and for every live edit. find/replace still works without it.
- `script_create` returns each new script's `rev`, so a line edit can follow without a read.
- `debug op="collisions"` ranks and filters by impact speed along the contact normal (`maxImpact`). Sliding contact no longer counts as a hard hit; total speed is still `maxSpeed`.
- Dependencies updated (zod 4.6.7).

### Fixed

- `viewport op="ui"` no longer walks every pair of elements in large interfaces; the overlap check compares siblings only, within its cap.

## 0.9.2

### Added

- `debug op="collisions"`: what a part (or every part in a model) hit during a playtest, with contact point, normal, impact speed and area, hardest first. Reads the server, or the player's own simulation with `target="client"`.

### Changed

- Dependencies updated.

## 0.9.1

### Added

- Stop button beside the prompt while an agent runs. The `stop` command still works but is hidden from the menu.
- Three new themes: Sonar, Ember and Pendulum, replacing Void, Nebula and Blueprint.
- The console log is one row per entry: errors and warnings get a coloured bar, rows light up under the pointer, and a "latest" button appears when you scroll up.

### Changed

- Theme picker redone: larger previews, a clear marker for the active theme, hover highlight.
- Dim text is brighter in every theme, and the Aurora, Phosphor, Observatory and Orbit animations are refreshed.
- The log no longer re-renders every row on each new line.
- Dependencies updated (MCP SDK 1.32.1).

### Fixed

- The server stays up after a stray error, and always releases the port on shutdown.
- A plugin that disconnects during connection no longer leaves a dead session behind.
- Sorting same-named siblings on a client no longer evicts handles you already hold.
- Error messages name same-named siblings by index (`Twin[2]`), not just `Twin`.
- Internal review notes are no longer shipped in the npm package.

## 0.9.0

### Added

- `tree`, `inspect`, `find`, `viewport ui/raycast` and `performance snapshot` take `target="client"` and optional `player`, so they read the running player's view, UI and render counters.
- `viewport op="pick"`: a point on the screen (normalized `x` / `y`) to the instance under it, using the editor or actual-client camera.
- `handles=true` on discovery returns references usable in place of paths. They survive renames and moves, distinguish same-named instances, and refuse stale or wrong-context use.
- Clipped successful `execute_luau` results return a `resultId`: page tables or strings, read nested values and select row fields without running the code again.
- `debug op="watch"`: property, attribute and direct-child changes over a short window, in Studio or the actual client, with initial values, old/new values, times and explicit drop counts.

### Changed

- Playtest `screenshot path=` crops to the selected client's instance, including UI that exists only on that client.
- Studio and client Luau replies say which context, VM and permission identity ran the code.

### Fixed

- `Font="Code"` is converted as `Enum.Font` instead of being mistaken for a `FontFace` value.
- Same-named client siblings keep a stable path order when Roblox refuses `GetDebugId`.
- A failed `viewport raycast` reports the error instead of saying nothing was hit.
- ScreenGui crops and UI bounds account for the GUI inset with either `IgnoreGuiInset` setting.
- Clipped Luau previews keep Unicode characters intact, and oversized printed lines say how much output was omitted.

## 0.8.7

### Added
- `sync` writes a `sourcemap.json`, so luau-lsp resolves requires between synced scripts.
- `universe op="analytics"`: the game's metrics over a date range (players, revenue, retention, crashes, frame rate), optionally split by platform, country and more.
- `universe op="events"`, `"schedule"`, `"cancel"`: list, create, reschedule and cancel the game's scheduled events.
- `script_edit target="live"` takes `revision` (the `rev` `script_read target="live"` now prints) and refuses to overwrite a script that was published since.
- Long calls tell the client they are still working, so clients with a short tool timeout (such as Codex) stop giving up on `generate`, live Luau, uploads and playtests that are fine.

### Changed
- Dependencies updated (MCP SDK 1.32).
- Open Cloud calls repeat a rate-limited request (and a failed read) after the wait Roblox asks for, up to twice.
- Live Luau runs, uploads and place operations are noticed as finished sooner: checks start at 0.4s, not 2s.

### Fixed
- `script_edit`: line edits starting on the same line (an insert and a replace) now apply in a fixed order; before, one order could hit the wrong lines.
- `script_read target="live"` could not reach scripts past the first 100 in a folder, and a cut listing did not say so.
- `execute_luau target="live"` returned only the first page of the script's output.
- `sync watch` missed changes to folders whose names contain a dot.

## 0.8.6

### Added
- `sync`: work on scripts as files. Pull, push, two-way sync, or live `watch` between Studio and a folder (Rojo-style layout). Renames keep the same script; edits on both sides become conflicts, never overwrites.
- `sync export` / `build`: UI and other instance trees as editable `.build.json` files, rebuilt in one undo step with their scripts kept.
- `script_grep`: several `patterns` in one pass, plus `files` and `counts` modes.
- `find properties=[...]`, `console mode="drain"`, and `screenshot player=`.

### Fixed
- `script_edit` never overwrites text typed while it writes.
- A timed-out request no longer runs late in Studio.
- Paging could skip or repeat rows; `Part[2]` could change meaning between calls.
- `debug clear` only removes the MCP's breakpoints.
- Colours read and written back no longer drift darker.

## 0.8.5

Withdrawn; replaced by 0.8.6.

## 0.8.4

### Changed
- Typing a sentence in the panel no longer starts an agent by default. Run `chat on` to turn it on, `chat off` to turn it off again; the choice is remembered. Commands are unaffected.

## 0.8.3

### Added
- `inspect` says why a requested property came back missing: a typo (with a suggestion), unset, or unreadable.
- `find` and `tree` point out a `className` that is not a Roblox class.

### Changed
- Screenshots encode faster (up to 8x on flat UI screens, same picture).
- `studio_status` answers faster: its two reads now run at once.
- Property and class checks stay current in long sessions: the Roblox API list refreshes daily, not only at startup.
- Dependencies updated (MCP SDK 1.31); CI also tests Node 24.

### Fixed
- `execute_luau target="client"` failed with "Requested module experienced an error while loading" (broken since 0.8.2).
- Zero-length inputs are refused instead of answering "nothing there": `viewport raycast`, `collision cast` and `overlap`, and `terrain` fills or regions with an empty side.
- `viewport focus` (zero `from`) and `viewport camera` (`position` equal to `lookAt`) no longer give the camera a broken position.
- `collision remove` on a group that does not exist said it was removed.
- `debug set` on a line past the end of the script blamed the Debugger beta setting.
- A call that timed out could still run in Studio later; it is now dropped.
- Calls to a Studio that has just closed fail cleanly instead of escaping error handling.
- The bridge refuses requests whose `Host` is not loopback, closing a DNS-rebinding hole.
- A server taking over the bridge port while shutting down could stay running.
- `assets publish` said to pass `publish: true`; it is `confirm: true`.
- Panel agent output no longer hides calls to other MCP servers, and its temp files are removed on exit.
- The panel no longer saves its size while the plugin is unloading.

## 0.8.2

### Added
- `universe op="servers"` / `op="logs"`: live servers and their error/warning logs.
- `universe op="products"` / `op="sell"`: list and create developer products and game passes.
- `playtest op="addPlayers"`: add players to a running multiplayer test.
- `geometry` supports `Tunable` collision fidelity.
- `console` and `execute_luau` show structured-log context (`LogService:Info(msg, {…})`).

### Changed
- Smaller replies: `inspect` children, `collision overlap` as a table, one-line `performance scene` categories, rounded numbers.
- `inspect` standard detail drops noise (`Rotation`, surfaces, zero velocities).

### Fixed
- `device network`: packet loss was applied 100x too small; `stop` no longer leaves memory emulated at 0 MB.
- `datastore set` (Studio and live) no longer wipes a key's user ids and metadata.
- A bad position/vector is an error instead of being silently ignored.
- `assets insert` keeps the model's rotation when moved.
- `collision assign` refuses a group that does not exist.
- `character op="path"` starts from the character when `from` is omitted.
- `audio graph` no longer warns about a missing listener that Roblox provides.
- `playtest stop` no longer reports a leftover player.
- `terrain stats` no longer reports a wrong limit.
- Open Cloud calls can no longer hang, and rate limits say how long to wait.

## 0.8.0

### Added
- `screenshot` can zoom: `path` (a GUI, part or model) or `rect`, at full resolution.
- Colors can be written as hex, e.g. `"#FF8800"`.

### Changed
- `script_edit` and `script_create` are up to 50x faster.
- Sharper screenshots (better downscaling).
- Smaller tool replies (compact JSON), so agents use fewer tokens.
- Faster first `create` / `modify` / `inspect`.
- Removed the `animation` tool.
- Dependencies updated.

### Fixed
- `create` works with Gemini / Vertex AI, and nested children are validated again.
- `script_edit` no longer removes the script's final newline.
- Instances named like `x[1]` can be found by path.
- A 12-number `CFrame` gets the right rotation.
- Client logs survive a player respawn.
- Property checking recovers after a network error.
- Missing arguments are reported as errors.
- `api` and `inspect` no longer list deprecated or unusable members.
- The server can no longer crash on odd output from a panel agent.
## 0.7.8

### Added
- `console target="client"` reads continuously captured playtest client prints, warnings and errors, with player selection in multiplayer and stack/source details when available.
- `console` returns `nextCursor`; passing it as `since` reads only newer matching output and reports any lines lost to buffer eviction or the response limit. Cursors are tied to one session and player.
- `playtest op="play"` and `op="multiplayer"` return the connected playtest server `studioId` and available player names directly. If the server has not connected within the wait, the start still succeeds and explains how to find it later.

## 0.7.7

### Fixed
- Studio's 30-minute reconnect no longer drops calls in flight or the chosen Studio.
- Place name stays correct after a reconnect.
- Calls no longer hang when a result can't be sent as JSON.
- Long-poll no longer loses commands.
- Big scripts reach Studio much faster.
- Stopping an agent from the panel can't crash the server.
- Small fixes: network timeouts, safer credentials save, clearer errors.

## 0.7.6

### Fixed
- Fix #4: decimal `input` hold/after values now produce integer millisecond deadlines, retaining the existing timeout padding. Bridge boundaries also normalize and validate deadlines for other tools.
- Peer/proxy calls no longer report local timeout or AbortSignal setup errors as `OWNER_GONE`.
- Clarify that client execution connections/hooks do not persist after the temporary relay call returns.

## 0.7.5

### Fixed
- `input` no longer fails on key sequences longer than 20 seconds.

## 0.7.4

- Extend `execute_luau` with `target="client"` and optional `player`, running in the actual playtest client VM with bounded structured returns and captured output.
- Share temporary relay setup, player selection, acknowledgement deadlines and cleanup with `input`.
- Support client GUI paths on click/text input steps; resolve current geometry and focus TextBoxes before typing.
- Add passive `debug op="remotes"` captures for a selected playtest player: both RemoteEvent directions, counts/rates and bounded argument-shape samples. No RemoteFunction interception.
- Add persistent panel `playtests [on|off]` controls: default ON grants permission without overriding project/user instructions; OFF stops detected tests and blocks MCP starts while preserving state/stop, edit-mode execution and inspection, and manual Studio Play.
- Preserve existing Studio/live execution and coordinate input. No new top-level tools.

## 0.7.2

### Fixed
- Big scripts no longer time out in `script_create` or `script_edit`. Studio splits large messages, and the plugin was dropping them.
- `script_create` handles scripts of 200,000+ characters, which Roblox refused before.
- `script_read` cuts long scripts on a whole line and says which `startLine` to read next.

### Changed
- New `npm run test:live` checks big scripts against a real Studio.
- Tests no longer need a fixed free port.
- Dependencies updated.

## 0.7.1

### Fixed
- The panel stays where you dock it, instead of floating in the middle every time a place is opened.
- The panel no longer opens over the game during a playtest. Studio will not dock it there, so it stays shut; the toolbar button still opens it.
- `input` no longer dies on a key Roblox reserves (Escape, Tab, F9). It names the key and runs the rest of the steps.

## 0.7.0

### Fixed
- A crashed Studio no longer blocks every tool with `AMBIGUOUS_STUDIO`.
- The panel's `use` command now works for tool calls.
- Panel prompts with `&`, `"` or `%` no longer break on Windows.
- `geometry mesh` and `mirror` work without a `path`.
- `inf` and `nan` values read correctly.
- `execute_luau` keeps `nil` returns and flags errors.
- `tree` shows top-level items first.
- `script_edit` returns the new `rev`.

### Changed
- Dependencies updated.

## 0.6.9

### Fixed
- **The MCP server now reports the package version instead of a stale hardcoded `0.3.5`.** Future version bumps are picked up automatically from the package metadata.

## 0.6.8

### Fixed
- **Live calls can no longer hit the wrong game.** `cloud place` is sticky and Studio's place is not, so opening a different experience left every live call pointing at the old one — reading another game's player data, restarting its servers, with a plausible success message and no error. They now refuse when the target is not the place open in Studio. Pass `universeId` or `placeId` to override on purpose.

## 0.6.7

### Added
- **`collision` cast and overlap** — find what is physically there: a door clipping a wall, a blocked sightline.
- **`geometry mirror`** — flip things across a plane. Studio cannot do this.
- **`assets insert stripScripts`** — take a free model's geometry without its code.
- **`audio`** — build and read the modern audio graph, and find the broken wire that makes it silent.
- **Open Cloud**, via one key set with `cloud` in the panel: upload files, read and write the **live** game's player data, run scripts on the published place, restart servers, ban players.

### Fixed
- **Hinges and rigs work in one `create` call.** References to siblings resolve now; they needed two calls before.
- **`NumberRange`, `ColorSequence`, `NumberSequence` and `Rect` can be written**, not just read. Recolouring a ParticleEmitter or UIGradient works.
- **Asset properties can be set at all** — `SurfaceAppearance.ColorMap`, `AudioPlayer.AudioContent` and every other `ContentId`/`Content`.
- **A missing instance names the path** instead of blaming the type.

## 0.6.5

### Added
- **Animations**: read, build and preview them on a rig without leaving edit mode.
- **Data stores**: read and write saved player data, including old versions of a key.
- **UI audit** finds interface faults a phone shows and a monitor hides.
- **Tag list**, **asset audit**, **audio search**, **network simulation**, **pathfinding in playtests**.

### Fixed
- **Instance properties can be set at all** — `Part0`, `PrimaryPart`, `Adornee` and friends. Rigs and welds no longer need `execute_luau`.
- **`FontFace` works**, so UI can be built.
- **Built animations actually move the rig.** Poses were attached in the wrong order and the engine ignored them silently.
- **`animation stop` restores the rig** instead of leaving it bent.
- **Clicks land where you aim them.** The coordinate advice was backwards.
- **`performance audit` can no longer hang Studio.**
- **Centre of mass is the real one**, not always zero.
- **Collision groups list in words**, not bitmasks.
- **The Studio panel names every call.** 26 of 72 said nothing useful, and writes were labelled as reads.
- **Panel times are honest**: a median instead of an average one slow call could ruin, and `<1ms` instead of `0ms`.

## 0.6.1

### Added
- **`autoopen off`** stops the panel putting itself on screen — not when a place opens, not when you press Play. The toolbar button still opens it. `autoopen on` puts it back; `autoopen` says which it is.

## 0.6.0

- README: the dsh section now prints the plugin row itself, and names the file to paste it into. It pointed at a path inside `node_modules`, which is not there when the server is run through `npx`.

## 0.5.8

### Added
- **A command menu above the prompt.** Click the bar and every command is listed with what it does. Keep typing to filter, scroll for the rest, click one to fill it in.

### Fixed
- **The prompt no longer keeps the cursor after a command runs**, so the reply is not covered and clicking the bar always reopens the menu.
- **Using DeepSeek Harness?** `config/dsh.cordis.yml` now ships inside the npm package, so `dsh --patch` can point at it without cloning the repo.

## 0.5.6

### Fixed
- **CI was red since 0.5.0: a bridge reply kept its socket alive.** One-shot JSON responses now close the connection, so a client's `fetch` pool can't reuse a socket to a server that has since closed and fail with "other side closed".

## 0.5.5

### Fixed
- **A raw `TypeError: fetch failed` during a bridge handover.** When the server holding the port exits mid-reply, the borrower now reports `OWNER_GONE` and says to retry, instead of surfacing a Node socket error. Only the network call was guarded; reading the reply was not.

## 0.5.4

- README cut to half its length: install, tools, panel, done.

## 0.5.3

### Fixed
- **Every tool call was logged twice** — once by Studio with a readable name and a duration, once by the agent. The agent's copy is dropped for `rbx-studio` calls; tools Studio never sees still appear.
- **opencode's naming of our tools is recognised**, so a call reads `studio_status` rather than `rbx-studio_studio_status`.

## 0.5.2

### Added
- **Six more coding agents** the panel can run: Amp, Qwen Code, Factory Droid, goose, GitHub Copilot CLI and Aider. Thirteen in total, each built against its documented headless output rather than a guess.

### Fixed
- **Output nobody can parse is now shown instead of dropped.** Every adapter discarded lines it did not recognise, which is exactly how opencode managed to print a blank run.

## 0.5.1

### Fixed
- **opencode printed nothing.** Its adapter was built on event names opencode does not emit, so every line was discarded and a prompt logged a blank run. Rebuilt from a recorded run.
- **Codex never resumed a conversation**, and follow-up turns were refused outright: the session id was read from the wrong field, and global flags were placed after the `resume` subcommand, which codex rejects.
- **Crush was launched with a flag it rejects.** It takes `run <prompt>`, not `-p`.
- **Gemini and Cursor now stream properly** instead of being treated as plain-text unknowns.
- **The panel asks which agent should answer** when more than one is connected to the Studio, instead of picking whichever sorts first. Remembered after you answer once.

## 0.5.0

A command line in the console panel, and terrain.

### Added
- **A prompt row at the bottom of the panel.** Type a command, or type a sentence. History on the arrows, Tab completion, and it shows what you have selected.
- **Commands:** `help`, `doctor`, `status`, `version`, `place`, `clients`, `studios`, `use`, `theme`, `visuals`, `log`, `clear`, `copy`, `port`, `reconnect`, `agent`, `stop`.
- **Anything that is not a command goes to a coding agent.** The bridge starts whichever one is on PATH — Claude Code, Codex, opencode, Gemini, Cursor, dsh — and its work streams into the log. `stop` cancels it.
- **DeepSeek Harness (dsh) support**, both ways: this server registers as a dsh plugin, and dsh can run your prompts.
- **`terrain`** — `fill` (block, ball, cylinder, wedge, one undo step), `replace` a material in place, `clear`, `stats`. Fill with `Air` to carve caves.
- The activity cell keeps moving while an agent thinks.

### Fixed
- **Script edits could be lost silently.** A write to a just-opened editor tab reported success and was then overwritten by the editor finishing its load. Writes are read back now.
- **Screenshots said nothing when nothing was rendered** — a script tab in front of the 3D view returned a flat rectangle, reported as an ordinary picture.
- **An agent started from the panel is no longer counted as a stranger.** It logged "2 MCP clients connected" on every prompt and lingered after `stop`.
- **Panel prompts say they come from Studio**, so "create a script" no longer sends the agent to the filesystem.
- Log lines wrap under themselves, render markdown, and no longer chop a message to fit the note beside it.
- `copy` writes the log as comments. `stop` kills the agent's whole process tree.

### Changed
- Dependencies bumped; `hono` to 4.13.7, clearing a moderate advisory reached through the MCP SDK.

## 0.4.6

Same as 0.4.5, republished so the npm package matches. README rewritten and brought up to date.

## 0.4.5

3D generation, one tool for every mesh operation, and a panel that opens.

### Added
- **`generate`** - 3D models from a text prompt, through Roblox's Cube model. `Body1` for props, `Car5` for a body and four named wheels a script can drive, or your own part names.
- **`geometry`** now covers every mesh operation: the boolean ops plus `fragment`, `segment` (cut a mesh into parts you name) and `sweep` (the volume a part moves through, and what it would hit on the way).
- **`script_edit` can refuse a stale write.** `script_read` prints a `rev`; pass it back and an edit is refused if the script changed since you read it.
- **`npx rbx-studio-mcp doctor`** - a health check with a fix on every line.
- **The clients badge says who is connected**, by name, with process id and uptime. Hover it, or click for the full list.
- **`assets op="bake"`** converts editable mesh and image data to static content, and **`viewport op="textbounds"`** answers whether text fits its label.

### Fixed
- **The panel stopped opening on its own.** A close is now only remembered when the toolbar button did it, so Studio closing a place can no longer be recorded as you closing the panel. Closing with the X is not remembered, so the panel comes back next launch.
- Running `doctor` appeared as a second connected client for 90 seconds. Reading the roster no longer joins it.
- Segmenting a mesh lost its scale and its texture.
- Collision groups go through `Workspace` instead of the deprecated `PhysicsService`.

### Known limits
- Generated meshes are edit-mode only. Their content reads as empty inside a playtest, and `bake` cannot convert it.

## 0.4.2

### Fixed
- The panel stopped opening on its own. Studio disables the widget while closing a place, and that was recorded as the user having closed it. A close now has to last a second before it counts.
- The plugin sometimes did not load at all. The installer overwrote the file in place while Studio was reading it. It now writes beside it and renames over.

### Changed
- Dependency and GitHub Action versions bumped.

## 0.4.1

### Fixed
- The console showed DISCONNECTED while the agent was working. Reconnect backoff never reset after a good connection, so it waited the full 30s between attempts that were succeeding.
- Closing the server that held the port killed the connection for every other one. Another now takes the port over in a few seconds.

## 0.4.0

The connecting wave and the call history share one grid.

### Fixed
- **The wave overlapped the bars already in the trace.** It sat on its own spacing, so on a reconnect its columns landed between and behind the history at a different pitch. Both now use the same slots: history fills from the right, the wave fills only what is left of it.
- **The history stood still while the wave rolled past it.** The bars are now lifted by the same swell, against the height each one has left, so the strip moves as one surface. Hover still reports the recorded time.

## 0.3.9

The console shows what it is doing while it connects.

### Added
- **The activity trace waves while the plugin is connecting.** It used to sit as a bare baseline, which looks the same as a panel that has died.
- **A flourish when a session lands.** A bright front runs across the trace on connect, once per real connection.
- **The clear button switches the log off like a CRT.** The picture collapses to a bright line, flashes, and blinks out.

All three are drawn by whichever preset is active, so each of the eight has its own.

## 0.3.8

Screenshots say when they came back black.

### Changed
- **A screenshot that is entirely black now says so.** It used to look like a valid picture of a dark scene, so an agent would read it and carry on. Usually it means Studio was not rendering — minimised, covered, or on another virtual desktop.
- **Playtest screenshots wait for a rendered frame** before capturing, instead of shooting on the frame the capture script lands.

## 0.3.7

The console log survives a playtest in both directions.

### Fixed
- **The console emptied when a playtest started and again when it stopped.** Studio loads the plugin separately into the editor and into the playtest, each with its own blank log, and shows you whichever view is current — so the session you were watching appeared to be wiped, then the playtest's work vanished from the editor's log on Stop. The rows you had are now carried into the playtest, and calls made during it are carried back out.

## 0.3.6

A rolled-back edit can no longer be redone, typing into a text box actually types, and the console keeps working while you playtest.

### Fixed
- **A rolled-back batch could be brought back with one Ctrl+Y.** `modify` said "nothing was changed" and meant it, but Studio filed the cancelled edit on the redo stack — so a single redo re-applied the half-finished state the rollback existed to prevent.
- **`input` reported typing text that never arrived.** A synthetic click does not give a TextBox focus, and `text` steps go to the focused box, so they did nothing and still returned success. The box under the click is focused now, and a step with nowhere to type says so.
- **`device` blamed the device id during a playtest.** A valid id came back as `NO_SUCH_DEVICE` with advice to check the spelling. Studio simply refuses device changes while a test runs; it now says that, and points at the edit session, which works.
- **The console came back on the saved theme's shape but the default's colours.** The palette was read before the saved preset was restored.
- **The Void preset strobed after every command.** Its orbit multiplied elapsed time by a speed that changes, so a change in speed jumped the disc instead of accelerating it — worse the longer Studio had been open. Aurora had the same fault when a session went quiet.
- **The activity cell snapped and stalled instead of bouncing.** A reply's impulse drove it into its own size limit while still carrying speed, and long frames dropped motion rather than catching up.
- **The panel vanished on every playtest.** Studio loads the plugin again into the playtest and its widget starts closed; it now opens the way you left it.

### Changed
- **The console keeps working during a playtest.** The view Studio shows you is the client half, which Roblox forbids from making HTTP requests, so it sat on a standby notice while the agent worked. It now mirrors the playtest's server session — the log fills and the activity strip reacts live. One `RemoteEvent` carries it, in the running game only, one-way, never saved with the place.
- `input` no longer suggests reusing a measured click offset: it holds under portrait emulation and with no device, but not in landscape.

### Known issues
- **A playtest opens the panel at the wrong size.** Studio does not restore plugin widget geometry in play mode — `HostWidgetWasRestored` reads false there — and a widget's size cannot be set from code. Studio → Settings → Test → "Load All Built-In Plugins in Test Mode" works around it. [Reported since 2023.](https://devforum.roblox.com/t/widgets-reset-when-playtesting-and-opening-a-new-studio/2946725)

## 0.3.5

Search results stop reshuffling between calls, values written as text land as the right type, and the console panel gets eight colour presets.

### Fixed
- **`find` and `tree` returned rows in a different order every call.** The engine does not order `GetDescendants` stably, and pages are cut by position — so page two came from a different ordering than page one, skipping some instances and repeating others with counts that still looked right. Results are now sorted.
- **A bad cursor silently returned the first page.** Indistinguishable from a genuine first page, so paging could never reach the end. It is an error now.
- **Numbers in a composite value were misread.** `Position: "1e3, 0, .5"` became `1, 3, 0` and reported success. Scalars and composites now read numbers the same way.
- **Anything but exactly `"true"` became `false`.** `Anchored: "True"` silently set the opposite. Near misses are accepted; anything else is refused instead of guessed.
- **Attributes could not hold a Vector3, Color3 or UDim2.** The same text that types a property was stored as a string. Pass `{ type, value }` for any non-scalar.
- **`find` disagreed with `modify` about enum notation.** `"Plastic"` and `"FALSE"` matched nothing while `modify` accepted both. Matching is case-insensitive and takes a bare enum name.
- **A self-referencing table printed as three nested copies.** `execute_luau` now says `<circular reference>`.
- **A backwards line range blamed the file.** `script_read` now names the argument.
- **`api` gave no suggestion for a mistyped class.** It now answers like `create` does.

### Changed
- **The console panel has eight colour presets** — Lattice, Observatory, Orbit, Void, Nebula, Aurora, Phosphor, Blueprint. Hover the tab on its right edge. Each replaces the activity cell's contents, not just its colours, and the choice persists across Studio restarts.
- `debug` now states what breakpoints actually do: they fire once per run rather than once per pass, and a log expression cannot see a loop's control variable.
- `console` no longer claims Studio's own messages never reach the log. Some do, some do not; a quiet log is not an all-clear.

## 0.3.1

Paths with dots in them resolve properly, `script_create` catches a script that would run twice, and the stale-plugin warning stops blaming the wrong side.

### Fixed
- **A path with a dot in a name could not be read back.** 0.3.0 rejoined dotted names but never backtracked, so `Workspace.Dr. Who` failed whenever a sibling named `Dr` existed — a path the tools themselves emit. Resolution now backtracks; a short name that resolves the whole path still wins.
- **The server compared against the sources it started with.** Rebuilding the plugin mid-session left the freshly installed plugin reported as the stale one, with advice that could not help. The fingerprint is re-checked when a source file changes.
- **Two sessions of one Studio could run different plugin builds.** A playtest keeps the plugin it loaded when it started, so a rebuild part-way through splits the two. `list_studios` now says so, names each session's build, and tells you to restart the playtest.

### Changed
- **`script_create` warns about a script that would run twice.** A `Script` with a non-Legacy RunContext inside `StarterGui`, `StarterPack`, `StarterPlayerScripts` or `StarterCharacterScripts` runs once where it sits and again in every player's copy. Studio warns about this in its own Output, which `console` cannot read, so the warning now comes back in the response. Use `LocalScript` there.
- **Better `NOT_FOUND` messages.** An index past the end says how many siblings share the name instead of blaming the wrong segment, and repeated sibling names are counted — `Part (x73)` rather than "Part" 25 times.
- **`console` says what it cannot see.** Messages Studio itself emits, and anything printed on the client, never reach any session's log — a quiet log is not proof nothing was said.

## 0.3.0

`execute_luau` now warns when it is reading a copy of a module instead of the live one, instance names containing dots resolve, and `script_read` can take a different line range per script.

### Fixed
- **`execute_luau` could report a running system as doing nothing.** It runs in the plugin's own Luau VM, which keeps its own `require` cache, so `require(SomeModule)` against a running playtest returns a second, freshly-initialised copy of that module — its counters and caches read as their starting values while the real ones are fine. A zero read that way is indistinguishable from a genuine zero, and there is no API that would let a plugin reach the game's cache, so the result now says so: any call using `require` while the game is running comes back with a note explaining what it actually read and pointing at the DataModel, or the game's own prints via `console`, as the way to see live state. The tool description says it up front too.
- **Instance names containing dots could not be addressed.** Paths are dot-separated, so `Workspace.Dr. Simon.Head` split into a segment named `Dr` and failed. Segments are now rejoined greedily, longest first, when the plain lookup misses — a place holding both `Dr` and `Dr. Simon` still resolves the short name to itself.

### Changed
- **`script_read` takes a line range per script.** An entry may now be `{path, startLine, endLine}` instead of a bare path, so "line 40 of this one, line 300 of that one" is one call rather than one call each. A bare string still reads the whole file, and the top-level `startLine`/`endLine` remain the default for entries without their own.
- **`script_create` waits 60 seconds instead of 15.** A batch of full script sources is the largest payload any tool sends, and the default was timing out on around 12KB across three scripts — splitting the batch is the wrong answer when creating related scripts as one undo step is the point of the tool.

## 0.2.9

A property that exists is no longer reported as a typo, and the stale-plugin warning stops repeating itself.

### Fixed
- **Properties you cannot set were reported as properties that do not exist.** `Lighting.Technology` is real — it is gated behind the RobloxScript identity, which no plugin has — but the name check reads the API dump filtered to what a plugin can reach, so it was indistinguishable from a misspelling. `modify` and `create` now answer with `RESTRICTED_PROPERTY`: "Lighting.Technology exists but is restricted to RobloxScript identity, so no plugin can set it. Change it in Studio's Properties panel (or Game Settings) instead." True of every property at that security level, and of `NotScriptable` ones, not just this one. Real typos still get `UNKNOWN_PROPERTY` and the closest matching names.
- **`inspect` with detail `full` hid the same properties.** "Every readable property" quietly meant "every property a plugin is allowed to see", and the ones it skipped were absent exactly the way a nonexistent property would be. They are now listed by name at the end of the response, with the identity each one needs.
- **The stale-plugin warning repeated on every call, for the whole session.** Four sentences of instructions on every `studio_status`, and once per row in `list_studios` — the same paragraph twice in one response with two Studio windows open. It is now stated in full the first time a build is seen and reduced to a single line after that, and a plugin that genuinely reloads into a different build warns again.

## 0.2.8

Packaging only. No code changes from 0.2.7.

The npm keywords were missing the terms people actually search for — `mcp-server`, `claude-code`, `cursor`, `ai-agent`, `roblox-development` — and keywords only take effect when a version is published, so they needed a release of their own to reach the registry.

## 0.2.7

Four tools that reported something untrue, and the one from 0.2.6 that replaced a wrong answer with another wrong answer.

### Fixed
- **`input` clicks land at an offset, and it now tells you what the offset is.** 0.2.6 said coordinates were out by the ratio between the emulated device's resolution and the screenshot's. Measured against a live playtest, it is a constant translation, never a scale — and it changes with the device and orientation, fitting no formula over resolution, viewport and GUI inset. So the relay now watches what the client actually receives and reports where the click was read against where it was aimed: `off by (-59, -58). Add (59, 58)`. Aim once, read the delta, correct. The offset is present with no device emulated at all, which the old explanation could not account for.
- **A click the client never registers is now called out as such**, instead of being reported as delivered. Phone emulation switches the client to touch input, which is why one that registered nowhere still looked like a success.
- **`perf coverage` diagnosed a failure on its own happy path.** Enabling coverage and reading straight back is expected to be empty — instrumentation only records while code runs — but 0.2.6 answered that with "these compiled before instrumentation was switched on". It now says what it actually knows, and where two causes are genuinely indistinguishable it names both instead of picking one.
- **Coverage reported scripts that had been destroyed**, for the rest of the session, under a bare name rather than a path.
- **`perf coverage` explained the "0 lines" flag with a cause that does not produce it.** An already-compiled script gets no record at all rather than an empty one; the replacement cause could not be reproduced either, so none is claimed now.
- `perf coverage` with an empty `enable` said nothing about having stopped, so a request to stop looked like a call that did nothing.
- `input` printed "emulated at undefined" when the device was known but its resolution was not.
- **A server whose MCP client was killed rather than closed never exited.** It kept the bridge port bound and re-registered itself every 30 seconds, so nothing ever swept it and the Studio console truthfully reported an agent that had left hours ago. It now shuts down when the process that spawned it goes away.

## 0.2.6

Four places where a tool told you something that wasn't true.

### Fixed
- **`input` clicks miss while a device is emulated.** Pointer coordinates are read in the emulated device's resolution, but `screenshot` returns the viewport's own pixels — 780x360 against 689x318 on a Galaxy S25 Ultra — so coordinates taken from a screenshot land short of the target. `input` now reports the emulation and says how to scale, or use `device op="stop"`. Keys were never affected, which is what made it look like a GUI fault.
- **`perf coverage` reported "no coverage recorded yet" for code that demonstrably ran.** A script already compiled when instrumentation was switched on gets no record at all, so it never reaches the results. The scripts the session was asked to instrument are now named, with the reason.
- **`list_studios` told the agent to ask the user which place they mean when only one place was open.** Two sessions on one placeId is an editor and its playtest, and the next call would have said so; the listing that comes first said the opposite. Both now give the same answer: pass `studioId` explicitly, edit session for anything that must outlive the playtest.
- **The console announced "Agent finished task." for an agent that had simply been closed.** The bridge sees a client disconnect and nothing more — quitting, a crash and a restart all arrive identically. It now says "Agent disconnected."

## 0.2.5

The console panel reacts to what the session is doing, reports how many agents share it, and says what a latency bar was.

### Added
- The activity band moves with the work: the solid draws in as a command goes out, springs past its size when the answer lands, snaps and wobbles on failure, breathes while idle, and winds down once the session goes quiet.
- Hovering a latency bar names the call — `Run luau: 2 ms`, not `2 ms`.
- A badge when more than one MCP client shares the bridge. Nothing shown for the usual single client.
- `Agent finished task.` when a client disconnects, and `agent idle — N calls, avg Xms` when work stops.
- **clear** logs `cleared N logs`, timestamped like every other row, and empties the latency trace with it.

### Changed
- The plugin is now called **rbx-studio** — window title, toolbar, and footer. Your panel's saved position and size are unaffected.

### Fixed
- **Two SSE frames sent in the same tick were both dropped.** They arrive as one chunk, and the parser decoded the whole chunk as a single JSON document. Visible as a client badge that went up and never came down; the real risk was a command sharing a chunk with a keepalive and vanishing — a lost tool call with no error at either end.
- An MCP client disconnecting was never noticed: `StdioServerTransport` listens only for `data` and `error` on stdin, so EOF never closes it and `onclose` never fires. Taken from stdin's `end` event instead.
- The bridge swept away the process it runs inside. The owner registered once and nothing refreshed it, so the reaper dropped it after 90s while it was serving — the client count read short and the drop was reported as an agent finishing.
- The latency bars' hover highlight had never once been visible: anchored to its bottom edge but positioned at the top of a frame that clips, so it drew entirely off screen.
- A departing client left its chosen Studio in the bridge forever.
- Shutdown aborted on Windows (`UV_HANDLE_CLOSING`) by calling `process.exit` mid-teardown.
- `check-plugin` filtered the Luau analyser to `LocalShadow` only, so a field used on a `--!strict` table that does not declare it shipped and crashed the plugin on load. It now also reports missing table keys.

### Faster
- The reply goes back to the agent before the console draws it. Repainting the log sat in front of every result on its way out.
- Repaints coalesced to one per frame, so a failure writing three rows no longer redraws the console three times.
- `TCP_NODELAY` on the bridge sockets.

## 0.2.0

A pass on console accuracy and a few real bugs found while doing it.

### Fixed
- `geometry` (union/subtract/intersect) could return a path that didn't exist.
- `inspect` and `modify` logged an internal probe call as a bare, misleading "Inspect X".
- `debug clear` with just a `path` (no `line`) always failed instead of clearing that script.
- The console described ~10 ops (`input`, `device.*`, `api.*`, `perf.scene`, `studio.transport`, capture internals) by raw wire name only.
- `playtest stop`'s teardown poll logged as "Check the playtest" with no "stop" line anywhere.
- The plugin's protocol version was sent but never checked; a rejected handshake showed a generic error instead of the real reason.

### Added
- `collision` can now `remove` a group — previously created-only, permanent for the place.
- `create`, `modify`, `move` describe what actually changed (class, properties, rename), not just that something did.

## 0.1.8

Found by actually watching the console during a live QA pass, immediately after 0.1.7 shipped: `playtest op="stop"` polls the surviving session every 400ms while the test tears down, and every one of those polls logged as "Check the playtest" — indistinguishable from an agent asking again for no reason, with no "stop" line anywhere to explain it (the real stop went to the session that is by then gone, and its console went with it).

### Fixed
- The teardown poll now logs as "Wait for the playtest to stop", not "Check the playtest".

## 0.1.7

The Studio console is the only feedback channel the plugin has — this is about making it tell the truth.

### Fixed
- **The console showed the raw wire name for ten operations instead of a description.** `input.send` — the one that fires on every keypress and click during a live playtest — read as "Input send" instead of "Press E" or "Click (320, 480)". Also fixed: `device.*`, `api.*`, `perf.scene`, `capture.playtestId`/`decode`, `studio.transport`.
- **A rejected handshake showed a generic "handshake failed" instead of the server's actual reason.** The bridge already sends a real message on every refusal (`missing header`, `no Studio connected`, etc.); the plugin was discarding it and showing a fallback string for any HTTP response that wasn't a plain success.

### Added
- **The plugin now announces its wire-protocol version, and a mismatch is reported the same way a stale build already is** — through `studio_status` and `list_studios`, not a silent failure. Existing plugins are unaffected: the version has never moved, so nothing changes until it does.

## 0.1.6

Documentation and error-message corrections. No behaviour change.

### Fixed
- `NO_STUDIO` and `list_studios` errors pointed agents at a nonexistent "Plugins tab -> Studio MCP -> Connect" command. The plugin connects automatically on load; the messages now say so and point at the reconnect button in the console.
- README called the beta "API debugger Luau" in one place; its real name is "Debugger Luau API".

### Changed
- README and package description rewritten shorter. The tagline no longer implies every write is undoable — `execute_luau` writes are not recorded.

## 0.1.5

Corrects two things 0.1.4 got wrong about the Debugger Luau API beta.

### Fixed
- **`debug` no longer refuses breakpoints with a message naming nothing.** The engine says only `Failed to execute AddBreakpoint request`. When every breakpoint in a call is refused, the error now points at the beta as the usual cause — it is off by default and needs a Studio restart — and at the other likely cause, a line that never runs, such as a `return` or an `end`.

### Removed
- **`studio_status` no longer reports `debuggerBeta`.** 0.1.4 added it and it never worked. Two probes were tried and measured, and neither varies with the beta: with it OFF, `GetService("ScriptDebuggerService")`, `FindService`, assigning `OnStopped` and `Enum.DebuggerResumeType` all still succeed; with it ON, `ReflectionService` still does not list the class. The only reliable test is `AddBreakpoint` itself, which cannot be run speculatively on someone's script to answer a status question. A field that always reads "fine" is worse than no field, so it is gone rather than guessed at a third time.

### Changed
- Corrected a claim in the 0.1.4 notes. They said the plugin could fail to load entirely when the beta was off, assuming `GetService` throws for an unregistered service. It does not — that was written without being checked. The guard added in 0.1.4 stays as insurance on a call that runs before any tool is invoked, but it fixed no observed crash.

## 0.1.4

Makes the Debugger Luau API beta impossible to miss, and stops it from being able to break anything else.

### Fixed
- **The plugin could fail to load entirely when the Debugger beta was off.** `ScriptDebuggerService` is only registered when that beta is on, and the handler asked for it at plugin start with no guard. If `GetService` threw there, every tool went down with it, not just `debug` — and silently, since a plugin that never loads never connects. The lookup is now guarded and a missing service is just a missing feature.

### Added
- `studio_status` reports `debuggerBeta: "off"` when the beta is disabled, so an agent finds out before calling `debug` rather than by failing. Absent when it is on, so the usual answer costs nothing.
- `CHANGELOG.md`, and the release workflow now builds each release body from it. A tag whose version has no section fails the workflow instead of publishing an empty release.

## 0.1.3

Documentation only — no code changes from 0.1.2.

The 0.1.2 package was published before the multi-agent notes landed, so the npm page was missing the two things you need before wiring several agents to one Studio:

- how per-client targeting works, and that `studioId` can still be passed per call
- that **subagents share their parent's connection and its target**, so they need an explicit `studioId`

If you are already on 0.1.2 the behaviour is identical; upgrade only for the docs.

## 0.1.2

Fixes a multi-agent bug that could send your edits to the wrong place.

### Fixed
- **Each agent now keeps its own active Studio.** Agents sharing one bridge also shared one target, so an agent calling `set_active_studio` silently retargeted every other agent's next un-addressed call. Nothing errored — edits simply landed in a place nobody asked for, and if that place was a playtest they were discarded when it stopped. The target is now per client, verified across two real MCP processes.
- Disconnecting a chosen Studio no longer promotes whichever session happens to remain. The choice is dropped, so a remaining pair asks again rather than pointing somewhere nobody picked.

### Notes
- Isolation is per MCP connection. **Subagents share their parent's connection**, so give those an explicit `studioId` per call rather than relying on the default.
- The built-in Studio MCP server solves the same problem by making `studio_id` mandatory everywhere and removing `set_active_studio`. This keeps the default instead, so a single open Studio still needs no id at all.

## 0.1.1

Multi-agent support, playtest screenshots, and a visible pointer.

### Added
- **Several agents can share one Studio.** Register the server in as many MCP clients as you like — two Claude sessions, Claude plus Cursor. The first server to start owns the port and the rest proxy through it automatically. No second connection to Studio, nothing to configure.
- **`screenshot` now works during a playtest.** Address it at the playtest's studioId and you get the player's own view — the only way to check a GUI in front of a running game. The shot is taken on the client and read back through the editor session, so keep the editor window connected.
- **`input` draws an on-screen pointer** that travels to each target before the click and ripples where it lands, so you can see what the agent is aiming at. Turn it off with `cursor: false`.

### Fixed
- `execute_luau` and other calls no longer time out with a bare "it timed out". Timeouts now report whether the command ever reached Studio, how long the plugin has been silent, what else was in flight, and which transport was used.
- A playtest is no longer mistaken for a second place. Editor plus playtest used to trigger AMBIGUOUS_STUDIO, which has no sensible answer — there is one place in two states. It now says so and explains which to target.
- `api describe` no longer lists deprecated members as if they were usable. `Instance` had eight, including `clone` and `getChildren`. They are counted, not listed.
- Device emulation reported portrait resolutions backwards (852x393 for a 393x852 viewport).
- `character`'s description claimed synthetic input was impossible. It has not been since `input` shipped.

### Notes
- `debug` needs the **Debugger Luau API** beta enabled in File → Beta Features, then a Studio restart. The error now says so.

## 0.1.0

First public release. 29 tools over a push-based SSE bridge, editor-safe script editing through `ScriptEditorService:UpdateSourceAsync`, and every write batched into a single undo step.
