roblox-guard 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +77 -0
- package/LICENSE +21 -21
- package/README.md +22 -5
- package/package.json +3 -2
- package/scripts/roblox-guard.mjs +16 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Roblox and Luau standards
|
|
2
|
+
|
|
3
|
+
Scope: every `.luau` and `.lua` file in a Roblox project. These rules govern how each script is
|
|
4
|
+
written, not how the project is structured, so they hold under any framework or folder layout.
|
|
5
|
+
|
|
6
|
+
They are active instruction, not background reading. Carry them forward verbatim into any
|
|
7
|
+
summary, handoff, or task note. Never reconstruct them from memory: a half-remembered layout
|
|
8
|
+
rule looks deliberate and is worse than none.
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
ROBLOX LUAU SKILL - INVARIANT CARD
|
|
12
|
+
1 Three sections, this order:
|
|
13
|
+
-- // VARIABLES // -- Services > Modules > Objects > Configuration > State Management
|
|
14
|
+
-- // FUNCTIONS // -- definitions only (ModuleScript: Private before Public)
|
|
15
|
+
-- // INITIALIZATION // -- everything that runs
|
|
16
|
+
Omit a section that would be empty. Never write a placeholder header.
|
|
17
|
+
2 Documentation Comments (Luau Comments) - default style, adapts to the project.
|
|
18
|
+
Default block: --[[ ]] above the function, desc > @param > @return.
|
|
19
|
+
Moonwave --[=[ ]=] or --- is equally correct when that is the project's style.
|
|
20
|
+
- Desc <= 3 lines and <= 250 chars, contract-level, states PURPOSE.
|
|
21
|
+
- Desc never names what the body does to get there: no APIs, algorithms,
|
|
22
|
+
collaborators, data structures, or code paths.
|
|
23
|
+
- Desc carries NO volatile content: no numbers, thresholds, tunable names,
|
|
24
|
+
feature names, or anything that needs editing when the body is retuned.
|
|
25
|
+
- Tags use Moonwave syntax: @param <name> <type> -- <description>
|
|
26
|
+
and @return <type> -- <description>. Only when they add what the
|
|
27
|
+
signature cannot show.
|
|
28
|
+
- English preferred. No em dashes or double-hyphen dashes as punctuation
|
|
29
|
+
(the -- in a tag is a separator, not punctuation). No emoji.
|
|
30
|
+
- IN-BODY COMMENTS: banned in code you write. Make names and structure say
|
|
31
|
+
it; put the why in the block above. Never delete an existing one;
|
|
32
|
+
propose removal once, Advisory only.
|
|
33
|
+
- Self-documenting code outranks commentary everywhere.
|
|
34
|
+
- Existing project comment style wins. Recommend this style when the user
|
|
35
|
+
asks to restyle; never impose it.
|
|
36
|
+
3 Server is authoritative. Validate every remote arg: type, range, ownership, rate.
|
|
37
|
+
4 Clean up everything created. Every connection has an owner and a teardown path.
|
|
38
|
+
5 No avoidable per-frame garbage. Never poll what has a signal.
|
|
39
|
+
6 UpdateAsync + backoff. Save on PlayerRemoving. Flush on BindToClose.
|
|
40
|
+
7 Re-validate after every yield: player gone? instance dead? session changed?
|
|
41
|
+
8 Never add --!strict unbidden. Never make a [Beta] feature the production default.
|
|
42
|
+
9 Reuse before writing: project, then stdlib, then engine API. No wrapper or
|
|
43
|
+
abstraction without a caller. But brevity has two hard limits:
|
|
44
|
+
- It NEVER reduces what was asked for. Short because it does less = failed.
|
|
45
|
+
- It NEVER costs readability. One statement per line, descriptive names,
|
|
46
|
+
blank lines kept. Less code means less WORK, not less whitespace.
|
|
47
|
+
10 No deprecated APIs: wait, spawn, delay, tick, lowercase :connect,
|
|
48
|
+
Humanoid:LoadAnimation, SetPrimaryPartCFrame, Body* movers.
|
|
49
|
+
11 Engine facts are cited, not remembered. Confirm a newer API against the
|
|
50
|
+
version dump or an in-Studio probe before relying on it.
|
|
51
|
+
12 User authority outranks these rules. Recommend; never refactor unasked.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Full standards
|
|
55
|
+
|
|
56
|
+
This card is the part that must survive a summary. The complete standards, with the reference
|
|
57
|
+
files behind each rule, live in this repository:
|
|
58
|
+
|
|
59
|
+
| Path | Covers |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `skills/best-practices/SKILL.md` | Writing and refactoring Luau |
|
|
62
|
+
| `skills/code-review/SKILL.md` | Reviewing, auditing, and scoring existing code |
|
|
63
|
+
| `skills/studio-ops/SKILL.md` | Studio MCP, sync toolchains, verifying in a running session |
|
|
64
|
+
|
|
65
|
+
Read the one whose task matches. Each reference file is self-contained; read one, not the set.
|
|
66
|
+
|
|
67
|
+
## The checks run outside you
|
|
68
|
+
|
|
69
|
+
`scripts/roblox-guard.mjs` reports deprecated APIs and out-of-order section headers
|
|
70
|
+
deterministically, with no model involved. Run it on the files you touched before you report
|
|
71
|
+
work as done:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
node scripts/roblox-guard.mjs --check <files>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
It exits 1 when a file has findings, and each finding names the line and the replacement.
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Muhammad Andriansyah
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Muhammad Andriansyah
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Professional Roblox and Luau standards for AI agents, and a checker that runs wi
|
|
|
9
9
|
[](https://github.com/andrian-syh/roblox-optimum/actions/workflows/ci.yml)
|
|
10
10
|
[](CHANGELOG.md)
|
|
11
11
|
[](LICENSE)
|
|
12
|
+
[](https://www.npmjs.com/package/roblox-guard)
|
|
12
13
|
[](package.json)
|
|
13
14
|
[](package.json)
|
|
14
15
|
|
|
@@ -25,8 +26,8 @@ Claude Code, and as a project instruction file everywhere else. [AGENTS.md](AGEN
|
|
|
25
26
|
ready to copy, along with a matching file for Cursor, Windsurf, Cline, Kiro, Qoder, Copilot,
|
|
26
27
|
Qwen Code, and Antigravity.
|
|
27
28
|
|
|
28
|
-
**The checker** is [`
|
|
29
|
-
dependencies. It reads Luau and reports the same findings whoever wrote the file, so it works as
|
|
29
|
+
**The checker** is [`roblox-guard`](https://www.npmjs.com/package/roblox-guard) on npm, one Node
|
|
30
|
+
file with no dependencies. It reads Luau and reports the same findings whoever wrote the file, so it works as
|
|
30
31
|
an agent hook, a commit hook, or a CI step. It never asks a model anything, which is why it still
|
|
31
32
|
holds after a long session has been summarized and the rules have fallen out of context.
|
|
32
33
|
|
|
@@ -54,9 +55,15 @@ Qwen Code:
|
|
|
54
55
|
qwen extensions install https://github.com/andrian-syh/roblox-optimum
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
Cursor, Antigravity, and
|
|
58
|
-
OpenCode
|
|
59
|
-
|
|
58
|
+
Cursor, Antigravity, Kiro, and Copilot CLI install it as a plugin from this repository. For those,
|
|
59
|
+
plus OpenCode or a plain commit hook, see **[INSTALL.md](INSTALL.md)**, which also states plainly
|
|
60
|
+
what each setup can and cannot do.
|
|
61
|
+
|
|
62
|
+
The checker on its own needs no repository at all:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
npx roblox-guard --check src/**/*.luau
|
|
66
|
+
```
|
|
60
67
|
|
|
61
68
|
## Skills
|
|
62
69
|
|
|
@@ -113,6 +120,16 @@ or synced, belong to a project rather than to a person, and are resolved per ses
|
|
|
113
120
|
Deprecated APIs and out-of-order section headers. Where the agent can receive them, findings go
|
|
114
121
|
straight back to it and it fixes its own output before you see it.
|
|
115
122
|
|
|
123
|
+
```
|
|
124
|
+
$ npx roblox-guard --check CoinService.luau
|
|
125
|
+
Roblox standards check failed for CoinService.luau:
|
|
126
|
+
- Line 5: :connect() is deprecated. Use :Connect().
|
|
127
|
+
- Line 6: wait() is deprecated. Use task.wait().
|
|
128
|
+
- Line 8: Humanoid:LoadAnimation() is deprecated. Use Animator:LoadAnimation().
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Exit 1, so a commit hook or a build step stops on it.
|
|
132
|
+
|
|
116
133
|
The check is deliberately conservative, because a wrong complaint gets a guard switched off:
|
|
117
134
|
|
|
118
135
|
- Comments and string literals are excluded, so a rule quoted in prose is never reported as a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roblox-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Deterministic Roblox and Luau standards checks: deprecated APIs and out-of-order section headers, as an agent hook, a commit hook, or a CI step.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"roblox",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"roblox-guard": "scripts/roblox-guard.mjs"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"scripts/roblox-guard.mjs"
|
|
20
|
+
"scripts/roblox-guard.mjs",
|
|
21
|
+
"AGENTS.md"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"test": "node scripts/roblox-guard.mjs --selftest"
|
package/scripts/roblox-guard.mjs
CHANGED
|
@@ -188,15 +188,21 @@ export function inspect(source) {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
const lines = code.split("\n");
|
|
191
|
+
const deprecated = [];
|
|
192
|
+
|
|
191
193
|
for (const [pattern, name, replacement] of DEPRECATED) {
|
|
192
194
|
for (let k = 0; k < lines.length; k++) {
|
|
193
195
|
if (pattern.test(lines[k])) {
|
|
194
|
-
|
|
196
|
+
deprecated.push({ line: k + 1, text: `Line ${k + 1}: ${name} is deprecated. Use ${replacement}.` });
|
|
195
197
|
break;
|
|
196
198
|
}
|
|
197
199
|
}
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
// Report in reading order. Grouping by pattern is how they are found, not how they are read.
|
|
203
|
+
deprecated.sort((a, b) => a.line - b.line);
|
|
204
|
+
problems.push(...deprecated.map((d) => d.text));
|
|
205
|
+
|
|
200
206
|
return problems;
|
|
201
207
|
}
|
|
202
208
|
|
|
@@ -399,6 +405,15 @@ Players.PlayerAdded:Connect(greet)
|
|
|
399
405
|
inspect(good.replace("task.wait(1)", "wait(1)")).some((p) => p.includes("wait()")),
|
|
400
406
|
"bare wait() is caught",
|
|
401
407
|
);
|
|
408
|
+
ok(
|
|
409
|
+
(() => {
|
|
410
|
+
const lines = inspect(`-- // VARIABLES // --\nlocal a = 1\n-- // INITIALIZATION // --\nspawn(function()\n\twait(1)\nend)\nx:connect(f)`)
|
|
411
|
+
.map((p) => Number(p.match(/^Line (\d+)/)?.[1]))
|
|
412
|
+
.filter(Number.isFinite);
|
|
413
|
+
return lines.length === 3 && lines.every((n, k) => k === 0 || n >= lines[k - 1]);
|
|
414
|
+
})(),
|
|
415
|
+
"findings are reported in line order, not pattern order",
|
|
416
|
+
);
|
|
402
417
|
ok(
|
|
403
418
|
!inspect(good).some((p) => p.includes("wait()")),
|
|
404
419
|
"task.wait() is not mistaken for wait()",
|