Un-minify Lua code using LLMs ("AI")
This tool uses large language models (like ChatGPT, Claude, Gemini, and locally-hosted Ollama models) to unminify and rename minified or obfuscated Lua code. The LLM only suggests new identifier names; the heavy lifting is done by full_moon, a lossless Lua parser, so the rewritten code is byte-identical to the input except for the renamed identifiers β humanify does not reformat or reindent your code.
Given the following minified code in splitstring.min.lua:
local function a(e,t)local n={}local r=#e local i=1 while i<=r do local j=i+t-1 if j>r then j=r end table.insert(n,e:sub(i,j)) i=i+t end return n endRun:
humanify-lua openai splitstring.min.lua -o splitstring.luaResult (splitstring.lua):
local function split_string(input_string,chunk_size)local chunks={}local length=#input_string local start_index=1 while start_index<=length do local end_index=start_index+chunk_size-1 if end_index>length then end_index=length end table.insert(chunks,input_string:sub(start_index,end_index)) start_index=start_index+chunk_size end return chunks endOnly the identifiers changed β humanify never reflows or reindents your code, so if you want it pretty-printed too, pipe the result through a Lua formatter such as StyLua:
humanify-lua openai splitstring.min.lua | stylua - -o splitstring.luaYou can also pipe via stdin:
cat splitstring.min.lua | humanify-lua openai - > splitstring.luaπ¨ NOTE: π¨
humanify-lua makes one LLM call per identifier in your code. For ChatGPT-class APIs the cost roughly scales with the number of identifiers and the surrounding context window (default 500 chars per call). A medium minified file (~500 identifiers) typically costs in the range of $0.10β$1.00 with OpenAI's small models, free with the Gemini free tier, and free with Ollama or OpenRouter free models.
For a rough character-count estimate of OpenAI mode:
echo "$((2 * $(wc -c < yourscript.min.lua)))"Using humanify-lua ollama is free but slower; quality depends on your local model.
Free OpenRouter models (e.g. qwen/qwen3-coder:free) can help with your budget,
but expect them to be heaviy rate limited.
The preferred way to install humanify-lua is to download a pre-built binary from the latest release.
# macOS (Apple Silicon)
curl -L https://github.com/opastorello/humanify-lua/releases/latest/download/humanify-lua-aarch64-apple-darwin.tar.gz | tar xz
sudo mv humanify-lua /usr/local/bin/
# macOS (Intel)
curl -L https://github.com/opastorello/humanify-lua/releases/latest/download/humanify-lua-x86_64-apple-darwin.tar.gz | tar xz
sudo mv humanify-lua /usr/local/bin/
# Linux (x86_64)
curl -L https://github.com/opastorello/humanify-lua/releases/latest/download/humanify-lua-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv humanify-lua /usr/local/bin/
# Linux (aarch64)
curl -L https://github.com/opastorello/humanify-lua/releases/latest/download/humanify-lua-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv humanify-lua /usr/local/bin/
# Windows: download humanify-lua-x86_64-pc-windows-msvc.zip from the releases pageOr build from source:
cargo install --git https://github.com/opastorello/humanify-luahumanify-lua <openai|gemini|anthropic|ollama|openrouter|requesty> [FLAGS] <INPUT><INPUT>is a file path or-for stdin.-o <FILE>writes to a file (default: stdout).-m <MODEL>overrides the preset's default model.-k <KEY>overrides the env-var-based API key.--base-url <URL>overrides the preset's base URL.--context-size <N>sets surrounding-code chars per identifier (default 500).--json-mode <MODE>pins a JSON-mode strategy. Options:ladder(default),openai-json-schema,anthropic-native,forced-tool-call,tool-call-and-prompt,prompt.-vprints resolved configuration and identifier-level rename steps to stderr.--progressshows an identifier progress bar on stderr.
Run humanify-lua --help for the full reference.
Note: humanify-lua does one job β rename identifiers in one Lua file in, one out. It supports Lua 5.1 through 5.4, LuaJIT, and CitizenFX/FiveM syntax extensions (compound assignment, safe navigation, etc). It does not reverse control-flow flattening, string encryption, or other bytecode/VM-level obfuscation (e.g. from Luraph or Prometheus) β only identifier renaming.
You'll need an OpenAI API key. Sign up at https://openai.com/ and create a key in the dashboard.
humanify-lua openai obfuscated.lua -o readable.lua -k your-tokenOr via environment variable:
export OPENAI_API_KEY=your-token
humanify-lua openai obfuscated.lua -o readable.luaDefault model: gpt-5-mini. Override with -m.
You'll need a Google AI Studio key. Sign up at https://aistudio.google.com/. Gemini's free tier is generous and is enough for most files.
export GEMINI_API_KEY=your-token
humanify-lua gemini obfuscated.lua -o readable.luaDefault model: gemini-3.1-flash-lite. Override with -m.
You'll need an Anthropic API key. Sign up at https://console.anthropic.com/.
export ANTHROPIC_API_KEY=your-token
humanify-lua anthropic obfuscated.lua -o readable.luaDefault model: claude-sonnet-4-6. Override with -m.
The Anthropic preset uses Anthropic's native structured-outputs API
(output_format: json_schema) when available, falling back to forced
tool-calls if your account doesn't have the structured-outputs beta enabled.
Local mode runs against Ollama, which manages local LLM
weights and exposes an OpenAI-compatible API on localhost:11434. (pre-v3
migration note: There's no humanify download anymore β use a local inference
provider like Ollama to run your own models)
Prerequisites:
- Install Ollama: https://ollama.com/download
- Pull the recommended model:
ollama pull qwen3.5:4b
Then run:
humanify-lua ollama obfuscated.lua -o readable.luaDefault model: qwen3.5:4b. Override with -m to use any model you've
pulled. Local mode is free and private, but slower and less accurate than
the hosted providers; quality depends on the model you pick.
If you want to point humanify-lua at a remote Ollama instance, override the base URL:
humanify-lua ollama obfuscated.lua --base-url http://my-server:11434/v1OpenRouter routes requests across many backend models. Useful for trying free-tier coding models without setting up multiple accounts.
You'll need an OpenRouter API key. Sign up at https://openrouter.ai/.
export OPENROUTER_API_KEY=your-token
humanify-lua openrouter obfuscated.lua -o readable.luaDefault model: openai/gpt-oss-120b. For free-tier usage:
humanify-lua openrouter obfuscated.lua -m qwen/qwen3-coder:freeRequesty provides an OpenAI-compatible router across many backend models via a single API key.
You'll need a Requesty API key. Sign up at https://requesty.ai/.
export REQUESTY_API_KEY=your-token
humanify-lua requesty obfuscated.lua -o readable.luaDefault model: nvidia/nemotron-3-super-120b-a12b. Override with -m:
humanify-lua requesty obfuscated.lua -m nvidia/nemotron-3-super-120b-a12b- Uses LLMs to get smart suggestions to rename variable and function names, and make the rename deterministically with full_moon, a lossless Lua parser β no reformatting, no reflowing, just renamed identifiers
- Supports Lua 5.1, 5.2, 5.3, 5.4, LuaJIT, and CitizenFX/FiveM (
cfxlua) syntax extensions β compound assignment (+=), safe navigation (?.),local a, b in tfield-unpacking,{ .a }set constructors, C-style/* */comments, and`hash`backtick string literals - Renames preserve all references and respect lexical scoping, including
upvalues captured by closures and the implicit
selfinfunction t:m()methods - Reserved-word and collision-aware safe naming. The LLM's suggestion is normalised to a valid Lua identifier and suffixed with a number if it collides with an existing binding
If you'd like to contribute, please fork the repository and use a feature branch. Pull requests are warmly welcome.
git clone https://github.com/opastorello/humanify-lua
cd humanify
cargo build
cargo testCI runs cargo fmt --check, cargo clippy -D warnings, cargo test on
every PR. Local ollama and judge e2e suites also run on every PR.
The gemini e2e suite runs by default only for branches in this repository.
Other providers' e2e suites require both a branch in this repository and
their corresponding label (test-openai, test-anthropic,
test-openrouter, test-requesty) to avoid exposing secrets to forks or
burning API credits on every PR.
The code in this project is licensed under MIT license.