Skip to content
Game dev

Roblox pure Luau modules checked outside Studio

Keep Roblox game rules in pure --!strict Luau modules that the luau CLI can type-check and test in milliseconds, with a scanner that keeps Roblox APIs out of them.

Verified install Not agent-tested v1.0.0 MIT updated robloxluaurojo
Equips
  • 2 2 Rules
  • 1 1 Skills
  • – 0 MCP

Roblox logic is usually tried out by pressing Play in Studio, which an agent can't do after every change. Rules that never touch the DataModel can be checked by the standalone Luau tools instead: luau-analyze type-checks them in strict mode, and luau runs their tests from the command line.

This loadout sets out the split. Prices, inventory, damage and cooldown maths go in src/shared/pure as --!strict modules that require each other by string (require("./Money"), which Roblox and the luau CLI both resolve). Server and client scripts stay as thin edges that own services, Instances and remotes. A standard-library Python scanner flags Roblox-only calls in the pure folder (game, workspace, script.Parent requires, Instance.new, services, task and the deprecated wait/spawn/delay, Roblox datatypes) as errors, and math.random, os.time and print as warnings. A small test runner prints PASS or FAIL per case and exits non-zero on failure. The verifier runs it all with the official Luau 0.743 tools on a Rojo shop project, and shows a broken rule failing the run.

What's in it

  • Pure --!strict modules in src/shared/pure, thin edge scripts for Roblox APIs
  • Scanner flags game, script.Parent requires, Instance.new and task.* in pure code
  • luau-analyze --mode=strict checks the rules and their tests outside Studio
  • A tiny test runner for the luau CLI that exits non-zero on failure
  • String requires that work in both Roblox and the luau CLI

You'll need

  • Tools: python3, luau
Level 1 · automated

Verification

Verified install

Checked at commit cc18d7e · 9 passed, 0 failed, 1 not applicable

CheckResultWhat we found
Listinglisting.yaml matches the schema and declares every file in the folder. Pass
Schema valid; 8 files declared, none missing or extra
  • tested.status: untested (agent tests are separate from Level 1)
Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. Pass All 8 files parse; front matter valid
AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. Pass
CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
  • CLAUDE.md: matches the generator
  • GEMINI.md: matches the generator
Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. Pass
Correct paths for all 6 agents; layouts re-discovered
  • Claude Code: 6 files, 1 skill in .claude/skills/
  • Codex CLI: 5 files, 1 skill in .agents/skills/
  • Cursor: 6 files, 1 skill in .agents/skills/, 1 rule
  • Gemini CLI: 6 files, 1 skill in .agents/skills/
  • Antigravity CLI: 5 files, 1 skill in .agents/skills/
  • GitHub Copilot: 5 files, 1 skill in .agents/skills/
MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. Not applicable No MCP servers in this loadout
Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode, instructions hidden in HTML comments or after long blank padding, or prompt-injection and covert wording (such as telling the agent to keep something from you), and the listing's network flag is honest. Pass
Clean: no credentials, risky shell, hidden text or covert instructions
  • Scanner intake-precheck/2: verdict clean; network no (listing says no)
ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. Pass 1 reference between files resolves for every agent
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
8 files, 13.9 KB total; largest skills/luau-pure-tests/scripts/pure_luau_guard.py 5.7 KB
  • Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule
