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|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 --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: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 requesty obfuscated.js -o readable.jsDefault model: nvidia/nemotron-3-super-120b-a12b. Override with -m:
humanify requesty obfuscated.js -m nvidia/nemotron-3-super-120b-a12b- 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. 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.