From archie
Reference for org.tomitribe.archie streaming archive transformation library. TRIGGER when: code imports from org.tomitribe.archie, or user needs to transform ZIP/JAR/TAR.GZ archives on-the-fly (inject entries, replace content, skip entries, enhance bytecode while streaming). DO NOT TRIGGER when: working with standard java.util.zip or unrelated archive libraries.
npx claudepluginhub tomitribe/claude-plugins --plugin archieThis skill uses the workspace's default tool permissions.
Java library for stream-based manipulation of archive files (ZIP, JAR, TAR.GZ). Apply transformations on-the-fly without extracting to disk: inject entries, replace content, prepend text, skip entries, and enhance bytecode -- all while streaming.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Compresses source documents into lossless, LLM-optimized distillates preserving all facts and relationships. Use for 'distill documents' or 'create distillate' requests.
Java library for stream-based manipulation of archive files (ZIP, JAR, TAR.GZ). Apply transformations on-the-fly without extracting to disk: inject entries, replace content, prepend text, skip entries, and enhance bytecode -- all while streaming.
Package: org.tomitribe.archie
<groupId>org.tomitribe</groupId>
<artifactId>archie</artifactId>
<version>1.1-SNAPSHOT</version>
Build a Transformations object with rules, then apply it to an archive via a format-specific transformer. Entries stream through one at a time -- no disk extraction, no full archive in memory.
Transformations transformations = Transformations.builder()
.before(InsertEntry.builder()
.name("README.txt")
.content("Hello, World!")
.build())
.build();
new JarTransformation(transformations)
.transform(new File("input.jar"), new File("output.jar"));
Central configuration for all transformation rules. Built via Transformations.builder().
Transform entry contents using Function<byte[], byte[]>:
Transformations.builder()
// Replace content of specific entries
.add(name -> name.equals("config.xml"),
bytes -> newContent.getBytes())
// Enhance class files (bytecode manipulation)
.enhance("org/example/MyClass.class", enhancerFunction)
// Enhance by predicate
.enhance(name -> name.endsWith(".class"), enhancerFunction)
// Prepend text to matching entries
.prepend(name -> name.equals("META-INF/LICENSE"),
"Copyright Acme Corporation. 2025\n\n")
.build();
Insert new entries before or after archive processing:
Transformations.builder()
// Insert at start of archive
.before(InsertEntry.builder()
.name("META-INF/NOTICE")
.content("Added by build pipeline")
.build())
// Insert at end of archive
.after(InsertEntry.builder()
.name("build-info.txt")
.file(new File("build-info.txt"))
.build())
// Inline all entries from another JAR (fat JAR)
.after(new InlineJar(new File("library.jar")))
// Raw Consumer<ArchiveOutputStream> callback
.before(archiveOut -> {
final byte[] bytes = "content".getBytes();
final JarArchiveEntry entry = new JarArchiveEntry("added.txt");
entry.setSize(bytes.length);
archiveOut.putArchiveEntry(entry);
archiveOut.write(bytes);
archiveOut.closeArchiveEntry();
})
.build();
Execute logic before or after specific entries:
Transformations.builder()
.beforeEntry(name -> name.endsWith("Red.class"), out -> {
out.writeEntry("BeforeRed.txt", "Pre-content");
})
.afterEntry(name -> name.endsWith("Red.class"), out -> {
out.writeEntry("AfterRed.txt", "Post-content");
})
.build();
Remove entries from the output:
Transformations.builder()
.skip(entry -> entry.equals("unwanted.txt"))
.skip(entry -> entry.endsWith(".bak"))
.build();
Prevent content transformation on signed JARs or specific entries:
Transformations.builder()
.skipTransformation(name -> name.startsWith("META-INF/"))
.build();
Archie automatically detects signed JARs (manifest with -Digest attributes) and skips their transformation.
beforeArchive() -- executed firstbeforeEntry(name) if predicate matchesenhance() / prepend() / add()afterEntry(name) if predicate matchesafterArchive() -- executed lastEach implements the Transformer interface and has a fluent builder.
For JAR, WAR, EAR, RAR files. Preserves compression method, timestamps, Unix mode, CRC32.
JarTransformation.builder()
.enhance("org/example/MyClass.class", enhancerFunction)
.skip(entry -> entry.equals("old-file.txt"))
.before(InsertEntry.builder().name("added.txt").content("hello").build())
.build()
.transform(inputFile, outputFile);
For ZIP files. Same builder pattern.
ZipTransformation.builder()
.prepend(name -> name.equals("README"), "Header\n\n")
.build()
.transform(inputStream, outputStream);
For TAR.GZ files. Handles symlinks, hard links, and long filenames (POSIX mode).
TarGzTransformation.builder()
.before(InsertEntry.builder().name("notice.txt").content("Built by CI").build())
.build()
.transform(inputFile, outputFile);
Copies input to output unchanged. Used as fallback for unsupported formats.
Transformations.transformer(File) selects the right transformer by extension:
| Extension | Transformer |
|---|---|
.jar, .war, .ear, .rar | JarTransformation |
.zip | ZipTransformation |
.tar.gz | TarGzTransformation |
.pdf | PassThroughTransformation |
transformations.transformer(archiveFile).transform(archiveFile, outputFile);
public interface Transformer {
void transform(InputStream in, OutputStream out) throws IOException;
default void transform(File src, File dest) throws IOException;
}
Inserts a new entry into an archive. Detects archive type automatically.
InsertEntry.builder()
.name("path/in/archive.txt")
.content("string content") // or
.file(new File("local.txt")) // or
.bytes(() -> byteArray) // lazy Supplier<byte[]>
.build();
Replaces entry content with a new string:
ReplaceFileContent.builder()
.content("new content")
.build();
// Returns Function<byte[], byte[]>
Extracts entries from a source JAR and inlines them into the output archive. Preserves all entry metadata.
new InlineJar(new File("library.jar"))
// Use as Consumer<ArchiveOutputStream> in .after() or .before()
File wrapper that manages associated digest files (.md5, .sha1, .sha256).
Binary binary = new Binary("application.jar");
// Write with automatic digest generation
try (Binary.BinaryOutputStream out = binary.write()) {
out.write(fileBytes);
}
// Creates application.jar.md5, application.jar.sha1, application.jar.sha256
// Read digests
String md5 = binary.getMd5();
String sha1 = binary.getSha1();
String sha256 = binary.getSha256();
// Verify against stored digests
binary.verify(); // throws on mismatch
binary.verify(System.out); // logs results, returns boolean
// Generate digests for existing file
binary.generate();
binary.generate(true); // overwrite existing digest files
Digest.MD5.digest(file) // hex digest of file
Digest.SHA1.digest(file)
Digest.SHA256.digest(file)
// Wrap streams for transparent digest calculation
DigestsOutputStream dos = Digest.SHA256.digest(outputStream);
dos.write(data);
String hex = dos.hex();
DigestsInputStream dis = Digest.MD5.digest(inputStream);
// read all data...
String hex = dis.hex();
String base64 = dis.base64();
Zips.unzip(zipFile, destinationDir);
String listing = Zips.list(zipFile); // tree listing with hashes
TarGzs.untargz(tarGzFile, destinationDir);
String listing = TarGzs.list(tarGzFile);
Both support recursive listing of nested archives and stream-based extraction with file filters.