wuuvy wuuvy
Documentation

wuuvy Docs

How to install wuuvy, run it from a normal terminal, point it at a config file, and wire it into Maven or Gradle. Short version: it's one jar and a handful of commands.

Install

After you buy a license, grab wuuvy.jar from your dashboard. That one jar is the whole thing. You need Java 8 or newer on your machine (check with java -version), and that's it.

You've got two ways to use it:

  • Just run it. java -jar wuuvy.jar app.jar protects app.jar right there. Nothing to set up. Great for a quick try or for CI.
  • Or install it once so you can type wuuvy from anywhere. Double-click wuuvy.jar (or run java -jar wuuvy.jar install). A small installer window opens — click Install.

The installer copies wuuvy into ~/.wuuvy/ and adds three commands to your PATH: wuuvy, ofc-jar, and ofc-jar-inside. They work in cmd, PowerShell, bash, WSL, and the terminal built into IntelliJ or VS Code. Open a new terminal afterwards so it picks up the PATH change.

Heads up: that window is just the installer — Install and Uninstall buttons, nothing else. There's no shell inside it. All the real work happens in your own terminal with the commands below.

Quick start

Once it's installed, protecting a jar is one line in any terminal:

PowerShell
–
☐
×
PS C:\dev\app> wuuvy app.jar In : C:\dev\app\app.jar Out : C:\dev\app\app_ofc.jar Map : C:\dev\app\app_ofc.jar.mapping Preset: fortify classes=1284 methods=9214 strings=3380 Done in 4.8s (errors=0) PS C:\dev\app>

