lua-guidelines
Skill1 starsChanged 4 months agoMITView on GitHub
Use when writing, reviewing, or designing Lua 5.4 or LuaJIT code, especially game scripting, modding APIs, sandboxed scripts, data-definition tables, or the C API boundary of an embedded interpreter.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- CsHeng/agent-skillstheir own version, first seen Nov 4, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- CsHeng/agent-skills★ 3same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository30 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- blind-reviewSkill
- c-guidelinesSkill
- cpp-guidelinesSkill
- dast-staging-guidelinesSkill
- data-engineering-guidelinesSkill
- diagramming-guidelinesSkill
- java-guidelinesSkill
- jj-guidelinesSkill
- kotlin-guidelinesSkill
- python-guidelinesSkill
- re-provenance-guidelinesSkill
- reverse-engineering-guidelinesSkill
- rust-guidelinesSkill
- sast-triage-guidelinesSkill
- scala-guidelinesSkill
- security-review-guidelinesSkill
- spark-guidelinesSkill
- spark-pyspark-guidelinesSkill
- spark-scala-guidelinesSkill
- sql-guidelinesSkill
- supply-chain-guidelinesSkill
- swift-guidelinesSkill
- technical-writing-guidelinesSkill
- terraform-guidelinesSkill
- tool-prioritySkill
- tutoring-guidelinesSkill
- typescript-guidelinesSkill
- unreal-guidelinesSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Use this as the shared Lua rubric for agents.
- Very specific: line 24
Use the module pattern: build a local table M, add functions, and return M.
- Very specific: line 41
Avoid table creation in per-frame loops: reuse tables, clear them in place, or pool them.
- Very specific: line 43
Avoid .. in loops. Avoid string.format and tostring on hot paths when a cached string works.
- Very specific: line 54
Call Lua with lua_pcall and a message handler that adds a traceback.
- Very specific: line 80
Use exact repo-native gates first.
- Distinctive: line 105
When reviewing, lead with severity-ranked findings and concrete file and line evidence.
- Distinctive: line 107
When implementing, make the smallest coherent change, add or update tests for observable behavior, and record the exact proof command.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Lua Guidelines
Use this as the shared Lua rubric for agents. Prefer repo-local conventions when they are deliberate and documented. Push back when they cause globals, silent failures, or an unsafe host boundary.
Source Of Truth
- Lua 5.4 Reference Manual: https://www.lua.org/manual/5.4/
- Programming in Lua, 4th edition (Roberto Ierusalimschy)
- LuaJIT documentation, including FFI, extensions, and NYI list: https://luajit.org/
- lua-users wiki style guide: http://lua-users.org/wiki/LuaStyleGuide
- The repo's
.luacheckrc, formatter config, and test runner.
Identify the target runtime first: PUC Lua 5.4, Lua 5.3, Lua 5.1, or LuaJIT (5.1 semantics plus extensions). Do not write code that depends on features the target lacks.
Core Rubric
- Dialects. LuaJIT has no integer subtype, no
//, no native bit operators (usebit.*), and no<close>or<const>. It hasgotoand the FFI. Lua 5.4 has integers,//,&,|,~,<<,>>,goto,<close>, and<const>. Write to the lowest common denominator only when the code must run on both. - Declare every variable
local. A global is allowed only for a documented host-provided name. Keep module state in locals. - Use the module pattern: build a local table
M, add functions, andreturn M. Do not callmodule()or set globals from a module. In 5.2 and later, replace the environment with_ENV. In 5.1 and LuaJIT, usesetfenv. - Tables have an array part and a hash part.
#tis only defined for sequences without holes. Never use#on a table that may containnilbetween elements. Track an explicit count or usetable.packand.n. - Use
t[#t + 1] = vortable.insert(t, v)to append. Usetable.removeonly when order must shift.ipairsstops at the firstniland is ordered.pairsorder is unspecified and can change between runs. Do not assign new keys to a table duringpairs. Assigningnilto an existing field is allowed. - Metatables: keep
__indexchains short (each level costs a lookup). Userawgetandrawsetinside__indexand__newindexto avoid recursion. Use__close(5.4) for scoped cleanup. Do not rely on__gcfor timely release. Use weak tables (__mode = "k"or"v") for caches, and remember that strings and numbers are never collected from weak tables. - Closures capture variables, not values. A loop variable is fresh per iteration, but an outer local is shared. Avoid creating closures in hot loops.
- Errors: use
error(value, level). Raise a table with acodeandmessagewhen callers must branch. Usepcallwhen the failure is handled. Usexpcallwithdebug.tracebackas the handler when the trace is needed. Never discard apcallresult. Re-raise what you cannot handle. Useassertfor invariants and note that its message argument is built eagerly. - Coroutines sequence work such as cutscenes and AI. Yield across
pcallworks in 5.2 and later and in LuaJIT 2.1, not in 5.1. A coroutine that errors is dead, so check theresumeresult. LuaJIT cannot yield across a C function boundary (alua_callfrom C or an FFI callback). - Strings are immutable and interned (short strings). Each
..creates a string. Build output with a table of parts andtable.concat. Lua patterns are not regex: no alternation, and-is a lazy quantifier. Use%to escape magic characters. Usestring.formatwith%qfor safe quoting. - Numbers: 5.4 distinguishes integer and float subtypes.
3 // 2is1,3 / 2is1.5, andmath.typetells them apart. Usemath.tointegerfor exact conversion.0/0is NaN andnan ~= nan, so never use NaN as a table key (it raises an error). Float to string formatting differs (1.0versus1). - Varargs: use
select('#', ...)for the true count, becausenilmay be present. Usetable.pack(...)to keepnilvalues.table.unpackneeds an explicit upper bound for tables with holes. - Validate types at API boundaries with
type()or a small checker, and fail with a message that names the argument and the expected type. Useerror(msg, 2)so the position points to the caller. - Data-definition tables are schemas. Validate required fields, types, ranges, and unknown keys at load time. Report the file and the field path. Freeze loaded definitions with a read-only proxy when scripts must not mutate them.
- Make the smallest coherent diff. No drive-by renames or formatting churn outside the change scope.
Performance
- Measure first. Profile with the engine's profiler,
os.clock, or LuaJIT's-jp. - Avoid table creation in per-frame loops: reuse tables, clear them in place, or pool them. Preallocate with
table.moveor a constructor of known size, ortable.newon LuaJIT. - Cache hot globals and fields in locals (
local floor = math.floor). A local lookup is a register access. - Avoid
..in loops. Avoidstring.formatandtostringon hot paths when a cached string works. - LuaJIT: stay on traced paths. Avoid NYI builtins in hot code (for example
string.gsubwith a function replacement,coroutinecalls, andunpackwith large counts). Check with-jvor-jdump. Usejit.off(fn)for cold or branchy code that causes trace aborts. Preferffi.newarrays for numeric buffers. - Tune the GC only with evidence. In 5.4 choose between
collectgarbage("incremental")and"generational". Callcollectgarbage("step")during idle frames instead of full collects.
C API And Embedding
- Stack discipline: every push needs a pop. Call
lua_checkstackorluaL_checkstackbefore pushing many values. Uselua_gettopto verify balance in tests. Convert negative indices withlua_absindexbefore pushing more. - Validate arguments with
luaL_check*andluaL_opt*. UseluaL_argerrorandluaL_errorfor failures. These longjmp (or throw in C++ builds), so do not leave C++ objects with destructors live on the frame, and do not call them while holding a resource that needs release. lua_tolstringpointers are valid only while the string value stays on the stack or reachable. Copy if you need it longer.lua_tostringon a number converts it in place and confuseslua_next.- Userdata: create with
lua_newuserdatauv, attach a metatable byluaL_setmetatable, test withluaL_checkudata. Put cleanup in__gc.__gccan run after the owning engine object dies, so use a validity flag or handle ids. Never store a raw pointer to a Lua-owned value in C. - Registry: pin a Lua value with
luaL_refand release it withluaL_unref. A leaked ref is a leak of the value. Upvalues onlua_pushcclosurehold per-function state. - Call Lua with
lua_pcalland a message handler that adds a traceback. Never use unprotectedlua_callfrom the host except inside a protected context. Never call into Lua from a signal handler. Set a flag and process it in the main loop. - A
lua_Stateis not thread safe. Use one state per thread, or serialize access.lua_newthreadcreates a coroutine state that shares the global state, so it is not a way to get parallelism. Anchor the thread object so it is not collected while in use. - Sandbox untrusted scripts by building a restricted environment table with an allowlist of functions. Do not expose
os,io,debug,package,dofile,loadfile, orrequireof arbitrary paths. Useload(chunk, name, "t", env)with mode"t"so precompiled bytecode is rejected. Blockstring.repabuse andsetmetatableon shared strings. Expose a metatable-protected string library. - Limit resources: use
lua_sethookwithLUA_MASKCOUNTto bound instructions, and a custom allocator passed tolua_newstateto cap memory. Use the hook to raise an error, never to continue silently. LuaJIT has no reliable count hook inside compiled traces, so usejit.offfor untrusted code or run it in a separate process. - Hot reload: clear
package.loaded[name]and re-require. Keep state in a separate table that survives reload, and migrate it with a versioned function. Re-register callbacks after reload. Remove old event handlers, or they run twice. Do not reload while a coroutine from the old module is suspended unless it is discarded.
Anti-Slop Checklist
Reject or fix these patterns on sight, whether writing or reviewing:
- Implicit globals from a missing
local, including loop variables and function names. #ton a table with holes ornilentries, andtable.insert(t, pos, nil).pcall(f)with the result ignored, orif not ok then end, or an error converted tonilwith no log.error("message")strings where callers need a code, and error tables with no message.- Using
pairswhere order matters, and mutating a table while iterating it. - String building with
s = s .. xin a loop. tostring(x) == "nil"style checks, and comparing floats with==after arithmetic.load(str)of data from users or the network without a sandbox environment and a size limit.- Methods called with
.instead of:(or the reverse) in a class pattern. requireof a path built from user input.- Deep
__indexinheritance chains used for plain data. - Comments that restate the code, and commented-out blocks left in delivered changes.
- A module that sets globals or mutates
string,table, ormathfor the whole process.
Verification
Use exact repo-native gates first. Typical gates are luacheck . (with the repo's .luacheckrc), the configured formatter check (stylua --check . or lua-format), and the configured test runner (busted or the repo's script).
Reach for these only when the repo has them or the change justifies them. Do not install tooling speculatively:
lua -e 'require("mod")'orluajit -e ...as a smoke run of the changed module on the target runtime.luajit -jv script.luato list trace aborts, and-jpfor a sampling profile.- A build of the host with AddressSanitizer and UBSan when auditing C bindings.
lua_gettopassertions in binding tests, and a loop that creates and destroys the bound object many times.collectgarbage("count")before and after a loop to check for leaks.
Adversarial Checklist
Push back when a change or suggestion hits these traps:
- Sandbox by blocklist. Removing
os.executefrom a full_Gleavesio,load,debug, and string metatable escapes. Build an allowlist environment instead. loadof text without a mode.load(s)accepts bytecode, which can crash the VM. Pass mode"t".- Instruction hook on LuaJIT. Count hooks do not fire inside compiled traces. Use
jit.off, an allocator limit, or process isolation. #on a sparse table. The result is any valid border. Use an explicit count.- Error thrown through C++ frames.
luaL_errorlongjmps over destructors. Compile Lua as C++ or release resources before raising. __gctouching freed host objects. Finalizers run late and in any order. Use handle ids and a validity check.- Hot reload leaking handlers. Old closures stay registered. Unregister before reload.
- Caching with strong references. A cache keyed by object keeps it alive. Use weak keys or values.
Output Contract
When reviewing, lead with severity-ranked findings and concrete file and line evidence. Each finding explains why the current Lua shape is risky and names the safer direction. State the target runtime you assumed.
When implementing, make the smallest coherent change, add or update tests for observable behavior, and record the exact proof command.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

