Skip to content
Game dev · Security

Roblox Luau (Rojo)

Luau conventions for Rojo projects with a server-authoritative mindset, plus a skill that reviews every RemoteEvent for exploits before you publish.

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

On Roblox, the client is the exploiter's playground: anything a LocalScript sends can be faked. Agents routinely write remotes like "GiveCoins(amount)" that hand the game to the first script kiddie. This loadout teaches your agent typed Luau, the Rojo file layout, server authority and safe DataStore use, and adds a skill that audits every remote in the place.

What's in it

  • Server-authoritative rules: clients request, the server decides
  • --!strict typed Luau, task library, no deprecated wait/spawn
  • DataStore patterns with pcall, UpdateAsync and session-safe saving
  • Remote security review skill with a per-remote verdict

You'll need

  • Tools: rojo, roblox-studio
Level 1 · automated

Verification

Verified install

Checked at commit ad36e85 · 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; 5 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 5 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 5 agents; layouts re-discovered
  • Claude Code: 3 files, 1 skill in .claude/skills/
  • Codex CLI: 2 files, 1 skill in .agents/skills/
  • Cursor: 3 files, 1 skill in .agents/skills/, 1 rule
  • Gemini CLI: 3 files, 1 skill in .agents/skills/
  • GitHub Copilot: 2 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 or prompt-injection wording, and the listing's network flag is honest. Pass
Clean: no credentials, risky shell or hidden text
  • Scanner intake-precheck/1: 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 No cross-file references to check
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
5 files, 7.0 KB total; largest AGENTS.md 2.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 Agent Loadout; 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
The loadout's Luau example compiles with the official Luau compiler inside a Rojo layout (syntax only: Roblox APIs and Studio can't run in CI)
  • Applied 6 loadout files at every agent's paths
  • Example from .cursor/rules/luau-remotes.mdc:14 (luau) → src/server/BuyItem.server.luau
  • luau 0.743
  • ✓ compile Luau (luau-compile): ${LUAU_BIN} --null src/server/BuyItem.server.luau src/server/Shop.luau
  • ✓ Rojo project file is valid JSON: node -e JSON.parse(require('fs').readFileSync('default.project.json','utf8'))
  • Covers: The Cursor rule's remote-handler example parses and compiles with Luau 0.743 (--!strict syntax, type annotations, compound assignment)
  • Covers: Not covered: type-checking against Roblox APIs and running in Roblox Studio, which is closed-source and Windows/macOS-only

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 ("tested with agent") 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://loadout.jnw-it.com/raw/roblox-luau/1.0.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/roblox-luau/1.0.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/remote-security-review/SKILL.md https://loadout.jnw-it.com/raw/roblox-luau/1.0.0/skills/remote-security-review/SKILL.md
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/remote-security-review/SKILL.md.claude/skills/remote-security-review/SKILL.md

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.

Files

Rules AGENTS.md Roblox Luau project rules for Rojo layouts. 41 lines
Download Raw
# AGENTS.md: Roblox Luau (Rojo)

## Layout (Rojo, see `default.project.json`)
```
src/server/   → ServerScriptService     server Scripts (*.server.luau) and server-only modules
src/client/   → StarterPlayerScripts    LocalScripts (*.client.luau)
src/shared/   → ReplicatedStorage       ModuleScripts used by both sides, plus Remotes
```
- `ServerStorage` and `ServerScriptService` are invisible to clients. Anything in `ReplicatedStorage` or the workspace is visible to exploiters.
- Run `rojo serve` and connect from the Studio plugin to sync. Do not edit synced scripts inside Studio — edits are overwritten.

## The golden rule: the server decides
- Clients can be fully controlled by exploiters. Every value from a `RemoteEvent`/`RemoteFunction` is an untrusted request.
- Remotes express intent ("I want to buy item X", "I pressed attack"), never outcomes ("give me 500 coins", "deal 999 damage").
- On the server, for every remote handler:
  1. Check argument types (`typeof(x) == "string"`) and ranges; reject NaN and huge numbers.
  2. Check the player is allowed (owns the item, has the cash, is close enough, cooldown passed).
  3. Rate-limit per player.
  4. Compute the result on the server.
- Never use `RemoteFunction:InvokeClient` — a client can yield forever and hang the server thread.
- Currency, inventory, damage, cooldowns and leaderboards live on the server.

## Luau style
- `--!strict` at the top of every file; type function signatures and module tables.
- `task.wait`, `task.spawn`, `task.delay`, `task.defer` — never the deprecated `wait`, `spawn`, `delay`.
- Get services once at the top: `local Players = game:GetService("Players")`.
- Use `WaitForChild` on the client for replicated objects; avoid it on the server for things the server creates.
- Disconnect connections you create per player or per round, or clean up with a maid/trove pattern.
- `PascalCase` for modules and services, `camelCase` for locals and functions.

## Data
- `DataStoreService` calls can fail: always wrap them in `pcall` and retry with backoff.
- Prefer `UpdateAsync` to `SetAsync` for player data so concurrent servers do not overwrite each other.
- Load on `PlayerAdded`, save on `PlayerRemoving` **and** in `game:BindToClose` (with a time budget), plus periodic autosave.
- Do not save if the initial load failed — you would overwrite real data with defaults.
- Studio needs "Enable Studio Access to API Services" switched on to test DataStores; remind the human.

