Un-minify JavaScript code using LLMs ("AI")
This tool uses large language models (like ChatGPT, Claude, Gemini, and locally-hosted Ollama models) to unminify and rename minified JavaScript code. The LLM only suggests new identifier names; the heavy lifting is done by oxc at the AST level so the rewritten code remains structurally identical to the input.
v3 highlights compared to v2:
- Single static binary: (Rust) β grab a binary from Releases. No Node, no npm, no Python.
- Unix-style I/O: read from stdin or a file, write to stdout or
-o <file>. Combine easily with a deobfuscator like webcrack. - New providers: Ollama (local), Anthropic and OpenRouter.
Check out the v3 PR for more info.
β‘οΈ Check out the introduction blog post for in-depth explanation!
Given the following minified code in splitstring.min.js:
function a(e,t){var n=[];var r=e.length;var i=0;for(;i<r;i+=t){if(i+t<r){n.push(e.substring(i,i+t))}else{n.push(e.substring(i,r))}}return n}Run:
humanify openai splitstring.min.js -o splitstring.jsResult (splitstring.js):
function splitString(inputString, chunkSize) {
var chunks = [];
var stringLength = inputString.length;
var startIndex = 0;
for (; startIndex < stringLength; startIndex += chunkSize) {
if (startIndex + chunkSize < stringLength) {
chunks.push(inputString.substring(startIndex, startIndex + chunkSize));
} else {
chunks.push(inputString.substring(startIndex, stringLength));
}
}
return chunks;
}You can also pipe via stdin:
cat splitstring.min.js | humanify openai - > splitstring.jsTo unbundle Webpack output first, pipe through npx webcrack:
npx webcrack < bundle.min.js | humanify openai - -o bundle.jsπ¨ NOTE: π¨
humanify 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.js)))"Using humanify 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 is to download a pre-built binary from the latest release.
# macOS (Apple Silicon)
curl -L https://github.com/jehna/humanify/releases/latest/download/humanify-aarch64-apple-darwin.tar.gz | tar xz
sudo mv humanify /usr/local/bin/
# macOS (Intel)
curl -L https://github.com/jehna/humanify/releases/latest/download/humanify-x86_64-apple-darwin.tar.gz | tar xz
sudo mv humanify /usr/local/bin/
# Linux (x86_64)
curl -L https://github.com/jehna/humanify/releases/latest/download/humanify-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv humanify /usr/local/bin/
# Linux (aarch64)
curl -L https://github.com/jehna/humanify/releases/latest/download/humanify-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv humanify /usr/local/bin/
# Windows: download humanify-x86_64-pc-windows-msvc.zip from the releases pageOr build from source:
cargo install --git https://github.com/jehna/humanifyhumanify <openai|gemini|anthropic|ollama|openrouter> [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.-venables verbose stderr logging.
Run humanify --help for the full reference.
Note: humanify does one job β rename identifiers in one JavaScript file in, one out. To unbundle webpack output first, pipe through e.g. webcrack:
npx webcrack < bundle.min.js | humanify openai - -o bundle.jsYou'll need an OpenAI API key. Sign up at https://openai.com/ and create a key in the dashboard.
humanify openai obfuscated.js -o readable.js -k your-tokenOr via environment variable:
export OPENAI_API_KEY=your-token
humanify openai obfuscated.js -o readable.jsDefault 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 gemini obfuscated.js -o readable.jsDefault 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 anthropic obfuscated.js -o readable.jsDefault 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 ollama obfuscated.js -o readable.jsDefault 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 at a remote Ollama instance, override the base URL:
humanify ollama obfuscated.js --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 openrouter obfuscated.js -o readable.jsDefault model: openai/gpt-oss-120b. For free-tier usage:
humanify openrouter obfuscated.js -m qwen/qwen3-coder:free- Uses LLMs to get smart suggestions to rename variable and function names, and make the rename using deterministic AST-level shenanigans via oxc
- Renames preserve all references and respect lexical scoping
- Reserved-word and collision-aware safe naming. The LLM's suggestion is
normalised to a valid JS identifier and
_-prefixed 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/jehna/humanify
cd humanify
cargo build
cargo testCI runs cargo fmt --check, cargo clippy -D warnings, cargo test on
every PR. Provider e2e suites run against gemini (every PR, free tier)
and ollama (every PR, runs on the GitHub runner). Other providers'
e2e suites are label-gated (test-openai, test-anthropic,
test-openrouter) to avoid burning API credits on every PR.
The code in this project is licensed under MIT license.