LicenceA recognised SPDX licence, with the licence text available. Pass MIT, by SetupBay; text in the repository LICENSE
Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. Pass
pure_luau_guard.py passes the shop's pure modules and flags every Roblox-only line in the skill's Studio-coupled sample: 13 errors and 2 warnings. With the official Luau 0.743 tools, luau-analyze --mode=strict passes the pure modules and their tests and rejects the sample's game, script and Instance
  • Applied 12 loadout files at every agent's paths
  • luau 0.743
  • ✓ scanner: the pure modules are clean: bash -c python3 .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py src/shared/pure; echo "exit=$?"
  • ✓ scanner: the Studio-coupled sample is flagged line by line: bash -c mkdir -p coupled && cp .claude/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt coupled/InventoryOld.luau && python3 .claude/skills/luau-pure-tests/scripts/pure_luau_guard.py coupled; echo "exit=$?"
  • ✓ place the skill's test runner: bash -c cp .agents/skills/luau-pure-tests/references/run.luau tests/run.luau && echo placed
  • ✓ luau-analyze --mode=strict: pure modules and tests type-check: bash -c "$(dirname "$LUAU_BIN")/luau-analyze" --mode=strict src/shared/pure tests; echo "analyze=$?"
  • ✓ luau-analyze --mode=strict: the sample's Roblox calls don't resolve outside Studio: bash -c "$(dirname "$LUAU_BIN")/luau-analyze" --mode=strict coupled/InventoryOld.luau; echo "analyze=$?"
  • ✓ luau runs the tests outside Studio: bash -c "$(dirname "$LUAU_BIN")/luau" tests/run.luau; echo "exit=$?"
  • ✓ a broken rule fails the run: bash -c cp -r src broken-src && sed -i 's/math.floor(price/math.ceil(price/' broken-src/shared/pure/Money.luau && sed 's#../src/#../broken-src/#' tests/Money.spec.luau > tests/Broken.spec.luau && sed -i 's#require("./Money.spec")#require("./Broken.spec")#' tests/run.luau && "$(dirname "$LUAU_BIN")/luau" tests/run.luau; echo "exit=$?"
  • Covers: The scanner's purity rules against a real Studio-coupled module, and clean pure modules
  • Covers: Luau 0.743's own type checker in strict mode on the pure modules, the specs and the sample
  • Covers: The skill's test runner under the luau CLI, passing and failing, including a string require between pure modules
  • Covers: Not covered: the edge scripts and remotes, which need Studio; run a play-test for those

What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results from agent runs are separate and stay untested until an agent actually runs.

Install

Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.

Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.

Download zip
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/roblox-luau-pure-modules/1.0.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://setupbay.com/raw/roblox-luau-pure-modules/1.0.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/luau-pure-tests/SKILL.md https://setupbay.com/raw/roblox-luau-pure-modules/1.0.0/skills/luau-pure-tests/SKILL.md
curl -fsSL --create-dirs -o .claude/skills/luau-pure-tests/scripts/pure_luau_guard.py https://setupbay.com/raw/roblox-luau-pure-modules/1.0.0/skills/luau-pure-tests/scripts/pure_luau_guard.py
curl -fsSL --create-dirs -o .claude/skills/luau-pure-tests/references/run.luau https://setupbay.com/raw/roblox-luau-pure-modules/1.0.0/skills/luau-pure-tests/references/run.luau
curl -fsSL --create-dirs -o .claude/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt https://setupbay.com/raw/roblox-luau-pure-modules/1.0.0/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/luau-pure-tests/SKILL.md.claude/skills/luau-pure-tests/SKILL.md
skills/luau-pure-tests/scripts/pure_luau_guard.py.claude/skills/luau-pure-tests/scripts/pure_luau_guard.py
skills/luau-pure-tests/references/run.luau.claude/skills/luau-pure-tests/references/run.luau
skills/luau-pure-tests/references/studio-coupled-sample.luau.txt.claude/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what Claude Code reads.

Or as a Claude Code plugin

Adds the skill to Claude Code for all your projects, without copying files. Plugins can't carry project rules, so add AGENTS.md and CLAUDE.md with the commands above. About the plugin marketplace.

/plugin marketplace add https://setupbay.com/marketplace.json
/plugin install roblox-luau-pure-modules@setupbay

Files

Rules AGENTS.md The pure/edge split, the rules for each, and the done checklist. 39 lines
Download Raw
# AGENTS.md: Roblox game with pure Luau modules checked outside Studio

Game rules (prices, inventory, damage, cooldown maths, matchmaking) live in **pure modules** in `src/shared/pure/`.
A pure module never touches the DataModel, so the plain `luau` CLI can type-check and test it in seconds, with no
Studio open. Scripts in `src/server/` and `src/client/` are the **edge**: they get services, read and write
Instances, handle remotes, then call the pure modules with plain values.

## Layout (Rojo)
```
src/shared/pure/   → ReplicatedStorage.Shared.pure   pure ModuleScripts, --!strict, no Roblox APIs
src/shared/        → ReplicatedStorage.Shared        other shared modules and Remotes
src/server/        → ServerScriptService.Server      server edge scripts (*.server.luau)
src/client/        → StarterPlayerScripts            client edge scripts (*.client.luau)
tests/             (not synced)                      *.spec.luau and run.luau, for the luau CLI
```

## Rules for pure modules
- First line `--!strict`. Export the types callers need (`export type State = {...}`).
- No `game`, `workspace`, `script`, `Instance`, services, `task.*`, `wait`/`spawn`/`delay`, `tick()`, or Roblox
  datatypes (`Vector3`, `CFrame`, `Color3`, `Enum`, `Random`). Take what you need as parameters.