## Before you say "done"
Code type-checks (`luau-lsp` or Studio's Script Analysis shows no errors), and you have listed what the human should test in a
Studio play-test — ideally with two players (Test → Clients and Servers).
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 10 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `remote-security-review`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Roblox Luau (Rojo)" v1.0.0 — https://loadout.jnw-it.com/loadouts/roblox-luau/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 10 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `remote-security-review`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Roblox Luau (Rojo)" v1.0.0 — https://loadout.jnw-it.com/loadouts/roblox-luau/ -->
Cursor rule .cursor/rules/luau-remotes.mdc Rule applied to server scripts that handle remotes. 33 lines
Download Raw
---
description: Server-side remote handler rules for Roblox
globs: "src/server/**/*.luau"
alwaysApply: false
---

Every `OnServerEvent` / `OnServerInvoke` handler must:

1. Treat its arguments as untrusted. Check `typeof` for each one and bounds for numbers (reject NaN: `x ~= x`).
2. Check permission and game state on the server (ownership, cost, distance, cooldown).
3. Rate-limit per player.
4. Compute outcomes on the server. Never accept amounts, damage, prices or positions as facts.

```luau
--!strict
local Remotes = game:GetService("ReplicatedStorage"):WaitForChild("Remotes")
local Shop = require(script.Parent.Shop)

local lastCall: { [Player]: number } = {}

Remotes.BuyItem.OnServerEvent:Connect(function(player: Player, itemId: unknown)
	if typeof(itemId) ~= "string" or #itemId > 64 then return end
	local now = os.clock()
	if (lastCall[player] or 0) + 0.5 > now then return end
	lastCall[player] = now
	Shop.tryPurchase(player, itemId) -- looks up the price server-side and checks the balance
end)

game:GetService("Players").PlayerRemoving:Connect(function(player) lastCall[player] = nil end)
```

Never use `InvokeClient`. Never `loadstring` anything.
Skill skills/remote-security-review/SKILL.md Audits every RemoteEvent and RemoteFunction for exploitable trust. 41 lines
Download Raw
---
name: remote-security-review
description: Audit a Roblox game's RemoteEvents and RemoteFunctions for exploitable client trust. Use before publishing, after adding remotes, or when players report exploits like infinite money or teleporting.
---

# Remote security review

## 1. Inventory
- Find every remote: search for `RemoteEvent`, `RemoteFunction`, `UnreliableRemoteEvent` instances in the Rojo project files
  (`*.model.json`, `*.project.json`, `.rbxmx`) and in code (`Instance.new("RemoteEvent")`).
- Find every handler: `OnServerEvent`, `OnServerInvoke`, and on the client `FireServer`/`InvokeServer` calls.
- Build a table: remote name → server handler file → client call sites → arguments sent.

## 2. Review each handler
For each remote, answer:
1. **What does the client claim?** List each argument. Would an exploiter gain anything by changing it?
2. **Types checked?** Every argument `typeof`-checked, strings length-limited, numbers bounded and NaN-rejected, Instances checked
   to be the expected class and in an expected place.
3. **Authority:** does the server compute the outcome, or trust a client value (amount, damage, price, position, target)?
4. **Permission/state:** does it check ownership, cost, distance (`(char.HumanoidRootPart.Position - target.Position).Magnitude`),
   cooldown, round state?
5. **Rate limiting:** can it be spammed? What happens if it is fired 1,000 times a second?
6. **Errors:** can bad input throw and break the handler for everyone, or leave state half-updated?
7. **RemoteFunctions:** never `InvokeClient`. `OnServerInvoke` returns quickly and never yields on client data.

## 3. Also check
- Server-only modules are not in `ReplicatedStorage` (secrets, admin lists, prices that should be hidden).
- No `loadstring`, no `require` of asset IDs you do not control.
- Admin commands check a server-side list of `UserId`s (not names, which can change).
- Clients are not given network ownership of things that matter (e.g. other players' parts, shop NPCs).

## 4. Report
```
Remote review — <place> — <n> remotes
[Critical] AddCoins (src/server/Economy.server.luau:42) — trusts `amount` from the client. Any exploiter can grant themselves unlimited coins.
  Fix: remove the remote; award coins on the server when the qualifying event happens.
[High] Attack — no distance check or cooldown. Fix: check range ≤ weapon reach and a per-player cooldown.
[OK] RequestRespawn — no arguments, cooldown present.
```
Order by severity. Offer to write the fixes, one remote at a time.

All files: source zip · Licence MIT · By Agent Loadout · First listed

Installing and testing

How do I install Roblox Luau (Rojo) in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/remote-security-review/SKILL.md at .claude/skills/remote-security-review/SKILL.md. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/roblox-luau/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 Luau (Rojo) in Codex CLI?

From your project root, put AGENTS.md, skills/remote-security-review/SKILL.md at .agents/skills/remote-security-review/SKILL.md. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/roblox-luau/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox Luau (Rojo) in Cursor?

From your project root, put AGENTS.md, .cursor/rules/luau-remotes.mdc, skills/remote-security-review/SKILL.md at .agents/skills/remote-security-review/SKILL.md. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/roblox-luau/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Roblox Luau (Rojo) in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/remote-security-review/SKILL.md at .agents/skills/remote-security-review/SKILL.md. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/roblox-luau/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 Luau (Rojo) in GitHub Copilot?

From your project root, put AGENTS.md, skills/remote-security-review/SKILL.md at .agents/skills/remote-security-review/SKILL.md. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/roblox-luau/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

Has Roblox Luau (Rojo) been tested?

It passed the Level 1 automated install checks on 2026-10-16: 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 and GitHub Copilot.