wuuvy writes the protected jar next to the original with an _ofc suffix, plus a matching .mapping file (keep that one — it's how you read crash reports later). Your original jar is never touched. No source changes, no runtime agent, nothing for your users to install.

Which settings did that use? A bare wuuvy app.jar runs the fortify preset — the strong, safe default that doesn't rename classes, so it's the least likely to upset reflection or frameworks. Want more or less? See presets.

Requirements

  • Java: JRE or JDK 8 or newer to run wuuvy.
  • What it can output: class files for Java 8 all the way up to Java 24.
  • Servers and CI: the command line is fully headless — no screen needed. The only window wuuvy ever opens is the installer, and you can skip that entirely with java -jar wuuvy.jar app.jar.
  • Memory: the default heap is fine for jars under ~100 MB. For bigger ones, give it more room with java -Xmx2g -jar wuuvy.jar ....

Commands

These are the commands the installer puts on your PATH. Anywhere you see wuuvy, you can also write java -jar wuuvy.jar if you skipped the install step.

CommandWhat it does
wuuvy <jar>Protect a jar with the default fortify preset. Add a preset flag or -t to change that. Writes <name>_ofc.jar.
ofc-jar <what> <jar>Same idea, but you lead with the preset or technique list: ofc-jar mod my-mod.jar.
ofc-jar-insideBuild the project you're standing in, then protect whatever it produced. Handy mid-development.
wuuvy listPrint every technique name, grouped by what it's for.
wuuvy doctor <jar>Look over a jar and suggest a preset (spots frameworks, reflection, mods).
wuuvy templateWrite a starter config file you can edit and reuse.
wuuvy mappingTurn an obfuscated stack trace back into readable names using a .mapping file.
wuuvy install / uninstallOpen the installer, or remove wuuvy from your PATH again.
wuuvy version / helpShow the version, or the full list of commands and flags.

Run wuuvy help any time for the complete list — there are more small tools in there (verify, compare, info, and friends) than most people need day to day.

Picking techniques by hand

Most of the time a preset is all you want. But if you'd rather choose the exact passes, run wuuvy list to see every name, then pass them with -t (comma-separated, no spaces). Each name is also explained on the Techniques page.

# a light, IDE-friendly mix, chosen by hand wuuvy app.jar -t rename,rename-fields,string-enc,shuffle,debug

ofc-jar

ofc-jar is the same obfuscator as wuuvy <jar>, just with the preset (or technique list) out front. Use whichever reads nicer to you. The first argument is a preset name (fortify, light, methods, turbo, all, mod, mod-strict, paranoid) or a comma-separated list of techniques.

# Forms accepted ofc-jar <techs> # build current project, then obfuscate ofc-jar <techs> <in.jar> # obfuscate <in.jar> -> <in>_ofc.jar in cwd ofc-jar <techs> <in.jar> <out.jar> # obfuscate to explicit output path # Examples ofc-jar all my-app.jar ofc-jar mod my-mod.jar # Minecraft-mod-safe preset ofc-jar string-enc,int-enc,cff foo.jar foo-stealth.jar ofc-jar methods # in cwd, build then obfuscate

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>

This is the plain command-line way in: no window, works in scripts and CI. Point it at a jar and it writes <name>_ofc.jar (plus the .mapping) into the folder you're in. With no preset given, it uses fortify.

# default: the fortify preset (strong, safe, no class renaming) wuuvy app.jar # pick a different preset with -<name> wuuvy app.jar -methods wuuvy app.jar -light wuuvy app.jar -all # or spell out the exact techniques wuuvy app.jar -t rename,rename-fields,string-enc,shuffle,debug # choose where the output goes wuuvy app.jar -methods -o dist/app.jar # see everything it can do wuuvy list wuuvy help

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.

# from the root of any Maven or Gradle project ofc-jar-inside # with a preset or explicit techniques ofc-jar-inside -methods ofc-jar-inside -light ofc-jar-inside -t rename,string-enc,shuffle # force a different project root ofc-jar-inside --root path/to/project # override where the _ofc.jar lands ofc-jar-inside -methods -o release/app-stealth.jar

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:

mvn -q -DskipTests package

It then takes the newest JAR in target/ and obfuscates it. A typical run looks like:

PowerShell
–
☐
×
PS C:\dev\my-service> ofc-jar-inside -methods Root : C:\dev\my-service Build : mvn package (in C:\dev\my-service) Built : C:\dev\my-service\target\my-service-1.4.0.jar Out : C:\dev\my-service\my-service-1.4.0_ofc.jar Tech : [junk-methods, dup-methods, rename, main-rename, rename-static, sig-strip, param-strip, nop-insert, opaque-pred] Elapsed: 2915 ms

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:

# if ./gradlew[.bat] exists: ./gradlew build -q -x test # otherwise: gradle build -q -x test

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:

# From inside any Gradle or Maven project root: wuuvy integrate # Or call the specific generators directly: wuuvy gradle-init # writes wuuvy.gradle (or .kts) next to build.gradle wuuvy gradle-init -preset mod # bake in the 'mod' preset wuuvy maven-init # writes wuuvy-pom-snippet.xml next to pom.xml wuuvy maven-init -preset all # bake in 'all'

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:

// add this one line to build.gradle apply from: 'wuuvy.gradle' // then: ./gradlew obfuscate # uses the preset baked at gradle-init time ./gradlew obfuscate -Pofc.tech=methods # override at command line ./gradlew obfuscate -Pofc.tech=string-enc,int-enc,cff

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>:

mvn package # uses the preset baked at maven-init time mvn package -Dofc.tech=methods # override at command line mvn package -Dofc.tech=string-enc,int-enc,cff

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.

How it works: both generated snippets just exec 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 runners don't have a screen, which is fine — wuuvy's command line doesn't need one. You don't even have to install it; just run the jar after your build step. A typical pattern:

  1. Stage wuuvy.jar in a trusted location (artifact cache, internal release bucket, or the repo itself under .ci/).
  2. On the agent, run java -jar wuuvy.jar <your-built.jar> -methods -o dist/app.jar after your normal build step. No install is needed - java -jar is sufficient for one-shot invocations.
  3. Upload the resulting _ofc.jar as your release artifact.

A few things worth knowing:

  • Exit codes: the CLI returns 0 on success, 2 if the input jar isn't found, 3 if inside couldn'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 Main entry opens a Swing window. The wuuvy CLI (the Wuuvy entry point) and wuuvy inside run fully headless. You do not need xvfb.
  • 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

A preset is just a bundle of techniques picked to work well together, so you don't have to. There are eight. With wuuvy <jar> you pass one as a flag (-light); with ofc-jar you put the name first (ofc-jar light app.jar). If you pick none, you get fortify.

PresetWhat you getReach for it when
fortify (default)The strong, safe default. Renames methods and fields but not classes, and never adds anything that could stop your jar from running.almost always. Start here. It's the best mix of "hard to read" and "won't surprise you."
lightThe gentle option: rename things, strip debug info, a couple of shape-preserving passes.you want a quick cleanup that's safe for basically any framework, or you're cold-start sensitive.
methodsFocuses on method bodies — rename, shuffle, light control-flow tweaks — and leaves your strings, classes, and layout alone.you want method-level protection without touching anything else.
turboBuilt for speed: string encryption, renaming, and a few cheap tricks, but skips the expensive control-flow flattening. Roughly 1.1× runtime.your code is compute-heavy and you can't spare the runtime cost of the heavier modes.
allEverything, class renaming included. The strongest setting.you want maximum protection and you've tested the result — renaming classes can break apps that look classes up by name (reflection, ServiceLoader).
modMinecraft-safe. Skips anything that would upset a loader, and automatically leaves entry points, mixins, and reflected names intact.you're shipping a Forge / Fabric / NeoForge mod. See Minecraft mods.
mod-strictmod turned up — more layered techniques on top.you want to push a mod harder; test it against your loader and fall back to mod if anything acts up.
paranoidall plus a self-defense layer (tamper checks, anti-debug, and gates). It will refuse to run unless the jar is signed, the OFC_RUN_KEY environment variable matches, and it's on the machine it was built for.you're building for exactly one machine and one runtime. Do not use it for a jar you hand out — it's designed to not run anywhere else.
Not sure which? Run wuuvy doctor app.jar — it reads your jar and tells you which preset fits.

Config file

Typing flags every time gets old. You can put your choices in a file instead and point wuuvy at it. There are two formats — pick whichever you like.

1. A quick text profile

The simplest one. Each line turns a technique on with {Y} or off with {N}, with an optional strength number after a dash. Lines like key: value set the basics. Anything after // or # is a comment, and =names in equals signs= are just section labels for your own eyes.

# my-settings.conf =what to turn on= [string-enc]{Y} - [1.0] // on, normal strength [cff]{N} // off [rename]{Y} - [0.5] // on, but gentler =the basics= preset: fortify // start from this, then apply the tweaks above seed: 1234 // same seed = same output every time output: dist/app.jar

Run it like this:

ofc-jar my-settings.conf app.jar

If you save a file at ~/.wuuvy/CONFIGS.txt, wuuvy uses it automatically whenever you run ofc-jar app.jar with no other instructions — a nice way to set your personal defaults once.

2. A JSON config

If you'd rather have something tidy to commit to your repo, use the JSON form. Generate a starter file (it comes fully commented) and edit it:

wuuvy template # writes ~/.wuuvy/template.json wuuvy template app.json # or put it where you want
// app.json { "input": "app.jar", "output": "dist/app.jar", // leave out for <name>_ofc.jar "preset": "fortify", "seed": 0, // 0 = random each run "techniques": { "string-enc": true, "cff": false, "rename": { "enabled": true, "intensity": 0.5 } } }
ofc-jar app.json

The JSON form is strict on purpose: a misspelled technique or unknown setting stops the build with a clear message, so a typo never quietly ships an unprotected jar. (The text profile is more relaxed — it just warns and skips names it doesn't recognise.)

Keeping names safe

Obfuscation only bites you when it renames something another part of your program — or a framework — looks up by its original name. wuuvy handles most of that for you:

  • The default never renames classes. fortify leaves class names alone, which is exactly the thing reflection and service loaders care about most. That's why it's the default.
  • Reflected names are detected. When wuuvy sees a string handed to Class.forName, getDeclaredMethod, and friends, it leaves that name as-is.
  • The mod presets go further and automatically protect loader entry points, mixins, and anything referenced from mod metadata.

For the stubborn cases, you can hand wuuvy a plain list of class names to leave completely untouched by pointing the WUUVY_KEEP_VERBATIM_FILE environment variable at a text file (one name per line). And the honest fallback that always works: if a heavy preset breaks something, drop to fortify or light and the problem usually goes away.

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.json are auto-collected and excluded from class renaming.
  • Mixin classes are skipped: any class with the @Mixin annotation is preserved verbatim. boze.mixins.json still resolves its targets by name after obfuscation.
  • Reflection-protected names: Class.forName / getDeclaredMethod / getDeclaredField string arguments are scanned across the jar and added to the no-rename set.
# typical workflow for a Fabric mod: cd path/to/mercwarex gradle build ofc-jar mod build/libs/mercwarex-1.0-SNAPSHOT.jar mercwarex-stealth.jar # or wire it into the build once: cd path/to/mercwarex wuuvy integrate echo "apply from: 'wuuvy.gradle'" >> build.gradle ./gradlew obfuscate -Pofc.tech=mod

Ship the auto-emitted ProGuard-format .mapping file with releases - without it, user crash reports become unreadable obfuscated stack traces.

Don't enable for mods: 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

Double-clicking the jar does nothing (or the installer won't open)

Almost always the wrong Java. wuuvy needs Java 8 or newer — check with java -version. If the installer still won't appear, open a terminal and run java -jar wuuvy.jar so you can see the actual error. And remember you never have to open the installer: java -jar wuuvy.jar app.jar protects a jar without it.

Installed it, but my terminal says wuuvy isn't a command

Terminals only read your PATH when they start, so the one that was already open won't see the new command. Close it and open a fresh one. On macOS/Linux you can also source the file the installer told you it edited.

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, @Controller classes, and the fields Spring injects into them.
  • Jackson / Gson: every DTO/POJO you (de)serialize - field names are the wire format.
  • JPA / Hibernate: @Entity classes and their fields.
  • JavaFX / FXML: controllers referenced by fx:controller.

Good news: the default fortify preset doesn't rename classes, so most of this never comes up unless you reach for all. If it does, see Keeping names safe — and the quickest fix is always to drop back to fortify or light. Making reflection-heavy apps "just work" on the heavier presets is near the top of the what's-next list.