- Require other pure modules by string: `require("./Money")`. Roblox (require-by-string) and the luau CLI both
  resolve it relative to the file. Never `require(script.Parent.Money)` inside `pure/`.
- No `print`/`warn`, no `math.random` or `os.time` inside rules. Return values and errors, and take an rng or the
  current time as a parameter, so tests are repeatable.
- Validate inputs in the pure function too (whole numbers, ranges, NaN). The edge script checks types from remotes;
  the rules decide what's allowed.

## Rules for edge scripts
- Keep them thin: read Instances and remote arguments, call the pure module, apply the result.
- Use `task.wait` / `task.spawn` / `task.delay`, never the deprecated `wait` / `spawn` / `delay`.
- The server decides: remotes carry intent, and the server runs the pure rules before changing any state.

## Before you say "done"
1. `python3 .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py src/shared/pure` reports `0 error(s)`.
2. `luau-analyze --mode=strict src/shared/pure tests` reports nothing.
3. `luau tests/run.luau` ends with `0 failed`. Add a test for every rule you change.
4. List what the human should play-test in Studio for the edge scripts. If Roblox Studio's built-in MCP server is
   connected, you can run that play-test through it, but the pure tests above still come first.
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 11 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes

- Skills from this loadout live in `.claude/skills/`: `luau-pure-tests`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From SetupBay "Roblox pure Luau modules checked outside Studio" v1.0.0 — https://setupbay.com/loadouts/roblox-luau-pure-modules/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 11 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes

- Skills from this loadout live in `.agents/skills/`: `luau-pure-tests`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From SetupBay "Roblox pure Luau modules checked outside Studio" v1.0.0 — https://setupbay.com/loadouts/roblox-luau-pure-modules/ -->
Cursor rule .cursor/rules/luau-pure-modules.mdc Never/instead table for pure modules and tests. 20 lines
Download Raw
---
description: Pure Luau modules in src/shared/pure must run outside Studio
globs: "src/shared/pure/**/*.luau,tests/**/*.luau"
alwaysApply: false
---

Files in `src/shared/pure/` are pure: the luau CLI must be able to run them with no Roblox engine.

| Never in `pure/` | Instead |
|---|---|
| `game:GetService(...)`, `workspace`, `script.Parent` | pass the values in from the edge script |
| `require(script.Parent.Money)` | `require("./Money")` |
| `Instance.new`, `Vector3`, `CFrame`, `Enum`, `Random` | plain numbers and tables |
| `task.wait`, `wait`, `spawn`, `delay`, `tick()` | return a value; the edge script schedules |
| `math.random()`, `os.time()` | take `rng` / `now` as parameters |
| `print`, `warn` | return `false, "reason"` |

- `--!strict` on the first line, with exported types.
- Every change gets a case in `tests/*.spec.luau`. Then run the `luau-pure-tests` skill's checks.
Skill skills/luau-pure-tests/SKILL.md Check purity, type-check in strict mode, then run the tests with the luau CLI. 56 lines
Download Raw
---
name: luau-pure-tests
description: Keep a Roblox game's rules in pure Luau modules and run their tests outside Studio with the luau CLI, checking purity with a scanner and types with luau-analyze in strict mode. Use when writing or changing game logic (prices, inventory, damage, cooldowns), when asked to add tests to a Roblox project, or when a module can't run in a test because it calls Roblox APIs.
---

# Pure Luau modules, checked outside Studio

Roblox logic is usually tried out by pressing Play. Rules that don't touch the DataModel can be checked by the
standalone Luau tools instead: `luau-analyze` type-checks them, and `luau` runs their tests in milliseconds.
That's something an agent can run after every change.

