Skip to content

jehna/humanify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

398 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

humanify

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.

Version 3 is out! πŸŽ‰

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!

Example

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.js

Result (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.js

To unbundle Webpack output first, pipe through npx webcrack:

npx webcrack < bundle.min.js | humanify openai - -o bundle.js

Note on token usage

🚨 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.

Getting started

Installation

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 page

Or build from source:

cargo install --git https://github.com/jehna/humanify

Usage

humanify <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.
  • -v enables 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.js

OpenAI mode

You'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-token

Or via environment variable:

export OPENAI_API_KEY=your-token
humanify openai obfuscated.js -o readable.js

Default model: gpt-5-mini. Override with -m.

Gemini mode

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.js

Default model: gemini-3.1-flash-lite. Override with -m.

Anthropic mode

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.js

Default 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 (Ollama)

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:

  1. Install Ollama: https://ollama.com/download
  2. Pull the recommended model: ollama pull qwen3.5:4b

Then run:

humanify ollama obfuscated.js -o readable.js

Default 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/v1

OpenRouter mode

OpenRouter 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.js

Default model: openai/gpt-oss-120b. For free-tier usage:

humanify openrouter obfuscated.js -m qwen/qwen3-coder:free

Features

  • 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

Contributing

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 test

CI 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.

Star History

Star History Chart

Licensing

The code in this project is licensed under MIT license.

About

Deobfuscate Javascript code using ChatGPT

Resources

License

Stars

Watchers

Forks

Contributors

Languages