Installation
Download the latest wuuvy.jar release from your license portal after purchase. That single JAR is the entire application - there is no installer, no native binary, no setup step. Save it wherever you like.
Optionally, run the install command once to self-obfuscate the JAR and drop wuuvy, ofc-jar, and ofc-jar-inside launchers on your PATH, so you can call them from any terminal - cmd, PowerShell, IntelliJ's terminal, VS Code's terminal, git-bash, WSL.
Launching wuuvy
wuuvy runs as a graphical, interactive terminal window. Launch it the same way you'd open any runnable JAR:
- Windows: double-click
wuuvy.jar, or runjavaw -jar wuuvy.jarfrom a shortcut. - macOS: double-click
wuuvy.jarfrom Finder, or runjava -jar wuuvy.jarfrom Terminal. - Linux:
java -jar wuuvy.jarfrom any shell.
When it opens, you'll see the wuuvy terminal window with the banner and an interactive prompt:
From this point, everything happens inside the wuuvy terminal - you type commands at the wuuvy\> prompt and press Enter.
Quick Start
The fastest way to protect a JAR: launch wuuvy, run ofc, and pick your JAR in the file dialog that appears.
wuuvy writes the protected JAR next to the original, suffixed with _ofc. No source changes, no runtime agent, no manifest editing required.
all profile enables every pass, including runtime hardening and anti-analysis tripwires. For most commercial apps you'll want a tailored profile - see the technique flags and presets sections below.Requirements
- Java Runtime: JRE or JDK 8 or newer to run wuuvy itself.
- Target class format: wuuvy produces class files valid for JVM 8 through JVM 24.
- Display: the interactive terminal opens a graphical window, so a desktop environment is required for it. For headless servers and CI, use the command-line entry point instead - it has no GUI dependency.
- Memory: for JARs under 100 MB the default heap is sufficient. Larger JARs may benefit from launching with
-Xmx2gor higher.
Terminal Commands
Every command is typed at the wuuvy\> prompt. Arguments are comma-separated, no spaces. Names are case-insensitive.
| Command | What it does |
|---|---|
ofc | Opens a file picker. Applies the full all profile to the JAR you select and writes <name>_ofc.jar next to it. |
ofc-jar <flags> | Opens a file picker, then applies a custom comma-separated list of techniques. Example: ofc-jar rename,string-enc,shuffle. |
ofc-list | Prints every available transformation flag, grouped by category. |
install | Self-obfuscates the running wuuvy jar, installs it to ~/.wuuvy/, and adds wuuvy, ofc-jar, and ofc-jar-inside launchers to your user PATH. |
uninstall | Removes the install directory and drops the PATH entry created by install. |
cls | Clears the terminal window. |
exit | Closes the wuuvy terminal. |
Selecting a JAR
Whenever you run ofc or ofc-jar, wuuvy pops up a native file-chooser dialog so you can pick the target. The dialog remembers your last-used directory between runs, so repeat builds only take two clicks.
wuuvy writes the output JAR to the same directory as the input, with the suffix _ofc. For example, selecting C:\dev\projects\app\app.jar produces C:\dev\projects\app\app_ofc.jar. The original is never modified.
Technique Flags
Run ofc-list inside wuuvy to print the full list. Each name shown is exactly the token you pass to ofc-jar (or to -t on the command line). For detailed descriptions of what each pass does and when to use it, see the Techniques Reference on the home page.
Example - a light, IDE-friendly combination:
install / uninstall
The interactive terminal is convenient for one-offs, but for everyday use you'll want wuuvy available from any shell. Run install once inside the GUI terminal:
What install actually does:
- Self-obfuscates the current wuuvy jar using a conservative profile that's been validated to keep it runnable after the pass (so the copy on disk doesn't look anything like the downloaded one).
- Copies the result to
~/.wuuvy/wuuvy.jar. - Writes launchers (
.cmdon Windows, shell scripts elsewhere) into~/.wuuvy/bin/:wuuvy,ofc-jar, andofc-jar-inside. - Appends
~/.wuuvy/binto your userPATH- via[Environment]::SetEnvironmentVariable('Path', ..., 'User')on Windows, or anexport PATHline in.zshrc/.bashrc/.profileon Unix.
Open a new terminal afterwards so the PATH change is picked up. uninstall reverses all of that.
ofc-jar (any terminal)
ofc-jar is the simplest way to obfuscate from any shell after install. It accepts a preset name (all, mod, mod-strict, methods, light, paranoid) or a comma-separated list of techniques as the first argument.
Bad technique names fail fast with unknown technique: foo instead of being silently dropped. The result jar is <name>_ofc.jar in the current directory unless you give an explicit output path.
wuuvy <jar>
Once installed, wuuvy is a headless CLI - no GUI, suitable for scripts and CI. Run it against an existing jar and it writes <name>_ofc.jar into your current working directory.
ofc-jar-inside (build + obfuscate in one step)
ofc-jar-inside is an alias for wuuvy inside. You run it from inside a project directory - it walks up looking for a pom.xml, build.gradle(.kts), an IntelliJ .idea folder, or the newest built jar, runs the right build command, then obfuscates the result.
The output JAR is dropped into the current working directory (not target/ / build/libs/), so it doesn't clash with your build outputs and is easy to attach to a release.
Maven Projects
When ofc-jar-inside finds a pom.xml at (or above) the current directory, it invokes Maven directly:
It then takes the newest JAR in target/ and obfuscates it. A typical run looks like:
For repeat builds, wire wuuvy into the package phase of your pom.xml with the snippet generated by wuuvy maven-init. Then a normal mvn package produces both the regular jar in target/ and the obfuscated <name>_ofc.jar next to it.
Gradle Projects
When a build.gradle or build.gradle.kts is detected, ofc-jar-inside runs the project's own Gradle wrapper if present, otherwise the installed gradle:
It then picks the newest JAR under build/libs/ (skipping -sources.jar, -javadoc.jar, and any previously-obfuscated *_ofc.jar) and obfuscates it. Shadow/fat jars work - the newest-modified jar wins, so if your shadowJar task produces build/libs/app-all.jar, that's what gets picked up.
For repeat builds, wire wuuvy into your Gradle build with the snippet generated by wuuvy gradle-init. Then ./gradlew obfuscate produces both jars in build/libs/.
wuuvy integrate (Gradle / Maven plugin in one command)
wuuvy integrate auto-detects the build system in your current directory and writes a ready-to-paste integration snippet:
Gradle
The Gradle generator detects whether you have build.gradle (Groovy) or build.gradle.kts (Kotlin DSL) and emits the matching syntax. The generated wuuvy.gradle adds an obfuscate task that runs after jar:
Output is build/libs/<name>_ofc.jar. Uncomment the tasks.named('build') { dependsOn 'obfuscate' } line at the bottom of the snippet to make every ./gradlew build produce the obfuscated jar automatically.
Maven
The Maven generator writes a wuuvy-pom-snippet.xml with a complete <plugin> block built on exec-maven-plugin, bound to the package phase. Paste it into <build><plugins>...</plugins></build>:
Output is target/<name>_ofc.jar. The snippet reads ${user.home}/.wuuvy/wuuvy.jar - i.e. the install you already have - so there is no Maven Central artifact to depend on, and offline builds work as long as install has been run on the build agent.
java -jar ~/.wuuvy/wuuvy.jar ofc-jar <techs> <in> <out>. There's no plugin artifact to download and no transitive dependencies dragged into your build. If ~/.wuuvy/wuuvy.jar is missing, the task fails loudly with a clear message rather than silently producing an unprotected jar.CI/CD
CI environments are headless, so the GUI terminal isn't available there. Use the installed CLI on the build agent instead. A typical pattern:
- Stage
wuuvy.jarin a trusted location (artifact cache, internal release bucket, or the repo itself under.ci/). - On the agent, run
java -jar wuuvy.jar <your-built.jar> -methods -o dist/app.jarafter your normal build step. Noinstallis needed -java -jaris sufficient for one-shot invocations. - Upload the resulting
_ofc.jaras your release artifact.
A few things worth knowing:
- Exit codes: the CLI returns
0on success,2if the input jar isn't found,3ifinsidecouldn't locate or build a jar, non-zero for any other failure. Your pipeline's default "fail on non-zero" behaviour is sufficient. - No display needed: only the interactive
Mainentry opens a Swing window. ThewuuvyCLI (theWuuvyentry point) andwuuvy insiderun fully headless. You do not needxvfb. - Non-determinism: the seed defaults to
System.currentTimeMillis(), so renaming and layout differ run-to-run. If you need byte-reproducible output, keep the output jar as the released artifact rather than trying to reproduce it. - Caching: wuuvy has no build-avoidance of its own. If you want to skip re-obfuscation when inputs haven't changed, gate the step in your pipeline by hashing the input jar.
Presets
The CLI exposes a handful of shorthand presets in addition to -t <list>. The standalone ofc-jar takes them as the first positional argument; wuuvy takes them as -<name> flags.
| Preset | Expands to | Use it when |
|---|---|---|
all | the all meta-technique (every pass) | you want maximum protection and have verified your app runs under it |
mod | Minecraft-mod-safe technique set (Forge / Fabric / NeoForge). Excludes anno-strip, access-max, resource-enc, manifest-clean, main-rename, strip-inner, and debug | you're shipping a Minecraft mod and need to keep the loader, mixin transformer, and asset reader functional |
mod-strict | mod plus the techniques added since the original mod set was tuned (array-enc, ldc-widen, cd-junk) and the anti-tamper layer (anti-dump, crc32-check). User-config opt-ins (sig-check / env-gate / fp-gate) are still off - those need explicit setup to not self-halt | you're pushing a mod harder and accept a small compatibility risk; back off to plain mod if issues arise |
methods | junk-methods, dup-methods, rename, main-rename, rename-static, sig-strip, param-strip, nop-insert, opaque-pred | you want method-level obfuscation without touching strings, control flow, or class layout |
light | debug, rename, shuffle, strip-inner, synth | you just want identifiers renamed and debug info stripped - safe for almost any framework |
paranoid | all plus anti-dump, crc32-check, sig-check, env-gate, fp-gate, verify-readback. Will halt the JVM unless the jar is signed, OFC_RUN_KEY matches, and host fingerprint matches the obfuscation host | shipping a one-host one-runtime build; do NOT use for portable jars or anything tested without signing |
The interactive terminal doesn't use these preset names directly - ofc always applies all, and the in-terminal ofc-jar takes a comma-separated technique list. The standalone ofc-jar command (after install) accepts both presets and technique lists as the first positional arg.
Minecraft Mods
Minecraft mods have hard constraints - reflection-heavy loaders (Forge / Fabric / NeoForge), Sponge Mixin transformers, annotation-driven entry points. The mod preset is hand-tuned to compose with these.
The obfuscator already has Mod awareness built in:
- Mod entry points are protected from rename: classes referenced from
fabric.mod.json,META-INF/mods.toml,META-INF/neoforge.mods.toml, and any*.mixins.jsonare auto-collected and excluded from class renaming. - Mixin classes are skipped: any class with the
@Mixinannotation is preserved verbatim.boze.mixins.jsonstill resolves its targets by name after obfuscation. - Reflection-protected names:
Class.forName/getDeclaredMethod/getDeclaredFieldstring arguments are scanned across the jar and added to the no-rename set.
Ship the auto-emitted ProGuard-format .mapping file with releases - without it, user crash reports become unreadable obfuscated stack traces.
anno-strip strips @Mod / @SubscribeEvent; access-max breaks final invariants Forge relies on; resource-enc would encrypt textures, sounds, and lang files; main-rename is a no-op (mods have no Main-Class); debug strips line numbers so user crash reports become unreadable.Troubleshooting
wuuvy window closes immediately after launch
Usually means a mismatched Java runtime. wuuvy needs Java 8 or newer. Run java -version from your terminal to check what's installed. On Windows, if double-clicking the JAR does nothing, try launching it from a terminal with java -jar wuuvy.jar so you can see any error output.
install says "added to user PATH" but wuuvy still isn't found
Windows and most shells only re-read environment variables when a process starts, so the terminal you ran install from won't see the change. Close it and open a new one. On Unix, either open a new shell or source the rc file install appended to (it tells you which).
ClassNotFoundException / NoSuchMethodError at runtime
Almost always caused by reflection or service loading in the protected app. Reproduce with a lighter preset to confirm - rerun with -light, and if the error disappears, renaming or stripping is hitting a reflectively-loaded class. Launching the protected app with -verbose:class will show exactly which class the JVM failed to find.
Protected JAR launches but throws at a specific method
Likely one aggressive pass conflicting with your code. Bisect with -t to isolate the culprit - start by removing cff, opaque-pred, indy-hide-*, and const-math. When the failing pass is identified, fall back to a technique list that excludes it (for example, build on top of -methods or -light rather than -all).
Slower startup after obfuscation
Expected if you enabled string-enc, clinit-finals, or any indy-hide-* pass - decryption and trampoline code runs at class load. For cold-start-sensitive apps (AWS Lambda, serverless), drop to -methods or -light and profile before adding heavier passes back.
ofc-jar-inside: "could not find or build a jar under <dir>"
The auto-detector couldn't find a pom.xml, build.gradle(.kts), IntelliJ artifact output under out/artifacts/, or a plain jar within three directories of where you ran it. Either run from inside the project root, pass --root, or build the jar yourself and call wuuvy <path-to-jar> directly.
My framework's reflection stops working
Most frameworks need reflection-touched classes to keep their original names. Common problem areas:
- Spring:
@Component,@Service,@Repository,@Controllerclasses, and the fields Spring injects into them. - Jackson / Gson: every DTO/POJO you (de)serialize - field names are the wire format.
- JPA / Hibernate:
@Entityclasses and their fields. - JavaFX / FXML: controllers referenced by
fx:controller.
In the current release the pragmatic answer is to drop back to -methods or -light and skip the identifier-rewriting passes that are breaking reflection. Finer-grained keep rules are on the roadmap.