## Tools
The Luau release (https://github.com/luau-lang/luau/releases) ships `luau` (runs scripts) and
`luau-analyze` (type-checks and lints) for Linux, macOS and Windows. Rokit or Aftman can install them per project;
otherwise download the release zip. Check with `luau-analyze --help`.

## 1. Check purity
```bash
python3 .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py src/shared/pure
```
(Use the path the skill was installed to: `.claude/skills/...` for Claude Code, `.agents/skills/...` for the others.)

Run it on the pure folders only; edge scripts are meant to use Roblox APIs. Each `error` is a Roblox-only call that
stops the module running outside Studio. Move that call into the edge script and pass the value in. `warn` lines
(`math.random`, `os.time`, `print`) make tests unrepeatable; take an rng or the time as a parameter.

## 2. Type-check in strict mode
```bash
luau-analyze --mode=strict src/shared/pure tests
```
It must print nothing. `Unknown global 'game'` or `Unknown require: unsupported path` means a Roblox API or an
Instance-path require got into a pure module.

## 3. Run the tests
Copy `references/run.luau` to `tests/run.luau` once and list each spec file in it. A spec returns a list of cases:
```luau
--!strict
local Inventory = require("../src/shared/pure/Inventory")
return {
	{ name = "Inventory: the stack limit holds", run = function()
		local s = Inventory.new(500)
		assert(Inventory.buy(s, { id = "sword", price = 150, stack = 1 }, 1))
		assert(not Inventory.buy(s, { id = "sword", price = 150, stack = 1 }, 1))
	end },
}
```
```bash
luau tests/run.luau
```
It prints `PASS`/`FAIL` per case and `N passed, M failed`, and exits non-zero on any failure.

## 4. Report
Say which rules changed, which tests you added, and that the scanner, `luau-analyze --mode=strict` and
`luau tests/run.luau` were clean. Then list what still needs a Studio play-test: the edge scripts, remotes and
anything that touches Instances.
Skill file skills/luau-pure-tests/scripts/pure_luau_guard.py Read-only scanner for Roblox-only calls in pure Luau modules. 134 lines
Download Raw
#!/usr/bin/env python3
"""Find Roblox-only calls in Luau modules meant to be pure (no DataModel), so they run and test outside Studio. Run it on the pure folders only, such as src/shared.

Usage: python3 pure_luau_guard.py [PATH ...]        (default: the current folder)
       python3 pure_luau_guard.py --list            (print every rule)

A "guard: ok" comment on a line silences its warnings (never its errors).
Prints one line per finding:  path:line: level [rule] what is wrong -> what to use
Exit 0 when nothing at "error" level is found, 1 when something is, 2 on bad usage.
Standard library only. Read-only: it never edits a file and makes no network calls.
"""
import fnmatch
import os
import re
import sys

# (rule id, level, regex, message, file patterns). Patterns run against each line with comments removed.
RULES = [
    ('datamodel', 'error', '\\b(game|plugin)\\b\\s*[:.]|\\bworkspace\\b|\\bscript\\.(Parent|Name)\\b|\\bInstance\\.new\\(',
     "pure modules can't touch the DataModel (game, workspace, script, Instance) -> pass plain values in from the server or client script", []),
    ('instance-require', 'error', '\\brequire\\(\\s*(script|game)\\b',
     'Instance-path require only works in Studio -> require("./Sibling") or require("../Folder/Module"), which Roblox and the luau CLI both resolve', []),
    ('roblox-services', 'error', '\\b(Players|ReplicatedStorage|ServerStorage|RunService|DataStoreService|HttpService|TweenService|UserInputService|MarketplaceService|MemoryStoreService)\\b\\s*[:.]',
     'a Roblox service in a pure module -> keep services in the edge script and pass what you need in', []),
    ('task-library', 'error', '\\btask\\.(wait|spawn|delay|defer|cancel)\\(',
     'the task library is Roblox-only -> keep scheduling in the edge script; pure functions return values', []),
    ('deprecated-scheduler', 'error', '(?<![\\w.:])(wait|spawn|delay)\\(',
     'wait/spawn/delay are deprecated in Roblox and missing in the luau CLI -> task.wait/task.spawn/task.delay in edge scripts only', []),
    ('roblox-types', 'error', '\\b(Vector3|CFrame|Color3|UDim2|BrickColor|TweenInfo|Enum|Random|DateTime)\\b\\s*[.(]',
     'a Roblox datatype in a pure module -> use plain numbers and tables, or pass the value in', []),
    ('tick', 'error', '(?<![\\w.:])tick\\(\\)',
     'tick() is deprecated -> os.clock() for timing, or pass the time in', []),
    ('connect-lowercase', 'error', ':connect\\(',
     ':connect is deprecated -> :Connect, and only in edge scripts', []),
    ('math-random', 'warn', '\\bmath\\.random\\(',
     'random numbers make pure functions hard to test -> take an rng function or a seed as a parameter', []),
    ('os-time', 'warn', '\\bos\\.(time|clock)\\(',
     'reading the clock makes pure functions hard to test -> take the time as a parameter', []),
    ('print-in-module', 'warn', '(?<![\\w.:])(print|warn)\\(',
     'printing from a pure module -> return the value or an error and let the caller log', []),
]
FILES = ['*.luau', '*.lua']
COMMENT = '--'
SKIP_DIRS = {".git", ".venv", "venv", "node_modules", "__pycache__", ".agents", ".claude", ".cursor", "dist", "build", "target", ".godot"}
COMPILED = [(rid, lvl, re.compile(rx), msg, globs) for rid, lvl, rx, msg, globs in RULES]


def strip_comment(line):
    """Drop a trailing comment, leaving string literals alone."""
    q = None
    i = 0
    while i < len(line):
        c = line[i]
        if q:
            if c == "\\":
                i += 2
                continue
            if c == q:
                q = None
        elif c in "\"'`":
            q = c
        elif line.startswith(COMMENT, i):
            return line[:i]
        i += 1
    return line


def wanted(name):
    return any(fnmatch.fnmatch(name, g) for g in FILES)


def walk(paths):
    for p in paths:
        if os.path.isfile(p):
            yield p
            continue
        for root, dirs, files in os.walk(p):
            dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)
            for f in sorted(files):
                if wanted(f):
                    yield os.path.join(root, f)


