How we build a living grid presence in Luau
The working notes behind inworld.help — bots, a viewer, a hub, and one scripting language everywhere.
2026-08-12
This is a high-level sketch of the system we operate and how we develop it. It is written to be read quickly by an
unfamiliar AI or engineer — enough to know what exists, why it's shaped that way, and
how work moves through it — without drowning in the API surface.
The thing, in one breath
We run a presence on the grid — a set of bots and a viewer — all scripted in
Luau (Roblox's flavor of Lua, chosen because it is fast, sandboxed, and
typeable). Every script talks to the grid through a single global table, client. Every bot and the viewer
can be driven over one central hub, which routes control requests and exposes a
Model Context Protocol (MCP) API so that AI tooling — and we ourselves —
can drive any of them.
The key point: none of this needs a remote server. A bot runs just as well on a local machine — a
laptop, a home box — with or without a hub in the middle. The remote host is optional; it exists only for the bonuses
it adds (a stable public presence, a persistent relay, MCP exposed over the network, many hosts reachable from one
door). If you only need a local bot that reads a parcel and sends you an IM, you can run it entirely on one machine
and never touch a server.
Bots — headless grid clients running on a server, driven by Luau services.
Viewer — a full grid client with an embedded VM; it implements the same
client surface, so the same script runs on either host.
Hub — a WebSocket relay + MCP server. Registers every bot and viewer, routes control, persists state.
Luau — the one language for scripts, services, and our own tooling. No Python in the workflow.
One contract, many hosts
The core design bet is a single scripting contract. A bot embeds a Luau VM behind a C-ABI shim; the viewer embeds the
same VM over its C++ managers. Both expose the same client table — chat, movement, inventory, objects,
marketplace, web, RLV lockdown, timers, and a raw packet escape hatch. Because the surface is identical, a
script written against the reference runs verbatim on either host; only the binding code beneath differs.
This matters for how we work: we can develop and verify behavior on a cheap, disposable bot, and know the same script
behaves on the interactive viewer. The full binding reference lives at
dev.inworld.help/ukulele.
The three places we run code
- Server — a VPS hosting the hub and the bot fleet. Services start at login, run on timers and
event handlers, and are controllable live over MCP. This is the optional, "for the bonuses" host — convenient when
you want a permanent presence and a reachable door, but not required.
- Viewer (laptop) — the interactive client the operator sits in. It hosts Luau services too, loadable
at login or hot-swapped live over the hub without a restart.
- Laptop tooling — a standalone Luau runtime for scripts, one-off automation, and the local half of
our MCP bridge. Everything we build by hand is Luau.
A local-only setup simply runs a bot and its services on one machine, talking straight to the grid — no hub, no
server. The hub becomes relevant when you want many hosts coordinated, state persisted centrally, or the whole fleet
reachable through one MCP endpoint.
How control flows
Locally, a bot runs its own services against the grid directly. Add a hub and it becomes the nerve center: a bot
registers under its grid username, the viewer registers too, and the hub relays requests to any of them — so many bots
and viewers are drivable at once, over MCP tooling (reachable over HTTP) or directly. Anything without a typed binding
is reachable through the raw-packet surface: subscribe to or send any classic-UDP packet by name.
The workflow
We develop in a tight loop:
- Write Luau — a script, service, or tool, targeting the
client contract.
- Compile-check — a fast static pass catches type and syntax errors.
- Run against a live host — eval a snippet on a bot, or hot-reload a viewer service in place.
- Verify, don't trust — a clean build is not a working feature; we confirm the behavior actually
shows up over the hub.
Pure-Luau changes hot-reload with no restart. Only changes to the bindings surface itself need a rebuild.
Reusing code, the Luau way
We don't drop to Python for libraries. Lute ships a package manager
(Loom) that pulls third-party Luau/Lua code straight from GitHub pinned by commit SHA — our native
stand-in for pip install. Most pure-Lua 5.1 libraries drop in with a thin shim. The standing rule:
if it can be done in Luau, it is done in Luau.
The repositories we lean on
Most of what we build is a thin layer over a handful of open-source projects. Knowing which is which helps place
everything else.
- Luau — the language itself. Roblox's sandboxed, typed Lua. This is
the cement: it is what every script and tool is written in. It is also what lets a contract like
client exist at all — the script is the product, the host is interchangeable.
- Lute — a standalone runtime for Luau (think Node,
but for Luau). Gives Luau a file system, networking, and HTTP — the "general-purpose programming" half that the
sandbox deliberately omits. Our laptop tooling and the local MCP bridge run on it.
- LibreMetaverse — the grid protocol
library. A bot is LibreMetaverse with a Luau VM bolted on; it handles the actual talk to the grid, and it is the
reference for the
client surface.
- Alchemy (viewer) — the full interactive
grid client we embed the same VM into. Because it implements the same
client contract over its C++
managers, scripts run on the interactive viewer exactly as they do on a headless bot.
- Loom — Lute's package manager. Our path to third-party code: it pulls Luau/Lua libraries straight
from GitHub pinned by commit SHA, so a library is a real, versioned dependency rather than a copy-paste. This is the
biggest single unlock for "no Python in the workflow."
- MCP (Model Context Protocol) — the standard for AI
tool access. The hub exposes its control surface as MCP tools, which is what lets an AI assistant — or us — drive bots
and viewers through one door.
The pattern to notice: small, focused open-source cores (a language, a runtime, a grid protocol
library, a viewer, a package manager, an AI-tool protocol), and our work is the thin, opinionated layer that wires them
together with one scripting contract and one workflow.
The short version
Bots and a viewer, all scripted in Luau against one client contract. A local bot runs fine on its own —
the hub and remote host are an optional layer that adds coordination, a persistent public presence, and an MCP door. We
develop in Luau end to end, verify live, and reuse third-party code without leaving the language. That's the whole
shape of it.
Want the API details? The Luau/LibreMetaverse
client reference and the
MCP server usage guide. The grid protocol itself is
LibreMetaverse, and the language is
Luau.