A Maven plugin that lets Claude Code inspect, decompile, and instrument classes in your jar dependencies.
-
No source jars required — decompile any dependency on the classpath
-
No System.out.println — instrument methods for args, return values, timing
-
No dirty diffs — instrumentation is bytecode-level, source code untouched
-
No forgotten debug code — delete
.jackknife/and everything reverts
One mvn command bootstraps everything; after that, Claude reads files directly with zero Maven overhead.
|
Build lightweight manifests of all dependency jars (sub-second). Generates |
|
Decompile a class. First request decompiles the entire jar; subsequent reads are instant file access. |
|
Instrument methods for runtime observation ( |
After mvn jackknife:index, Claude greps the manifests and reads decompiled source directly — no further Maven invocations needed for most lookups.
Three steps, once per machine and once per parent pom.
Add to your global ~/.claude/CLAUDE.md:
## Jackknife - When you need to inspect, decompile, or find classes in jar dependencies, run `mvn jackknife:index` in the project. This generates `.jackknife/USAGE.md` with full instructions. Read that file — it has everything you need.
Add the plugin group to ~/.m2/settings.xml so you can use the shorthand mvn jackknife:…:
<pluginGroups>
<pluginGroup>org.tomitribe.jackknife</pluginGroup>
</pluginGroups>Add the jackknife profile to your parent pom. It auto-activates when a .jackknife/ directory exists and does nothing otherwise:
<profile>
<id>jackknife</id>
<activation>
<file><exists>.jackknife</exists></file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.tomitribe.jackknife</groupId>
<artifactId>jackknife-maven-plugin</artifactId>
<version>0.2</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>Tomitribe projects: already included in org.tomitribe:oss-parent:14+ and com.tomitribe:tomitribe-parent:14+.
Jackknife uses two tiers, optimized for minimal overhead:
-
Manifests (all jars, sub-second) — lightweight class name listings. Enough to find which jar has a class and search across the classpath.
-
Decompiled source (per jar, on demand) — full Vineflower decompilation. Triggered on first request for any class in a jar. Every class in that jar is written as an individual
.javafile for direct read access.
After the first decompile of a jar, Claude reads .jackknife/source/<groupId>/<artifact>/<path>/MyClass.java directly. No Maven, no startup overhead, no output noise.
Jackknife renames instrumented methods (e.g., process becomes jackknife$process) and generates a wrapper that delegates to a java.lang.reflect.InvocationHandler. The handler chain is composable:
TimingHandler -> DebugHandler -> ProceedHandler
-
TimingHandler measures elapsed time
-
DebugHandler logs args, return values, and exceptions
-
ProceedHandler calls the renamed original method via reflection
Each handler wraps the next. Adding new capabilities is just writing a new InvocationHandler.
Large captured values (over threshold or containing newlines) are written to target/jackknife/captures/ with a file reference in the console output — Claude reads the file directly for test assertions.
.jackknife/ +-- manifest/ Class listings (all jars, sub-second) | +-- <groupId>/ | +-- <artifact>.jar.manifest +-- source/ Decompiled source (per jar, on demand) | +-- <groupId>/ | +-- <artifact>-<version>/ | +-- com/example/MyClass.java +-- instrument/ Instrumentation inbox | +-- <groupId>/ | +-- <artifact>.jar.properties +-- modified/ Patched jars + receipts | +-- <groupId>/ | +-- <artifact>.jar | +-- <artifact>.jar.properties +-- USAGE.md Auto-generated reference (do not edit)
-
File in
instrument/→ needs processing -
File in
modified/→ done, actively swapped in -
File deleted → reverted
-
rm -rf .jackknife/→ fully clean