def scan(path):
    out = []
    name = os.path.basename(path)
    try:
        with open(path, encoding="utf-8", errors="replace") as fh:
            lines = fh.read().splitlines()
    except OSError as e:
        return [(path, 0, "error", "unreadable", str(e))]
    for n, raw in enumerate(lines, 1):
        code = strip_comment(raw)
        if not code.strip():
            continue
        accepted = "guard: ok" in raw  # a person accepted the warnings on this line
        for rid, lvl, rx, msg, globs in COMPILED:
            if accepted and lvl == "warn":
                continue
            if globs and not any(fnmatch.fnmatch(name, g) for g in globs):
                continue
            if rx.search(code):
                out.append((path, n, lvl, rid, msg))
    return out


def main(argv):
    if "--list" in argv:
        for rid, lvl, _, msg, globs in RULES:
            print(f"{lvl:5} [{rid}] {msg}" + (f"  (only {', '.join(globs)})" if globs else ""))
        return 0
    if any(a.startswith("-") for a in argv):
        print(__doc__)
        return 2
    paths = argv or ["."]
    for p in paths:
        if not os.path.exists(p):
            print(f"no such path: {p}", file=sys.stderr)
            return 2
    files = list(walk(paths))
    findings = []
    for f in files:
        findings.extend(scan(f))
    for path, n, lvl, rid, msg in findings:
        print(f"{os.path.relpath(path)}:{n}: {lvl} [{rid}] {msg}")
    errors = sum(1 for x in findings if x[2] == "error")
    warns = sum(1 for x in findings if x[2] == "warn")
    print(f"pure_luau_guard: {len(files)} file(s), {errors} error(s), {warns} warning(s)")
    return 1 if errors else 0


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
Skill file skills/luau-pure-tests/references/run.luau Minimal test runner for spec files under the luau CLI. 22 lines
Download Raw
--!strict
-- Minimal test runner for the luau CLI: luau tests/run.luau
local specs = { require("./Inventory.spec"), require("./Money.spec") }

local passed, failed = 0, 0
for _, spec in specs do
	for _, case in spec do
		local ok, err = pcall(case.run)
		if ok then
			passed += 1
			print(`PASS {case.name}`)
		else
			failed += 1
			print(`FAIL {case.name}: {err}`)
		end
	end
end
print(`{passed} passed, {failed} failed`)
if failed > 0 then
	error(`{failed} test(s) failed`, 0)
end
Skill file skills/luau-pure-tests/references/studio-coupled-sample.luau.txt A Studio-coupled inventory module for checking the guard. 30 lines
Download Raw
-- A Studio-coupled inventory module, used to check the guard. It only runs inside Roblox.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Money = require(script.Parent.Money)
local Config = require(game.ReplicatedStorage.Shared.Config)

local Inventory = {}

function Inventory.buy(player, item, quantity)
	local stats = player:FindFirstChild("leaderstats")
	if stats.Coins.Value < item.price * quantity then
		warn("not enough coins")
		return false
	end
	stats.Coins.Value -= item.price * quantity
	local drop = Instance.new("Part")
	drop.Position = Vector3.new(0, 10, 0)
	drop.Parent = workspace
	if math.random() < Config.bonusChance then
		spawn(function()
			wait(2)
			stats.Coins.Value += 5
		end)
	end
	player:SetAttribute("lastBuy", tick())
	ReplicatedStorage.Remotes.Bought:FireClient(player, item.id)
	return true
