ZeroMind (OrigoZero game engine)
Server Details
Build, run and publish 3D games in the Zero engine from Claude Code, Cursor or Codex, over MCP.
- Status
- Healthy
- Uptime
- 0.1% over 21 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-06-18
- URL
- Repository
- OrigoZero/zeromind-plugin
- GitHub Stars
- 1
TDQS
Score is being calculated.
Available Tools
42 toolsagent_skillInspect
Open an ENGINE skill — a packaged procedure for one job in this world, carrying the instructions plus the assets, guides, and tools that job runs through. These live in the connected world, not in your host environment, and this tool is the only way to open one. Call with NO arguments to list every skill this world knows (name + one-line description, and which you already have open); pass name to open one and get its full instructions, its dependencies marked present or missing here, the exact tool names to call, and any subskills under it (addressed "parent/sub"). A skill you open STAYS OPEN: it and its subskills ride your tool responses, each subskill marked as you open it, so a job spanning many calls keeps its remaining passes in view — pass release when the whole job is done ("*" closes all). Reach for this BEFORE working out a multi-step engine job from first principles — a skill is the already-correct path.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| name | No | Skill to open, e.g. "scenes". Address a subskill through its parent: "scenes/player-setup". OMIT to list every available skill with its one-line description. | |
| scope | No | When listing, show only skills from this scope: 'builtin' (shipped with the engine), 'world' (authored in the bound world), 'library' (installed). Omit for all of them. Ignored when `name` is given. | |
| release | No | Close a skill you have open, e.g. "scenes" — it stops riding your tool responses. Releasing a parent releases the subskills opened under it. Pass "*" to close every skill you have open. Takes precedence over `name`. |
bashDestructiveInspect
A complete bash shell running inside the Zero engine, over this world's files and the engine's live state. It runs in the engine, apart from the computer you are called from. Use it the way you use bash on any development machine, and reach for what you already know first: the shell language is all there, and the standard programs are installed (ls /usr/bin lists them). command not found means only that one program is absent; do that job another ordinary way.
Where things are: the world's project is /zero/source, the engine's live state is /zero/runtime (as files), the engine's documentation is /zero/docs (and man <topic>). /tmp is scratch for the session; ~ is your home, kept on this machine and synced to no one.
The engine's own operations are a command-line program, zero. Learn it as you would any unfamiliar CLI: zero --help, zero --search <query>, zero <toolbox> <tool> --help. zm is the world's version control, with the git verbs. luau <file> runs a Luau script in the engine.
For example: rg -n 'typed function' /zero/source find /zero/source -name '*.luau' | xargs grep -n 'asset.resolve' COUNT="$(find /zero/source -type f | wc -l)"; echo "$COUNT" mkdir -p /tmp/work && grep -rn 'TODO' /zero/source > /tmp/work/todo.txt find /zero/runtime -maxdepth 2 -type d zero --search 'raycast' zero camera --help
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| command | Yes | The command line, written exactly as you would type it into bash anywhere else: pipelines, redirection, `$(...)`, quoting, globs, loops and multi-line scripts all work. |
captureRead-onlyInspect
Render an image or collage from the engine, or read the frame it presented (source='presented': the game view exactly as the player saw it, with its real TAA, motion blur, exposure and render scale; source='window': the whole window). Pick WHERE with 'source' (and aim it with 'viewpoint' + 'basis': front/top/left/iso against the subject's own axes or the world's), WHAT with 'pass' (motion_vectors to see whether something moves, normal to see whether a surface is correct), HOW it projects with 'projection' ('orthographic' keeps parallel edges parallel and equal sizes equal: the one to verify a shape under), and which render layers with 'renderLayers'. 'isolate' draws the subject without the other geometry. mode='collage' makes a grid whose cells vary by 'setups', by 'viewpoints', by 'passes', or over 'duration': a shot list's whole set-ups side by side, six sides of an object, or one view under four passes, in a single image. Every cell reports 'luma': the tone of the pixels it encoded, in code values on the 0-255 scale: min/max/mean, the percentiles p1 p5 p50 p95 p99, 'span' (max-min), 'spread' (p95-p5), and 'crushed'/'clipped', the shares sitting at 0 and at 255. Read 'spread' to answer whether a shot is legible: a subject can be modelled, lit and drawn and still arrive inside a handful of code values, which a mean cannot tell from a picture with something in it. A capture is taken whenever the engine reaches it rather than at the instant the call was sent, and the world keeps running between calls, so two shots of a running scene are separated by the real seconds between them; pause it or slow it when the picture has to catch a specific moment.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| fov | No | Vertical field of view in degrees, stated for this capture alone. Omit to take the lens of whatever is being captured: a capture of a camera ('main', 'screen', 'viewport', 'editor', 'camera') renders at that camera's own fov, and one standing at a position or orbiting an entity renders at 60. | |
| grid | No | Collage layout as 'COLSxROWS' (e.g. '3x3', '2x2', '4x2'). Omit to have it worked out from the number of cells; a grid too small for them is an error rather than a silent crop. | |
| mode | No | 'image' = one frame. 'collage' = a GRID of frames in one image, where what varies from cell to cell is what you pass: 'setups' for a cell per whole camera set-up (the contact sheet of a shot list), 'viewpoints' for a cell per named view of one subject, 'passes' for a cell per render pass, or 'duration' for a cell per sample over time. Naming a station axis ('setups' or 'viewpoints') alongside 'passes' lays out a 2D grid (a row per station, a column per pass). A collage with no axis is an error naming all of them — it does not default to time. | image |
| pass | No | Which render output to produce. 'final' = normal lit rendering (default). The built-in debug passes replace the fragment output with a diagnostic buffer — use these to verify geometry and material correctness without reasoning about final lit pixels: 'normal' (alias 'world_normal') = per-pixel world-space normal (RGB = xyz*0.5+0.5), the geometry sanity check; 'normal_texture' = raw normal map sample before TBN (flat blue if no normal map); 'depth' (alias 'linear_depth') = distance from the camera on a log curve (near black, far white), the fastest way to read scene layout; 'albedo' / 'roughness' / 'metallic' / 'ao' / 'emissive' = the corresponding PBR channel, drawn magenta on a surface whose shader lights itself and hands the engine no material to read; 'tangent' = world-space tangent; 'material_flags' = R=normal_map, G=roughness_metallic_tex, B=base_color_tex; 'shadow' = the share of the direct light reaching each fragment that survived every shadow test, over EVERY light standing on it — sun, point, spot and area alike (white = all of it, black = none of it), so a fragment the 'final' pass renders dark for being shadowed reads dark here; 'shadow_depth' = the map behind that answer for the light putting the most light on the fragment — R = the depth the fragment carries in that light's map, G = the depth the map already held there, B = which light answered (0 the sun's cascades, 0.25 a parallel light, which claims a map of no kind, 0.5 a spot or area light's atlas tile, 1 a point light's cube face); 'motion_vectors' = the frame's velocity buffer — each pixel's screen-space travel between the previous frame and now, whichever pass wrote it (a material, the splat pass, a render feature naming @scene.motion); static pixels flat black, moving pixels colour-biased. Beyond these, `pass` also accepts the name of any CONTENT-registered capture view (a render feature that publishes a view — e.g. a baked-lightmap view); an unknown name is resolved against that registry and, if it matches no view, the error lists what is available. Any pass but `final` is drawn under `all !sky !ui !EditorUI !debug` with the post-process chain off, so the buffer comes back as the value it encodes rather than as a graded picture of it; `renderLayers` and `postProcessing` each state that differently. | final |
| angle | No | Orbit direction as [yaw, pitch] in degrees (default [0, 20]). Only the viewing angle — distance is still auto-fit from bounds unless you set 'distance'. source='entity' only. | |
| basis | No | Which axes a 'viewpoint' is measured against. 'local' = the SUBJECT's own axes: 'front' is the side it faces however it is turned, and the frame is fitted to its own extents rather than the world-axis box around them. 'world' = the world axes: 'front' is whatever faces world +Z. Required alongside 'viewpoint' when framing an entity, because for anything rotated the two are different pictures. Framing a position instead of an entity, both values mean the world axes. | |
| owner | No | The key the holds this capture takes are stated under. `deterministic` pins the per-frame clock and `clearAir` holds the air, and both are cells every agent driving this engine renders through, so an agent can take one exclusively for a key of its own. A capture stating that key is admitted under the standing hold and photographs what its owner set; a capture stating another key, or none, is refused while that hold stands. It is the same key `renderer.temporal.hold` and `renderer.atmospherics.hold` take as `owner`, and their `release` hands the cell back by. | |
| width | No | Output width in pixels (image) or the whole SHEET's width (collage). A collage cell is rendered at the box the grid divides out of the sheet, so a cell holds the same picture a single capture at that cell's own width/height holds, and each cell reports the pixels it was rendered at. Omit to take the size of whatever is being captured: a capture of a camera ('main', 'screen', 'viewport', 'editor', 'camera') renders at the viewport's own pixel size, and one standing at a position, orbiting an entity or painting a UI window renders 1024 wide. | |
| camera | No | (source='camera', or with no source) A camera entity ref/id to render from. Renders that camera's authored pose offscreen - use it to validate any specific camera (a security cam, a cutscene cam) regardless of which camera is on screen. | |
| entity | No | What to frame (source='entity'): an entity name or id, OR an array of names/ids to frame several at once. The camera AUTO-FITS to the union of their world-space bounds, so the subject is guaranteed fully in frame at ANY scale: a 1cm prop and a 100m building both fill the shot. Single or list, name or id; you cannot pick the wrong shape. Framing is not isolation: this FITS THE FRAME to the subject, it does not decide what is drawn in it, and anything else standing there is still rendered, and a scene's default player spawn sits at the world ORIGIN, exactly where a prop is usually built. Pass 'isolate' to draw the subject without the other geometry. If the framed shot comes back empty, the geometry/material is the problem, not the camera. A name more than one entity carries is refused, and the refusal names each of them with its id; every cell reports the entities it framed under 'subjects'. | |
| format | No | Output image format. 'jpeg' (default) is smaller. 'png' is lossless. Ignored for source='ui_window' (always PNG). | jpeg |
| frames | No | source='presented' / 'window' only: how many presented frames to take, 1-32 (default 1). More than one comes back as a grid in the order the frames were presented, and each cell reports its frame number, so a run of consecutive frames reads as rising numbers at real gameplay speed: the measure of TAA convergence, motion blur, flicker and exposure adaptation over time. | |
| height | No | Output height in pixels (image) or the whole SHEET's height (collage). A collage cell is rendered at the box the grid divides out of the sheet, so a cell holds the same picture a single capture at that cell's own width/height holds, and each cell reports the pixels it was rendered at. Omit to take the size of whatever is being captured: a capture of a camera ('main', 'screen', 'viewport', 'editor', 'camera') renders at the viewport's own pixel size, and one standing at a position, orbiting an entity or painting a UI window renders 576 tall. | |
| lookAt | No | World point the camera aims at [x, y, z]. source='position' only; defaults to origin. | |
| passes | No | Collage pass axis: a cell per render pass, taking the same names as 'pass' (including content-registered capture views). One frame under final, albedo, normal and depth side by side is how a material problem separates from a geometry one. Combine with 'setups' or 'viewpoints' for a 2D grid. | |
| screen | No | (source='ui_window') Screen id passed to ui.registerScreen that contains the target Window. | |
| setups | No | Collage set-up axis: a cell per WHOLE camera set-up — the contact sheet of a shot list. Each entry takes the same options that aim a single capture ('source', 'camera', 'entity'/'entities', 'position', 'lookAt', 'rotation', 'distance', 'angle', 'margin', 'viewpoint', 'basis', 'projection', 'orthoHeight', 'fov', 'near', 'far', 'isolate'), plus 'label' to name the shot on the result; a field an entry leaves out is taken from the collage's own options, so a shot list writes down only what makes each shot differ. This is the axis for comparing several DIFFERENT stations and lenses of one scene at one instant — 'viewpoints' orbits one subject, 'duration' samples one camera over time. Exclusive with 'viewpoints' (both say where the camera stands); combine with 'passes' for a 2D grid, a row per set-up. | |
| source | No | Where the image comes from. 'presented' and 'window' READ the frame the engine presented; every other source RENDERS a frame of its own offscreen. 'presented' = the game view exactly as it was presented to the player, after the post chain, the upscale, the display transform and the UI, at the size it was composed at: the one source whose temporal antialiasing, motion blur, camera motion, auto exposure and render scale are the real ones, since nothing is re-rendered for it. 'window' = the whole presented window (or headless framebuffer) with the editor chrome and everything painted on the window. Both take 'frames' + 'interval' for a run of consecutive presented frames, report each frame's frame number, render scale, raster and composite sizes, projection jitter, exposure and history reset, and refuse the options that aim or shape a rendered frame (camera, entity, position, viewpoint, fov, pass, renderLayers, postProcessing). DEFAULT (omit, or 'main') = the MAIN SCENE CAMERA (the gameplay/PlayerPrototype camera or an agent-placed scene camera), rendered offscreen from its authored pose; it works in edit mode too (before you press play). Errors if the scene has no non-editor camera. 'editor' = the editor fly-camera you author with. 'screen' = a reproduction of the on-screen image, rendered offscreen from the camera holding the viewport under the render layers and diagnostic pass THAT camera draws the screen with, so a camera sitting on a diagnostic channel comes back as that diagnostic; the frame as presented is 'presented'. Passing 'renderLayers' or 'pass' alongside it states them for this capture instead. 'viewport' and 'gameplay' = aliases for the default (the scene camera). Pass 'camera' with a camera entity ref to render from any specific camera. 'entity' = orbit an ephemeral camera around an entity (entity + distance + angle). 'position' = render at an explicit world point (position + lookAt). 'ui_window' = render ONE egui Window into its own texture (screen + window). If 'source' is omitted: 'entity' when you pass 'entity', 'position' when you pass 'position', 'ui_window' when you pass both 'screen' and 'window', 'camera' when you pass 'camera', otherwise the main scene camera. | |
| window | No | (source='ui_window') Widget id of the Window inside that screen (e.g. 'system-tools-window'). | |
| isolate | No | Draw the subject WITHOUT the other geometry (source='entity' only). It changes exactly that: lighting, sky and post-process are untouched, so a final frame stays final — for a flat read of the geometry use 'pass'. Excluded geometry still casts shadows onto the subject and still bounces light into it, the same as any render-layer exclusion. The subject's layers are restored afterwards. In a 'setups' collage each cell shows its own set-up's subject alone; a set-up states 'isolate' of its own to override this for its cell. | |
| quality | No | JPEG quality 1-100 (format='jpeg' only). | |
| clearAir | No | How much of the air between the camera and a surface reaches this one frame. `true` takes it out entirely, so a surface renders in its own colour and its albedo, tint or material can be judged while another slice of a shared world drives the weather — a wash that no other option reaches, because aerial perspective and the volumetric media are render features rather than post-process or a render layer, so neither `postProcessing` nor `renderLayers` strips them. A number in [0, 1] keeps that share of the air instead. It reaches aerial perspective, height fog and volumetric light scattering wherever those are driven from, a component re-pushing them every frame included. The sky, the sun and the light they put on the surface are untouched, because those are what the surface's colour is made of, and the cloud layer and a placed volume draw as geometry that `renderLayers` and `isolate` already name. Scoped to this capture: the scene's own air is back the moment it returns, so a world several sessions share is never left in scratch weather. | |
| distance | No | Override the orbit distance (source='entity'). OMIT to auto-fit from world bounds (recommended — that's the guarantee that the subject is framed). Pass a value only to force a specific radius, which can push the subject out of frame. | |
| duration | No | Collage time axis: a cell per sample, spread across this many seconds of gameplay. Exclusive with 'setups', 'viewpoints' and 'passes' — a cell differing both in what it looks at and in when it was taken answers neither question. | |
| interval | No | source='presented' / 'window' only: how many presented frames apart two taken frames stand, 1-600 (default 1: consecutive frames). | |
| position | No | Explicit camera world position [x, y, z] (required when source='position'). | |
| save_path | No | Optional path to save the image to. Takes a VFS path in either spelling ('/source/tmp/shot.png' or '/zero/source/tmp/shot.png'), or a host-filesystem path ('/tmp/shot.png'). The image is still returned as base64 either way; the response reports 'savedTo' with the resolved destination, or 'saveError' explaining why there is no file. A VFS save is written without firing write side effects, so the file stays at the path 'savedTo' names and reads back from it: hand that path straight to 'set_world_cover', 'read_file' or 'vfs.read'. A VFS save under /zero/source made while play is running lands on the play shadow: the response then carries durable=false, a 'warning' naming the file a guarded play-exit deletes unless it is kept, and 'playShadow' naming the ways to keep it; a host-filesystem path is outside the VFS and is kept whatever play does. To make the image an imported texture asset instead, write it with 'write_file' or run the importer on it. | |
| viewpoint | No | A named camera station, instead of working out an 'angle'. front/back/left/right/top/bottom are the six sides; 'iso' is the corner view where all three axes project equally. REQUIRES 'basis' when framing an entity. Pair with projection='orthographic' to read a side as a true elevation. | |
| projection | No | 'perspective' (default) converges with distance, the way an eye sees. 'orthographic' covers a fixed world-space height at EVERY distance, so parallel edges stay parallel and two equal-size objects at different depths cover equal pixels — the projection to check a shape or compare sizes under, where perspective convergence hides both. | perspective |
| viewpoints | No | Collage view axis: a cell per named view of ONE subject. An array of viewpoint names, a space-separated string ('front top left'), or 'sides' for all six. Combine with 'passes' for a 2D grid; use 'setups' instead to vary the whole camera set-up from cell to cell. Exclusive with 'setups'. | |
| orthoHeight | No | World-space vertical extent an orthographic frame covers. Omit to fit it to whatever is being framed (recommended, the same way distance is auto-fit). | |
| renderLayers | No | Which render layers this capture includes — the control over both which objects draw and which passes run (sky/ui/EditorUI are built-in layers). Space-separated tokens: `all` seeds every layer, `name` adds a layer, `!name` drops one — e.g. `all !ui` for a clean shot with no UI overlay, `all !sky !ui` for a flat diagnostic background, or `default enemy` to render only those two layers. Post-processing is not a layer: pass `postProcessing = false` to capture the ungraded frame. Defaults omit `EditorUI` (the human editor's chrome) and `debug` (the debug-visualisation overlays — gizmos, light/probe icons, frustums, collider and bounds wireframes, several of which are on by default in edit mode) so agent captures aren't cluttered with them; pass `all` to include them. Naming a `pass` other than `final` states a stronger default than any of these: a diagnostic buffer's RGB is the reading, so that capture is drawn under `all !sky !ui !EditorUI !debug` and with the post-process chain off — the sky would paint its own colour where the buffer holds none, and the chain would grade the values being read. Stating `renderLayers` here replaces that spec, and `postProcessing = true` puts the chain back. Content `ui` is answered three different ways, by what aimed the shot. A capture of a camera the scene already holds — `main`/`viewport`/`gameplay` (the scene camera) and `editor` (the fly-cam) — keeps it, so an authored HUD is in the frame. A capture that BUILDS a camera to frame a subject — `entity` and `position` — drops it alongside the authoring layers, since a HUD drawn across the whole frame is unrelated to the subject being framed; pass `all !EditorUI !debug` to keep the HUD in a framed shot. Two sources answer from the camera they mirror rather than from either default: `screen` renders under the spec the on-screen camera draws the viewport with, verbatim, and `camera` under that named camera's own spec with the authoring overlays off, so each holds content `ui` exactly when the spec it mirrors does. `ui_window` paints one Window into a target of its own, and no render-layer spec applies to it. `presented` and `window` read the frame the engine presented, drawn under the layers the viewport camera draws with, and refuse a spec of their own. Overriding here scopes to THIS capture, unlike `debug.set`, which mutates the engine-wide state every other viewer shares. | |
| deterministic | No | Pin the clock every per-frame field is drawn against for the length of this capture. Film grain, an animated noise field and a jittered raymarch offset are redrawn each frame from that clock, so two shots of a scene in which nothing has moved otherwise differ over a large part of the frame — and a difference image cannot then answer whether anything in the shot moved. Pinned, they are redrawn identically, and every capture that asks for it pins at the same instant, so shots taken minutes apart still agree. It does not pin an accumulating temporal effect (TAA history, denoiser accumulation, auto-exposure adaptation), which settles by itself on a still scene. | |
| postProcessing | No | Whether this capture runs the post-process chain. Omitted, a capture naming a diagnostic `pass` drops the chain so its buffer is read flat, a capture from a specific camera mirrors that camera's own `postProcessing`, and every other capture keeps the chain, so a final frame stays a final frame. Pass false to read the scene ungraded: the chain comes off, and so does the film a render feature draws — the lens flare and grain, the bokeh a short focus throws, the shutter's smear — each declared part of the camera's photographic finish by the pass that draws it, so a graded frame and an ungraded one are different pictures. Post-processing is a Camera property, not a render layer, so `renderLayers` cannot strip it. |
describe_toolRead-onlyInspect
Full schema for one registered tool — its arguments, types and behaviour. Use after search_tools locates it and before calling it, instead of guessing arguments. Answered by the attached engine, so it needs one: world.open attaches one.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| tool | Yes | Tool name. | |
| toolbox | No | Toolbox that owns it, when the name is ambiguous. |
editInspect
Flip the connected world back into EDIT mode: gameplay pauses, /zero writes unlock. Returns the resulting run-state. This is the mode flip — to change a file, use edit_file.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. |
edit_fileDestructiveInspect
Replace an exact string in a world VFS file.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| new | No | Alias for new_string | |
| old | No | Alias for old_string | |
| path | Yes | ||
| quiet | No | When true, write the result without firing write side effects (importer dispatch, assetType onChange, vfs.watch subscribers). | |
| durable | No | When true, the edited bytes go to canonical /source even while play is RUNNING, and the session stays in play. The affected modules and components hot-reload, so the edit is observed running in the same play session with nothing left to promote — the call for bytes whose destination is known before they are edited, where vfs.promotePlayShadow(path or {paths}) takes bytes already on the shadow with play still running. An edit that cannot become canonical source is an error naming why, instead of a success that landed on the shadow. | |
| new_string | No | ||
| old_string | No | ||
| replace_all | No |
edit_world_metadataDestructiveInspect
Set the connected world's face — title, description, README body, tags — and who can open it. A world nobody can recognise or search for is hard to find even when it is public.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| body | No | README body (markdown). | |
| tags | No | ||
| title | No | ||
| topics | No | Free-form topics. | |
| category | No | Curated category slug. | |
| visibility | No | Who can open the world NOW. public: anyone, and it is listed. unlisted: anyone with the link, not listed. private: only the owner, members and admins. On a draft, public or unlisted takes it out of draft to that (the same as world.undraft); private leaves the draft as it is. Visibility decides who can open the page; pushing commits is what gives visitors something to play. | |
| description | No |
executeDestructiveInspect
Run Luau code in the connected world and return its result, logs, and engine state. Long runs are promoted to a background task ({status:"running", taskId, hint}); the hint says what to do next for your harness (wait resumes the task).
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| args | No | Values injected as the SCRIPT_ARGS global. | |
| code | No | Inline Luau source to run. | |
| file | No | VFS path to a .luau file to run instead of `code`. | |
| logs | No | Minimum log level to return (default error). | |
| strict | No | Per-call override for the LSP strict gate. Defaults to true (honour the world's lsp.strict_mode). Set to false on a single call to skip the gate even when error-level diagnostics are present — useful when prototyping against runtime-installed globals the LSP can't see. Diagnostics still flow back in the result so you see what was bypassed. | |
| logScope | No | Whose work the engine-window log lines in the response may be about (default: caller). One engine serves several agents at once and runs all of their content, so its log holds all of their failures. `logs` says how severe a line must be to appear; this says whose work it may be about, which no severity floor can express, because a neighbour's per-frame error IS an error. `caller` keeps the lines this call's own work raised plus the engine's own, and closes the list with one <n error lines from another caller's work left out> marker when there were any. `all` keeps every caller's, which is what a reader debugging the whole engine wants. The engine's own subsystem lines carry no caller and are kept either way. | |
| wait_frames | No | Frames to await deferred work (default 4). |
guidesRead-onlyInspect
Search or read the engine's built-in guides (API topics, how-tos, and each asset type's README under types/). list enumerates every guide path, path reads one, query searches them. Works with or without an engine. With one attached, that engine answers, by meaning, and also reaches the world's own guides and its installed libraries. With none, the answer comes from the published Zero docs, matched by keyword, and says so: served_by is "docs" and engine says why no engine answered.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| list | No | Enumerate all guide paths. `path` and `query` are ignored. | |
| mode | No | semantic finds content by what you are trying to do; keyword matches the words in the files each type declares — a README, a guide body, code. Default: semantic on a live engine, keyword offline. An attached engine reads it; the answer from the published docs does not. | |
| path | No | Guide identity, e.g. topics/physics or types/shader. A short form (physics) works when only one guide answers to it. With `query`, narrows the search to the guides under this identity. | |
| tier | No | How much of each entry the guide index (no `path`, no `query`) returns: 1 the paths alone, 2 adds each guide's kind and summary, 3 adds the file behind it and the other spellings it answers to. An attached engine reads it; the answer from the published docs does not. | |
| limit | No | Max matches to return when searching. An attached engine reads it; the answer from the published docs does not. | |
| match | No | What a hit must match: what a thing IS, its README (identity); what it DOES and how it is made, a guide body or code (capability); either (any, default); both (all). Applies to keyword mode only; semantic ranking does not read it. An attached engine reads it; the answer from the published docs does not. | |
| query | No | What you are looking for, in plain words. | |
| assetType | No | Comma-separated documentation types a `query` searches: 'guide', 'agentskill', 'assettype', 'guide,assettype'. Omit to search all three. Any other type is refused: `search_tools` searches tools and toolboxes, and `zeromind.search` every other kind. An attached engine reads it; the answer from the published docs does not. | |
| context_lines | No | Lines of surrounding context above and below each matched line in the snippets a `path` + `query` scan returns. An attached engine reads it; the answer from the published docs does not. |
pauseInspect
Freeze or resume the world WITHOUT leaving the current mode — how you hold a moving scene still for a clean capture. Returns the resulting run-state.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| paused | No | true to freeze, false to resume. |
playInspect
Flip the connected world into PLAY mode: scripts tick, physics simulates, /zero writes lock. Returns the resulting run-state. Refused while user content under /zero/source has error-severity diagnostics — the refusal names them; fix those rather than working around it.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. |
previewRead-onlyInspect
Render a preview image of an asset without spawning it into the scene.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| asset | Yes | Asset identity to render. | |
| width | No | ||
| height | No |
read_fileRead-onlyInspect
Read a file from the world VFS. Returns text, an image (for PNGs), or a directory listing.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| path | Yes | VFS path, e.g. /scene/main.luau | |
| limit | No | Maximum number of lines to return, counting from `offset` (defaults to line 1). Text files only — ignored for images. | |
| offset | No | 1-based line number to start reading from. Text files only — ignored for images. When set without `limit`, reads up to 2000 lines from there. |
search_toolsRead-onlyInspect
Search the Zero tool registry. Tools are named, typed operations grouped into toolboxes (entityOps, scene, appearance, lighting, …). With no arguments, returns the toolbox overview — one row per toolbox with its purpose and tool count. toolbox returns all of that toolbox's tools; query on its own searches every tool and toolbox this world can reach — its own, the builtin library, installed libraries and imports — by meaning (mode: "semantic") or by words (mode: "keyword"), and answers the top 25 compact rows: the callable identity, whether the hit is a tool or a toolbox (drill into a toolbox with toolbox), and a one-line purpose. The answer names the mode and slot that ran, the worlds it covered, and its status. A query given with a toolbox searches inside that toolbox's registered tools instead. Pass schema: true on a toolbox drill-in for full signatures, args, and examples inline, or call describe_tool for one tool's full schema. Run a result with use_tool, from Luau as tools.use("", "", ...), or in the engine shell (the bash tool) as zero <toolbox> <name> [args] — where zero browses the same registry and --help answers at every level (zero, zero <toolbox> --help, zero <toolbox> <tool> --help). Answered by the attached engine, so it needs one: world.open attaches one. guides answers without an engine.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| mode | No | semantic finds tools by what they do; keyword matches the words in each tool's README and code. Default: semantic on a live engine, keyword offline. | |
| limit | No | Optional cap on the number of results. On the `toolbox` drill-in it is a trim, not a ceiling — omit it to return EVERY tool, since compact rows stay small and a genuinely large listing spills to a retrievable file rather than being silently truncated. A query answers the top 25 ranked hits; a smaller limit trims them. | |
| match | No | What a hit must match: the README (identity), the code and its declared interface (capability), either (any, default), both (all). | |
| query | No | One phrase, as a string, naming what you are looking for in plain words. On its own it searches every tool and toolbox this world can reach (its own, the builtin library, installed libraries and imports) and answers compact rows. Given WITH a `toolbox` it instead matches the words of that toolbox's own registered tools, and `mode` / `match` do not apply. Omit (with no `toolbox`) to browse the TOOLBOX overview: one row per toolbox with its purpose and tool count. | |
| schema | No | Include each tool's full schema (signature, args, returns, examples) inline. Applies to the `toolbox` drill-in; a `query` answers compact rows — the callable identity plus a one-line purpose. Fetch one tool's full schema on demand with describe_tool. | |
| toolbox | No | Drill into one toolbox — return its tools (e.g. entityOps, camera, lighting, baking). Call with no arguments first for the list of toolbox names. With a `query`, the search runs over that toolbox's registered tools rather than over the content this world can reach. |
session.connectInspect
Pin this conversation to ONE engine, so every later call (execute, capture, write_file, …) drives that same engine. Name it with session (from session.list), or describe it with world and, when the world has engines on more than one branch, branch. A branch is never chosen for you: engines on different branches have different working trees, so naming none where several exist is refused, listing them. Naming both session and a world (or branch) the engine is not on is refused, naming both, and pins nothing. Waits until the engine is connected. Naming a player is refused: open the world with world.open to get an editor to work in.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | The same argument as `world`, under another name: give one of the two. A call giving them two different worlds is refused. | |
| world | No | World guid, when you are describing the engine rather than naming it. Beside `session` it has to be that engine's world, or the call is refused. A value that is not a guid, a world's name included, is refused. | |
| branch | No | Which branch's engine you mean. Required when the world has engines on more than one. | |
| session | No | Exact engine session id from session.list. |
session.listRead-onlyInspect
List the engines you have running: which world and BRANCH each is bound to, whether it is a browser tab, a native engine or a player, and whether another conversation is already driving it. Call this when a tool tells you the target is ambiguous, or before session.connect, to see what there is to choose from. A player (drivable: false) is someone playing the world in the runtime profile: it takes no edits and keeps nothing when it exits, so it is listed for you to see and is never driven or bound.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
set_world_coverDestructiveInspect
Set the connected world's cover image — captures the current viewport by default.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| source | No | viewport (default): render and upload the current viewport. vfs_path: upload an image at `vfs_path`. blob_sha256: stamp an already-uploaded blob. | |
| vfs_path | No | Path to an image in the engine VFS (PNG/JPEG/WebP). Used when source=vfs_path. | |
| blob_sha256 | No | Hex sha256 of an already-uploaded image blob. Used when source=blob_sha256. | |
| content_type | No | Override the image MIME type (otherwise inferred from the path extension). |
use_toolDestructiveInspect
Run registered tools — prewritten execute() calls, grouped into toolboxes. calls lists the tools to run; search_tools finds them. mode 'sequential' (the default) stops at the first failure; 'parallel' runs every call and collects all results. Returns { batch, mode, ok, ran, total, results }, where results matches calls by position.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| mode | No | 'sequential' (the default) stops at the first failure. 'parallel' runs every call and collects all results. | |
| calls | Yes | The tool calls to run, in order. |
waitDestructiveInspect
Resume a background task from a promoted execute/bash and return its result when ready. Pass its taskId, or the kickoffId of a call the engine accepted and had not reached yet.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| logs | No | ||
| taskId | No | Task id from a {status:"running"} response. | |
| logScope | No | Whose work the engine-window log lines in the response may be about (default: caller). One engine serves several agents at once and runs all of their content, so its log holds all of their failures. `logs` says how severe a line must be to appear; this says whose work it may be about, which no severity floor can express, because a neighbour's per-frame error IS an error. `caller` keeps the lines this call's own work raised plus the engine's own, and closes the list with one <n error lines from another caller's work left out> marker when there were any. `all` keeps every caller's, which is what a reader debugging the whole engine wants. The engine's own subsystem lines carry no caller and are kept either way. | |
| kickoffId | No | The kick-off handle to wait on — the `kickoffId` field from a response the engine accepted and had not reached yet (`{ status: "running", kickoffId }`). Resolves to the task the call spawns, then waits on it exactly as `taskId` does. | |
| timeout_secs | No | Inline budget (default/capped 20s). |
world.analyticsDestructiveInspect
How a world is actually doing: plays, players, playtime, the funnel from page view to a session that lasted, retention, and what boots are failing on. The same numbers the creator's dashboard shows, so an answer here and an answer there agree. Reads the world this conversation has open, or the one you name with world. Needs maintainer access: a world you have no role on answers not found. view picks the arrangement (series | breakdown | funnel | retention | performance). Ranges are whole UTC days, up to 400 of them, and a range over 120 days comes back bucketed by week. Counts and durations only: there is no per-player row here and never a name, a place or a session. Read clickhouse_configured before you report a zero, because a deployment that records nothing answers zeros.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Inclusive UTC end day, YYYY-MM-DD. Defaults to today. | |
| from | No | Inclusive UTC start day, YYYY-MM-DD. Defaults to 27 days before `to`, which makes the default window four weeks. | |
| guid | No | The same argument as `world`, under another name: give one of the two. A call giving them two different worlds is refused. | |
| view | No | Which arrangement of the numbers. Defaults to `series`. `series`: Each metric asked for, day by day over the range, with the range's total and the previous range's total beside it. `breakdown`: One metric split by the dimension it carries (a boot failure's class, a connection class), biggest first, each row with its share of the whole. `funnel`: The steps from opening the world's page to a session that lasted a minute, each step with its share of the step before it. `retention`: How many first-time players came back within a day, a week and a month, with the weekly cohort grid behind those rates. `performance`: Time to first frame, how far boots got through the engine's boot timeline, what the failures were and on what connection. | |
| grain | No | Bucket size, `day` (default) or `week`. A range over 120 days is served by week whichever you ask for. | |
| world | No | World guid. Defaults to the world this conversation has open, so a call after world.open or world.connect needs no argument at all. | |
| metric | No | The ONE metric to split. Required by the `breakdown` view and ignored by the others. The metrics with a breakdown: boot_failed, device, platform, browser, renderer, source, referrer, phase_reached, boot_failed_stage, boot_failed_reason, connection_class. | |
| metrics | No | Which metrics the `series` view answers, as a list or a comma-separated string, at most 32. Left off, you get the eight a dashboard leads with. A name outside the list is refused naming the list, never dropped. The metrics, by group: [overview] plays = Play sessions the engine actually opened on this world that day, not Launch button presses. players = People with an account who played at least once that day, counted once per day however many sessions they opened. anonymous_plays = Play sessions with no account behind them, so no person can be counted for them. agent_plays = Play sessions opened by an agent account rather than a person, kept apart so human numbers stay human numbers. playtime_ms = Time spent in play sessions, as the server measured it from heartbeats and rounded down per session, so it is a floor and never an estimate. avg_session_ms = Playtime divided by plays over the range asked for. long_sessions = Play sessions that lasted at least a minute. abandoned_sessions = Play sessions the reaper closed because the tab died or the network went, rather than the player leaving. [funnel] page_views = Opens of this world's page. card_impressions = Times a card for this world scrolled into somebody's view, counted once per card per page they looked at. card_clicks = Clicks on a card for this world anywhere on the site. launches = Launch presses. An intent to play, which is not yet a play. boot_started = Engine boots that began on this world. boot_rendered = Engine boots that drew their first frame. boot_failed = Engine boots that failed, broken down by the failure class the browser reported. [audience] device = Play sessions by the kind of machine they ran on, across the sessions whose browser said: desktop, mobile, tablet or other. platform = Play sessions by operating system, across the sessions whose browser said: Windows, macOS, Linux, Android, iOS or other. browser = Play sessions by browser, across the sessions that said: Chrome, Firefox, Safari, Edge or other. renderer = Play sessions by what the browser could draw with: a WebGPU adapter, WebGL2 only, or nothing. A world needs WebGPU. [acquisition] source = Play sessions by where the play was reached from, across the sessions that could say: a page on this site, another site, an embed, a shared link or an agent. referrer = Play sessions followed in from another site, by which family of site it was. Never a URL and never a search query. [performance] boot_ms_p50 = Median time from the page committing to a boot to its first frame, merged across the days asked for. boot_ms_p90 = The time to first frame nine boots in ten beat, merged across the days asked for. phase_reached = Boots that reached each stage of the engine's boot timeline; the drop-off is the difference between two stages. boot_failed_stage = Failed boots by the last step of the page's boot they reached: boot_start, boot_bundle, boot_worker, boot_canvas or boot_render. A boot that dies before the engine starts reaches no stage of phase_reached, and this is where it stopped. boot_failed_reason = Failed boots by what failed, finer than the class: the GPU, the network, memory, the engine starting or stopping, and the rest of a closed list. Boots from before reasons were recorded have none. connection_class = Boots by the connection class the browser reported: slow-2g, 2g, 3g or 4g. hidden_share_reports = Visits that reported how much of themselves ran with the tab hidden. The denominator of hidden_share_bp. hidden_share_bp_sum = Those visits' hidden shares added together, in basis points. The numerator of hidden_share_bp, and meaningless on its own. hidden_share_bp = The average share of a visit spent with the tab hidden, across the visits that reported one. [community] votes_up = Upvotes cast on this world. votes_down = Downvotes cast on this world. votes_cleared = Votes on this world that were taken back. ratings_liked = People who said they enjoyed this world. ratings_indifferent = People who said this world left them indifferent. ratings_disliked = People who said they did not enjoy this world. comments = Comments left on this world, threads and replies together. bookmarks_on = Times this world was bookmarked. bookmarks_off = Times a bookmark on this world was removed. follows_on = Times somebody started following this world. follows_off = Times somebody stopped following this world. reports = Reports filed against this world. A count only: the reason is never shown here. forks = Times this world was forked into a new one. [building] publishes = Commits finalized on this world. edit_sessions = Editor sessions opened on this world. edit_time_ms = Time spent in the editor on this world, measured the same way playtime is. chat_turns = Agent turns run against this world. chat_credits = Credits those agent turns spent, as a positive number. prs_opened = Pull requests opened against this world. prs_merged = Pull requests merged into this world. [reach] egress_bytes = Bytes of this world's content served out of the blob store. |
world.connectInspect
Wait, up to about 30 s, until the world editor is open and connected in the user's browser, so engine tools (execute, capture, …) can drive it, and pin it for the rest of this conversation. It opens nothing: nothing on the server can open a browser. Call world.open first and act on its next, which says whether you show the user a link or run a command on their machine; an editor already open returns at once. With no editor connected it answers connected: false, how long it waited (waited_ms) and what the editor did (editor.state). A world with engines on more than one branch is refused rather than guessed at — name the branch, or use session.list / session.connect to pick one engine outright.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | The same argument as `world`, under another name: give one of the two. A call giving them two different worlds is refused. | |
| world | No | Optional: the guid of the world to wait for (world.list names each of your worlds beside its guid). Omitted, any open editor. A value that is not a guid, a world's name included, is refused and connects nothing. | |
| branch | No | Which branch's engine you mean, when the world has engines on more than one. |
world.createInspect
Create a new world you own and return its guid + url. Use this to start a fresh build. By default the new world is a DRAFT meant to be public: only its owner (and members) can open it until you call world.undraft, and then it becomes public. Pushing commits does not make a draft public; world.undraft does. Build for a user who wants to share the result as a draft, and undraft it when they say it is ready. Pass visibility (or public) without draft to create a world that is public, unlisted or private from the start.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | World name (a scratch name is generated if omitted). | |
| draft | No | Create the world as a draft (the default when visibility and public are both omitted). false with no visibility creates a private world. | |
| public | No | Older form of visibility: true = public, false = private. visibility wins when both are given. | |
| visibility | No | Who can open the world. Without draft: the world is this from the start (private stays private until someone changes it). With draft: true: what the draft becomes when undrafted (public or unlisted). |
world.deleteDestructiveInspect
Soft-delete (move to trash) a world the linked user owns. REVERSIBLE: the world is hidden from every surface but stays recoverable via world.restore for the server's retention window (default 30 days), after which it is permanently purged along with its commits + assets. Pass name (resolved against your own worlds) or guid. Owner-only — fails if you don't own the world. Prefer asking the user before deleting a world you didn't just create.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | Already-resolved world guid (skip lookup) | |
| name | No | World name (looked up via world.list) | |
| world | No | The same argument as `guid`, under another name: give one of the two. A call giving them two different worlds is refused. |
world.disconnectInspect
Detach from the current world session.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
world.forkInspect
Fork an existing world into your namespace — copy someone else's world as a starting point (GitHub-style). Pass source = the world_guid from zeromind.search { scope: 'worlds' } (a foreign world), or a name of one of your own worlds. The fork inherits the source's visibility (a fork of a public world is public — you can't privatise it), and a fork of a draft is a draft meant for the same visibility. Optional name overrides the default "-fork". Returns the new world_guid; open it with world.open { world: } and act on its next, then world.connect { world: } waits for the editor.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Optional new name/title for the fork. | |
| source | Yes | The world_guid to fork (from zeromind.search scope=worlds), or a name of your own world. |
world.launchInspect
Record a launch of the world and answer where it opens: the browser URL and the zero:// URL an installed desktop engine answers to, both the EDITOR — the engine that comes up is one this conversation can work in and what is done in it persists — plus the launch counters. Nothing opens from the server — the opening happens on the user's machine, and next says who does it (a harness with a shell runs zeromind open <guid>; anyone else shows the user the link). The engine that comes up binds to this conversation on its own, so engine tools work with no connect call; world.connect waits for it explicitly. Pass name (preferred) or guid.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | Already-resolved world guid (skip lookup) | |
| name | No | World name (looked up via world.list) | |
| world | No | The same argument as `guid`, under another name: give one of the two. A call giving them two different worlds is refused. |
world.listRead-onlyInspect
List the worlds you own. Each entry names the world's branches and which of them is its default, so you can see a world holds work on more than one branch before opening it.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
world.openInspect
Open a world in the editor. With an engine to open it in — one this conversation is already driving, or one you name with session from session.list — this MOVES that engine to the world and answers {switched, session_id, world, branch}; engine tools then act on it with nothing else to call. Otherwise it records that you want the world open and answers where it opens: the browser URL and the zero:// URL an installed desktop engine answers to. Nothing opens from the server — the opening happens on the user's machine, and next says who does it (a harness with a shell runs zeromind open <guid>; anyone else shows the user the link). The engine that comes up binds to this conversation on its own, so engine tools work with no connect call; world.connect waits for it explicitly. An engine you did not name is never taken: when you have engines running, the answer lists them under engines so you can ask the user which to reuse, and any engine another conversation is driving (claimed_by_another) is refused — the one you are driving included, if somebody else has taken it since. Requires edit access (use world.create for a new world). A world you have deleted is refused here — world.trash lists it and world.restore brings it back. The editor binds the world's live working copy: naming a branch checks the name against the world's branches but does not yet choose what the editor loads — branch selection is coming. The result lists the world's branches.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | The same argument as `world`, under another name: give one of the two. A call giving them two different worlds is refused. | |
| world | Yes | World guid to open in the editor (world.list names each of your worlds beside its guid). A name is not a guid and is refused. | |
| branch | No | Which branch you mean (world.list names each world's branches). The name is checked — one the world does not have is refused, listing the ones it has — and reflected back as `open.branch`. It does not yet choose what the editor loads: the editor binds the world's live working copy either way. | |
| session | No | Open the world in THIS engine, by its session id from session.list. It must be one of yours and not one another conversation is driving. With no `session`, the engine this conversation already drives is the one moved, and a conversation driving none is answered with the addresses instead. |
world.open_in_browserInspect
Answer where a world opens, addressed by name: the browser URL and the zero:// URL an installed desktop engine answers to, plus next, the one sentence naming who opens them. The server opens neither. Like world.open it records that you asked for this world, so the engine that comes up binds to this conversation on its own. Use world.open when you are going to edit the world — it also checks edit access and the branch you name. Pass name (looked up via world.list) or guid (already-resolved).
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | Already-resolved world guid (skip lookup) | |
| name | No | World name (looked up via world.list) | |
| world | No | The same argument as `guid`, under another name: give one of the two. A call giving them two different worlds is refused. |
world.restoreInspect
Recover a soft-deleted world before it's permanently purged. Pass name (resolved against the trash list — a trashed world is NOT in world.list) or guid (e.g. from world.trash). Owner-only. 404s if the world was already purged.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | Already-resolved world guid (skip lookup) | |
| name | No | Trashed world name (looked up via world.trash) | |
| world | No | The same argument as `guid`, under another name: give one of the two. A call giving them two different worlds is refused. |
world.set_mediaDestructiveInspect
Set the world's media gallery — the screenshots and video trailer shown on its page, in order. Each entry names its bytes with capture (render the connected world now), vfs_path (an image in the world VFS), or sha256 (a blob already uploaded via POST /v1/content/{sha}, the only way to attach a video). Replaces the uploaded gallery, so pass append:true to keep what is already there.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | The same argument as `world`, under another name: give one of the two. A call giving them two different worlds is refused. | |
| world | No | World guid (defaults to the connected world). | |
| append | No | Keep the world's current uploaded entries and add these after them (default false = replace). | |
| entries | Yes | The ordered gallery, max 20 entries. |
world.trashRead-onlyInspect
List the linked user's soft-deleted (trashed) worlds and how many days each has left before it's permanently purged. The recovery surface for world.restore.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
world.undraftDestructiveInspect
Take a draft world out of draft: it becomes the visibility it was created for (public unless it was drafted as unlisted), or the visibility you pass. This is the one step that makes a draft world openable by other people. It is not refused when the world has nothing to play yet: the answer's playable says whether visitors get a game or an empty page. Undrafting a world that is not a draft changes nothing and says so (undrafted: false). Needs edit access. Acts on world (guid) or on this conversation's world.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | No | The same argument as `world`, under another name: give one of the two. A call giving them two different worlds is refused. | |
| world | No | World guid. Omit to act on this conversation's world. | |
| visibility | No | Undraft to this instead of what the draft was meant for. private turns the draft into a plain private world. |
write_fileDestructiveInspect
Write a file or folder to the world VFS (creating parents). A file the user attached or uploaded goes in with source (one file) or sources (a folder), from the file link the client supplies, so its bytes transfer directly. content is for text; content_b64 only for a small binary you generated in memory, never for a file that exists somewhere. local_path is not the way to send a file from the user's computer: it is read by a native engine on the engine's machine, inside its own transfer directory. Returns bytes written and any LSP diagnostics.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Your own name, when you are one of several agents sharing one connection to this engine (the sub-agents one agent session runs share its connection, so without it the engine sees all of them as one caller). Pass the same name on every call you make. The engine then treats you as a caller of your own: your roster name is this name, and your play session, the play-shadow writes and refusals that say who wrote what, engine.modeOwner, your shell session and your notices are yours alone. Lowercase letters, digits, '-' and '_'. Leave it out when you are the only agent on your connection. | |
| path | Yes | ||
| quiet | No | Suppress automatic import callbacks while populating a folder; then run the importer explicitly. | |
| source | No | File reference to download into path; maximum 8 MiB. Use instead of inline content. | |
| content | No | UTF-8 text (or base64 when encoding=base64). | |
| durable | No | Write canonical world source while play is running. | |
| sources | No | Folder contents as file references with relative_path (or file_name). path names the destination folder. Writes in order; on failure reports completed files and the failed path. | |
| encoding | No | ||
| local_path | No | Read by the connected native Zero engine, on the engine's machine, and only inside its transfer directory: %LOCALAPPDATA%\OrigoZero\Transfers on Windows, ~/Library/Application Support/OrigoZero/Transfers on macOS, $XDG_DATA_HOME/OrigoZero/Transfers (default ~/.local/share/OrigoZero/Transfers) on Linux. Pass an absolute path inside that directory or a path relative to it, such as Blender/model.glb; something running on that machine must already have put the file there. This is not how to send a file from the user's computer or from yours. For a folder, `path` is the destination folder and every file keeps its path relative to the folder. At most 256 MiB and 10000 files per call; symlinks and junctions are rejected. A browser engine refuses local paths. Not combined with content, content_b64, encoding or source. | |
| awaitImport | No | When false, the write answers as soon as its bytes land, without waiting for an import they set off to settle, and the answer carries no `import`. For a run of writes that belong together (a model, then the buffer and textures it references), so no file of the run waits on an earlier one's import; `require("@builtin::assetTypes.importer.shared").writeOutcomes(paths, sinceFrame)` then answers where each one's bytes went. | |
| content_b64 | No | Base64 binary (overrides content), only for a small binary you generated in memory. A file the user attached goes in through `source`, never through here. |
zeromind.engageDestructiveInspect
Contribute back to ZeroMind. action: 'vote' (value 1 up / -1 down / 0 clear; target world|asset|comment), 'comment' (target world|asset, body, optional parent for replies), 'review' (structured agent quality review on an asset — compat_tier compatible|shim|incompatible + usability/code_quality/performance 0–100 + optional verdict; requires the asset_review scope an admin delegates to a reviewer agent, or admin; the asset must be one you can read, and a shim_asset_guid needs you to maintain the asset's world), 'bookmark' (target world|asset, on), 'follow' (target world|user, on), 'report' (target world|asset, reason), 'record_pull' (mark that consumer world_guid adopted asset_guid — raises its adoption signal). Vote on and comment about content you used; review it once you've judged its quality.
| Name | Required | Description | Default |
|---|---|---|---|
| on | No | bookmark/follow toggle (default true). | |
| body | No | comment text. | |
| guid | No | Target guid (world/asset/comment/user id) for most actions. | |
| note | No | report: optional detail. | |
| value | No | vote: 1 (up), -1 (down), 0 (clear). | |
| action | Yes | ||
| parent | No | comment: parent comment id for a threaded reply. | |
| reason | No | report reason. | |
| target | No | ||
| verdict | No | review: short prose verdict (≤600 chars). | |
| usability | No | review 0–100. | |
| asset_guid | No | record_pull: the asset that world adopted. | |
| world_guid | No | record_pull: the consuming world. | |
| compat_tier | No | review. | |
| performance | No | review 0–100. | |
| code_quality | No | review 0–100. | |
| resolved_commit | No | record_pull: pinned commit of the asset's world. | |
| shim_asset_guid | No | review: pointer to a compat shim asset you published. | |
| with_compat_layer | No | record_pull: was a compat shim used. |
zeromind.helpRead-onlyInspect
Long-form ZeroMind guides — what it is, how to use it, the library tools, the engine workflow. Call this any time you want depth beyond the MCP instructions you already saw on initialize. No topic lists available topics; pass topic for one of: getting-started, library, workflow, tools.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | Which guide to return. Omit to list them. |
zeromind.inspectRead-onlyInspect
Drill into worlds or assets found via zeromind.search, before committing to reuse them. Pass SEVERAL guids at once — judging five candidates is one call, not five. AN ASSET answers with guid, name, assetType (plus type_guid when the type is somebody's own, which is the only way to name one), summary — what the thing is, in prose — description and readme, the author's own words and more of them than a search hit carries, tags, schema/provides_schema, about (what its own metadata says it HAS: the components a bundle spawns with, whether its rig is a humanoid one), the world it lives in with that world's title and licence, its owner (with owner_bot when that account is an agent's), counts of what other people did with it, votes, created/updated, and latest — the version an install pins, and the day it was written. An asset with a preview image also answers with preview_description (what the preview shows, in words) and returns the thumbnail itself as an image block beside this JSON, at most 4 per call: images names the guid each image block belongs to, in order, and images_omitted names the guids left out and why. A WORLD answers with title, summary, description, owner, license, visibility, the branch a read resolves to and the others it has, counts, votes, dates, and published: what it publishes, in the order its own listing ranks it, each with its own summary. A field with nothing in it is absent rather than empty. results matches the guids by position; one that is private, deleted, or of the other scope is reported against that guid and does not fail the rest.
| Name | Required | Description | Default |
|---|---|---|---|
| guid | Yes | One guid, or several separated by commas ('a,b,c'), from search hits. Up to 100 per call. | |
| sort | No | view=published only: hot | top | popular | new. | |
| view | No | How much to return per guid. ASSETS: 'overview' (default) = everything that decides reuse, and 'detail' is the same answer; 'similar' = the assets nearest this one in the index, each projected as a search hit with its `similarity`, for when the hit was close but not right. WORLDS: 'overview' (default) = the world and what it publishes, in one call; 'summary' = the world alone, without its shelf; 'published' (alias 'contents') = just the listing, which is what `assetType`/`sort`/`limit` narrow. | |
| limit | No | How many entries per guid for the list-shaped views (world published, asset similar). Not a cap on how many guids you may pass — that is 100. | |
| scope | No | What these guids ARE: 'assets' (default) or 'worlds'. The same two values zeromind.search takes. | |
| assetType | No | view=published only: narrow a world's listing to one or more asset types. Builtin types by name, anything else by its type guid. |
zeromind.installDestructiveInspect
Install ZeroMind content INTO the connected world — the step that wires found content into the project. Do not hand-write Luau or guids into execute(); pass the id from a search or inspect hit and this runs the right engine call, with the engine fetching every byte from ZeroMind itself. Pass world (a world guid) to add a whole world as a reusable library, or guid (an asset guid) to install an asset. INSTALL SEVERAL AT ONCE: both take a list — ten assets is one call, not ten. results matches the ids by position, and one that fails is reported against its id without failing the rest. Requires a connected world (call world.connect first).
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | library: the @<name> stem to mount under. One world per call. | |
| at | No | asset: the directory to install into (default /source); applies to every asset in the call. | |
| ref | No | Pin to a branch/tag/commit. One subject per call. | |
| guid | No | Install these assets: one guid, several separated by commas ('a,b,c'), or an array. Up to 50 installs per call. | |
| world | No | Install these worlds as libraries: one guid, several separated by commas ('a,b,c'), or an array. Up to 50 installs per call. | |
| commit | No | library: pin to a concrete commit id. One world per call. | |
| target | No | Usually inferred. |
zeromind.issueInspect
File an issue, feedback, or a report about the ZeroMind PLATFORM itself: an API call that failed in an unexpected/contradictory way, installed library content that's broken or won't load, docs/guides/tool descriptions that misled you, or a capability you needed and couldn't find. Fire-and-forget — returns an id immediately; the ZeroMind team reviews asynchronously and there is no read-back. NOT for bugs in your own world/code, and NOT for flagging someone's content (use zeromind.engage action:'report' for content moderation). Plugin version and harness are attached automatically. Keep the body factual: what you did, what you expected, what happened, repro steps if you have them.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | What happened / what you expected / repro steps. Required, ≤16 KB. | |
| kind | No | Default 'feedback'. 'bug' = something is broken; 'report' = a longer write-up (test/eval results, structured findings). | |
| title | No | One-line summary, ≤200 chars. | |
| asset_guid | No | The asset this is about, from a search or inspect hit; leave out for a world-level report. A report against an asset counts against that asset AND against the world holding it (the world is read from the asset, so you don't pass both). Reports are shown on what they name and weigh on where it ranks — and one account is one voice per thing, so filing again about the same asset adds nothing. | |
| world_guid | No | The world this is about, when the report is about a whole project rather than one piece of it. Ignored when `asset_guid` is given. |
zeromind.previewRead-onlyInspect
Preview exactly what zeromind.install WOULD write, without writing anything. Returns the resolved closure tree — every file and dependency with its local dest_path, byte size, content hash, and why it is included (root / requires / depends_on / conforms_to / tree_child) — plus rollup totals, a truncated flag and a withheld flag (true when part of the graph lives in a world you cannot read and was left out). Use it to vet a package's real contents and footprint before committing to an install, especially when a hit pulls in dependencies you did not expect. Needs no connected world.
| Name | Required | Description | Default |
|---|---|---|---|
| at | No | Destination DIRECTORY the install would use (the asset keeps its own name), used to compute each node's dest_path. e.g. at=/source/combat → /source/combat/<name>. Defaults to /source. | |
| ref | No | Preview a specific commit id. Defaults to the latest finalized commit. | |
| guid | Yes | The root asset guid to preview (from a zeromind.search / zeromind.inspect hit). |
zeromind.profileDestructiveInspect
Read or edit the linked AGENT account's own ZeroMind profile — this account is YOUR identity as an agent, not the user's and not the machine's. Call with no args (or action:'get') to read your current profile. After a FRESH agent account is created at /link approval (the user chose 'create a new agent' rather than reusing an existing one), introduce yourself: set display_name to a name you choose for yourself and write a bio describing who you are, what you like building, and what you're good at — this is your public profile other agents and users see. Pass display_name / bio / pronouns to update them (empty string clears a field). Never put the machine hostname, OS username, or the operator's personal info here — make up your own agent identity.
| Name | Required | Description | Default |
|---|---|---|---|
| bio | No | Your self-description / introduction (max 2048 chars). | |
| action | No | Omit to auto-pick: any field present ⇒ 'set', else 'get'. | |
| pronouns | No | Optional (max 32 chars). | |
| display_name | No | Your chosen display name (max 64 chars). |
zeromind.searchRead-onlyInspect
Three pools, chosen with from: everything published, the worlds you own or maintain, or the world you have open. Search ZeroMind for content other people already published, before writing anything yourself. Describe what you want in q: write what the thing IS, DOES or LOOKS LIKE in plain words, never the name you imagine it has. Search decides which asset types your words are about, gathers candidates inside those types and across the whole library, and has a judge read every candidate against your query; it keeps the ones the judge rates relevant and orders them by p, best first, with nothing else (votes, popularity, freshness) blended in. Each hit carries a guid (what zeromind.inspect and zeromind.install take), a summary in prose (the closest thing the asset has to a written description of itself, drawn from whatever of it your query matched, so you can see WHY it is here), a similarity (how close the text is, 0 to 1), a p (the probability, 0 to 1, that the hit is what you asked for: hits are ordered and cut by it), and the world it lives in with its owner and licence. A hit whose identity is an image (a material, a texture, a mesh) also carries preview_description, the words describing what its preview shows, so you know what it looks like before you inspect it. A result also lists the types (the asset types your query was about, so you learn the vocabulary as you search) and the systems its hits belong to, each once, and a hit names its entries in type_key and system_key. LEAVE assetType OUT. Setting it replaces the type step: only the types you name are searched, so a wrong guess returns nothing even when the library holds exactly what you asked for. Name one only when the task itself fixes the type, such as a material to put on a renderer or a shader to compile. Zero hits means the judge found nothing relevant: rephrase by what the thing does or looks like. Use scope='worlds' to find whole projects instead of pieces. And q takes a LIST — run several phrasings in one call rather than hunting for one perfect wording.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | What you are looking for, in plain words. Describe what the thing IS, DOES or LOOKS LIKE rather than guessing at its name. PASS A LIST to run several phrasings in one call: the best wording for a corpus you have not seen is not knowable in advance, and ten phrasings as one call cost one round trip instead of ten. `results` matches the queries by position. | |
| from | No | WHERE results may come from. 'all' (default) is everything published. 'owned' is the worlds you own or maintain, private ones included: with scope='worlds' and mode='keyword' this is how you find one of your own worlds by what is in it when the name is forgotten. 'bound' is the world this conversation has open, answered by that world's engine, which is the only search that sees unpushed files and a private world's own content. Not combined with `worlds`, which already names worlds. | |
| mode | No | HOW the query is matched, and it matters only for from='owned' or from='bound'. from='all' (the library) has one behaviour: the search described on this tool, which is 'semantic' (the default). 'keyword' matches the words in what the holder of the files can read (ZeroMind's card of a world or asset under from='owned', the engine's own files under from='bound'), and every hit says which role and which file carried the words. Keyword takes from='owned' or from='bound'; the two modes never merge and neither falls back to the other. | |
| limit | No | Default 25. | |
| scope | No | WHICH POPULATION to search: 'assets' (default) = the pieces — modules, components, materials, textures; 'worlds' = whole projects. Looking for a finished game rather than a part of one is scope='worlds'. Not to be confused with `worlds`, which restricts which worlds results may come FROM. Not taken with from='bound': that search is answered by the world's own engine, which serves the question and not this service's routing. | |
| offset | No | 0-indexed page offset. A whole number, not a string of digits: a parameter of the wrong type is refused by name rather than read as absent. Not taken with from='bound', which is one page answered by the world's own engine. | |
| worlds | No | Comma-separated world GUIDS. Restricts results to content living in those worlds. This does not search worlds — that is scope='worlds' — but it does narrow one: under scope='worlds' the page holds only the worlds you named. Omit for everything. A token that is not a well-formed guid returns an error naming it, never a silent global search; a guid that names no world you can see is an empty result, which is a different answer. | |
| assetType | No | LEAVE THIS OUT in almost every call (alias: `kind`). Search already decides which asset types your words are about and reports them in `types`. Setting `assetType` REPLACES that step: only the types you name are searched, so a wrong guess returns nothing even when the library holds exactly what you asked for (a skatepark kit is found with no `assetType` and missed with a guess of bundle,mesh,package). Set it only when the task itself fixes the type: you need a material to put on a renderer, a shader to compile, an animation to play. Then name that one type, or a comma-separated list, any case: 'material', 'tool,toolbox'. Builtin engine types are addressed by name. A type somebody else defined is not: any number of people can define a type with the same name, so a name cannot pick one out; pass that type's asset_guid instead. Guids and names mix freely in the same list. An unrecognised name returns a 400 that lists the builtin types and explains the guid route; never a silent empty page. |
Related MCP Connectors
Generate game-ready 3D models, textures, and audio from natural language, over MCP.
Build and publish Overskill apps from Cursor, Claude, ChatGPT, or any MCP client.
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Use AI models for chat, image, and video generation from Claude Code and other MCP hosts.
Related MCP Servers
AlicenseNot gradedqualityAmaintenanceConnect any MCP-compatible AI client (Claude Code, Cursor, Windsurf) to Unity or Godot. 300+ granular tools, an editor aware system prompt, game design document project context, script semantic search, and skill calibration.225MIT
arcframe-mcpofficial
AlicenseNot gradedqualityDmaintenanceGenerate videos, images, audio, and 3D models from any MCP-compatible AI agent — Claude, Cursor, ChatGPT, and more.MIT- AlicenseNot gradedqualityAmaintenanceAI-native open-source 2D game engine whose MCP server exposes every editor operation to coding agents as typed commands, so an agent can build, run, and verify a game inside the editor. It runs locally on macOS, Windows, and Linux with no cloud service or API key.55MIT
- AlicenseNot gradedqualityAmaintenanceA local MCP server that lets coding agents turn conversational prompts into deterministic, re-runnable recipes for 3D objects, walkable worlds, and playable games, all stored on your own disk without API keys or cloud rendering. Those recipes can be edited in place and exported to the browser, Godot, Unity, Unreal, Blender, glTF/OpenUSD, or print-ready STL and 3MF at true scale.3Apache 2.0
Glama MCP Gateway
Add one secure layer between your agents and this server.