end

return Inventory

All files: source zip · Licence MIT · By SetupBay · First listed

Installing and checks

How do I install Roblox pure Luau modules checked outside Studio in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/luau-pure-tests/SKILL.md at .claude/skills/luau-pure-tests/SKILL.md, skills/luau-pure-tests/scripts/pure_luau_guard.py at .claude/skills/luau-pure-tests/scripts/pure_luau_guard.py, skills/luau-pure-tests/references/run.luau at .claude/skills/luau-pure-tests/references/run.luau, skills/luau-pure-tests/references/studio-coupled-sample.luau.txt at .claude/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt. The "Claude Code" tab on this page has the curl commands, or download https://setupbay.com/download/roblox-luau-pure-modules/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox pure Luau modules checked outside Studio in Codex CLI?

From your project root, put AGENTS.md, skills/luau-pure-tests/SKILL.md at .agents/skills/luau-pure-tests/SKILL.md, skills/luau-pure-tests/scripts/pure_luau_guard.py at .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py, skills/luau-pure-tests/references/run.luau at .agents/skills/luau-pure-tests/references/run.luau, skills/luau-pure-tests/references/studio-coupled-sample.luau.txt at .agents/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt. The "Codex CLI" tab on this page has the curl commands, or download https://setupbay.com/download/roblox-luau-pure-modules/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox pure Luau modules checked outside Studio in Cursor?

From your project root, put AGENTS.md, .cursor/rules/luau-pure-modules.mdc, skills/luau-pure-tests/SKILL.md at .agents/skills/luau-pure-tests/SKILL.md, skills/luau-pure-tests/scripts/pure_luau_guard.py at .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py, skills/luau-pure-tests/references/run.luau at .agents/skills/luau-pure-tests/references/run.luau, skills/luau-pure-tests/references/studio-coupled-sample.luau.txt at .agents/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt. The "Cursor" tab on this page has the curl commands, or download https://setupbay.com/download/roblox-luau-pure-modules/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox pure Luau modules checked outside Studio in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/luau-pure-tests/SKILL.md at .agents/skills/luau-pure-tests/SKILL.md, skills/luau-pure-tests/scripts/pure_luau_guard.py at .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py, skills/luau-pure-tests/references/run.luau at .agents/skills/luau-pure-tests/references/run.luau, skills/luau-pure-tests/references/studio-coupled-sample.luau.txt at .agents/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt. The "Gemini CLI" tab on this page has the curl commands, or download https://setupbay.com/download/roblox-luau-pure-modules/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox pure Luau modules checked outside Studio in Antigravity CLI?

From your project root, put AGENTS.md, skills/luau-pure-tests/SKILL.md at .agents/skills/luau-pure-tests/SKILL.md, skills/luau-pure-tests/scripts/pure_luau_guard.py at .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py, skills/luau-pure-tests/references/run.luau at .agents/skills/luau-pure-tests/references/run.luau, skills/luau-pure-tests/references/studio-coupled-sample.luau.txt at .agents/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt. The "Antigravity CLI" tab on this page has the curl commands, or download https://setupbay.com/download/roblox-luau-pure-modules/antigravity-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox pure Luau modules checked outside Studio in GitHub Copilot?

From your project root, put AGENTS.md, skills/luau-pure-tests/SKILL.md at .agents/skills/luau-pure-tests/SKILL.md, skills/luau-pure-tests/scripts/pure_luau_guard.py at .agents/skills/luau-pure-tests/scripts/pure_luau_guard.py, skills/luau-pure-tests/references/run.luau at .agents/skills/luau-pure-tests/references/run.luau, skills/luau-pure-tests/references/studio-coupled-sample.luau.txt at .agents/skills/luau-pure-tests/references/studio-coupled-sample.luau.txt. The "GitHub Copilot" tab on this page has the curl commands, or download https://setupbay.com/download/roblox-luau-pure-modules/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

What has been checked in Roblox pure Luau modules checked outside Studio?

It passed the Level 1 automated install checks on 2026-10-29: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.

More for Claude Code, Codex, Cursor, Gemini CLI, Antigravity CLI and GitHub Copilot.