How to Use IronZIP with ChatGPT Codex

Curtis Chau
Curtis Chau
Updated: October 19, 2026

Partners send their nightly files in whatever format their own systems produce. One drop holds ZIP files with and without passwords, TAR and TGZ bundles from Linux hosts, a BZIP2 stock bundle, a file named .tar that is really a ZIP, and an upload that stopped halfway. The intake has to unpack every one, prove that each file arrived as the partner sent it, and say which uploads failed and why.

ChatGPT Codex, OpenAI's coding agent, runs in the terminal, in editors, inside the ChatGPT desktop app and as a cloud service, and each of these accepts a ChatGPT sign-in. IronZIP is Iron Software's .NET library for reading and writing ZIP, TAR, GZIP and BZIP2 archives.

This guide gives Codex a drop of 25 uploads, a manifest with the status each one should get, and a SHA-256 list from each partner. Most prompts ask Codex for a CSV that holds one row for each file, and every IronZIP behavior described below was measured on version 2026.10.2.

Quickstart
NuGetInstall with NuGet

PM > Install-Package IronZip

Install IronZIP by running the command above in the NuGet Package Manager Console, or search for the package in the NuGet Package Manager.

Launch Codex from the .NET console project that holds the drop, and ask for a listing first.

$ironzip Add IronZIP 2026.10.2 from NuGet to this console project.
Next, Program.cs opens every file in Drop/sample/ with IronZipArchive, read-only.

out/quickstart.csv gets one row per file, holding these values:

- entry count
- encrypted entry count
- the exception type when IronZIP refuses the file

Read that CSV back and print its totals.
Assign the key from IRONZIP_LICENSE_KEY and never print it.
Extract nothing yet.
Build and run it with three repair attempts at most, then report what happened.
Text


What is ChatGPT Codex, and how does it fit into .NET archive work?

The Codex CLI pages cover installation with npm install -g @openai/codex or a standalone installer, and the IDE pages cover editors.

OpenAI's security guidance asks you to treat Codex suggestions like any other pull request, with targeted verification and a diff review. An invented member fails the build, and a mishandled archive appears as a status the manifest contradicts.

How do you write an IronZIP prompt and set up Codex for it?

An intake prompt names the input, the format rule, the output folders, the checksum proof, the password source and the read-only folders. Any part left out becomes a choice the agent makes for you.

Codex scans .agents/skills in the working directory and in each parent folder up to the repository root. IronZIP's skill.md, saved as .agents/skills/ironzip/SKILL.md, makes $ironzip resolve. Its examples pin 2026.8.2, and it mentions neither the TAR folder failure nor the single-entry password failure measured below.

Codex reads AGENTS.md at the start of every run, at most one file per folder on the path from the project root to the working folder. Files nearer the working folder override earlier ones. IronZIP's llms.txt index is the second API source.

Give the repository root an AGENTS.md holding a Partner drop intake section.
The section holds these rules:

- IronZIP is the only archive library allowed.
- Its package is IronZIP, and its namespaces are IronZip and IronZip.Enum.
- The API sources are the ironzip skill in .agents/skills/ironzip/ and the llms.txt index.
- The index URL reads https://ironsoftware.com/zip/csharp/llms.txt.
- Nothing under Drop/ or config/ may change.
- Passwords from config/passwords.csv never appear in code, output or logs.
- IRONZIP_LICENSE_KEY is checked for presence and length only.
- A reply gives a count only when a results file backs it.
- That file was read or written in the same turn.
Text

How do you ask Codex to add IronZIP and check the package?

Show me these:

- the IronZIP PackageReference in DropIntake.csproj
- the version restore resolved
- every IronSoftware package that dotnet list package --include-transitive reports

If that command can't read the package reference, find out why within three attempts.
Make the smallest change that lets it run, and say what you changed.
Keep the same package and version.
Write the packages that command lists to out/packages.csv.
Text

NuGet lists the package as IronZIP, and code imports the IronZip namespace. With .NET SDK 10.0.400, dotnet add package IronZip, the command IronZIP's skill gives, wrote the reference as IronZIP while restore recorded IronZip, and dotnet list package then stopped with Unable to read a package reference. Adding the package as IronZIP kept the two spellings the same. Its only dependency, IronSoftware.Common 2026.4.2, added 23 more packages to the restore on .NET 9.

IronZIP has no reduced mode without a key. In a probe, every call that opened, listed or extracted an archive threw a LicensingException whose message read Production License Required. With IRONZIP_LICENSE_KEY defined, License.IsLicensed stayed false until code assigned the value to License.LicenseKey.

Add a public Startup class with a public ApplyIronZipKey method, called first in Program.cs.
It assigns IRONZIP_LICENSE_KEY to IronZip.License.LicenseKey.
It reports only whether License.IsLicensed is true.

Then add a --list-sample mode that makes one listing pass over Drop/sample/.
Run it twice as a child process:

1. Run it unchanged.
2. Run it with IRONZIP_LICENSE_KEY removed from that child's environment alone, never the session's.

Write out/license-check.csv with columns run, file, IronZIP call, exception type and message.
IronZIP's licensing exception is internal, so catch Exception and log GetType().FullName.
Tell me which calls threw.
Text

The license keys page documents the IronZip.LicenseKey setting for appsettings.json, App.config and Web.config.

How do you tell what an archive really is before extracting it?

IronZipArchive reads only ZIP files. Given a TAR, GZIP, BZIP2 or text file it threw a ZipException saying it could not find the central directory, and opening a 0-byte file gave EOF in header. The leading bytes identify the format. OpenAI documents the built-in explorer agent for read-heavy codebase exploration.

Have the explorer agent go through Drop/inbox/ and note these values for every file:

- the byte count
- the opening eight bytes as hex
- the five bytes at offset 257, skipped for files shorter than 262 bytes
- the format those bytes indicate under Drop/README.md

Save what it reports as out/inventory-explorer.csv.
Then write a small script that computes the same fields into out/inventory.csv.
For GZIP and BZIP2 data, IronZIP decompresses a temporary copy saved under out/tmp/.
That copy gets a .gz or .bz2 name, and the script tests it for a TAR header.
The script labels each file ZIP, TAR, GZIP, TAR.GZ, BZIP2, TAR.BZ2, EMPTY or NONE.

Then list the rows where the two files differ.
Also list every file whose extension disagrees with its content.
Text

Five uploads should be flagged. One is a ZIP named .tar, one a TGZ named .zip, one a text file and one random bytes that both carry archive extensions, and one is empty.

How do you list what is inside each archive?

Create Services/EntryLister.cs.
It lists every inbox archive the inventory calls ZIP or TAR, without extracting.
It reads them this way:

- For ZIP, open an IronZipArchive and call its Entries() method.
- When an open without a password fails, open again with the password from config/passwords.csv.
- For TAR, open an IronTarArchive and call GetArchiveEntryNames().

Give out/entries.csv the columns archive, entry, size, stored CRC, encrypted, or the exception type.
Also write out/entry-counts.csv.
It compares the file entries of each archive with the files column of Drop/manifest.csv.
Tell me which archives the comparison flags.
Text

GetArchiveEntryNames gives only a TAR's names, while Entries returns an Entry with each item's name, size, stored CRC and IsCrypted flag. GZIP and BZIP2 have no listing call. Folder entries count as entries, and the kestrel-pod archive listed 252 of them for 250 files.

Opening an encrypted ZIP without a password threw ArgumentNullException, and so did passing a password for a ZIP that has none. On archives with more than one entry, the constructor accepted a wrong password and Entries listed every file, so a listing cannot tell a good password from a bad one.

How do you extract every archive and prove the files arrived intact?

OpenAI describes the built-in worker agent as execution-focused, for implementation and fixes. The extract protected ZIP example shows the password overload of the static extraction call.

Have the worker agent write Services/IntakeExtractor.cs.
It applies Drop/README.md to every inbox file in this order:

1. Choose the IronZIP class from the format in out/inventory.csv.
2. Extract into out/extracted/<file name>/.
3. Hash each extracted file against Drop/checksums/.
4. Set the README status and reason.

Add an --intake mode that writes out/intake-results.csv.
Its columns are file, format, IronZIP call, status and reason.
After those come files expected, files matching and exception type.
The mode prints the status counts read from that file.
Tell me those counts.
Text

The hash check is required with IronZIP, because extraction does not compare an entry with its stored CRC. In ivy-orders, one flipped byte in a stored entry came out without an exception, and that entry's Crc value differed from the CRC of the file written to disk.

A GZIP extraction of a ZIP, TAR or text file threw and still wrote an empty file under the archive's name, and a wrong password left an empty folder, so the README asks for cleanup. Extracting into the same folder a second time overwrote the files without a warning.

Why does a TAR with subfolders fail to extract?

IronTarArchive.ExtractArchiveToDirectory does not create folders. On every TAR with entries in subfolders it threw DirectoryNotFoundException and wrote nothing, whether or not the TAR carried folder entries. Creating each folder from GetArchiveEntryNames first made the same call succeed.

Why does the same GZIP file extract differently under another name?

Rerun --intake.
Find each row of out/intake-results.csv whose status or reason disagrees with Drop/manifest.csv.
Add <Compile Remove="scratch/**" /> to DropIntake.csproj.
Make a scratch console project under scratch/format-probe/.
From it, call the same IronZIP method on a copy of each such file, and record what it wrote.

Save the findings to out/format-check.csv, then fix the extractor.
Stop after three fix rounds or when every row agrees.
Tell me which rows still disagree.
Text

IronGZipArchive decides by file name. Under a name ending in .tgz or .tar.gz, both ExtractArchiveToDirectory and ExtractTGZArchiveToDirectory unpacked the TAR inside. Under any other name, both wrote one decompressed file named after the archive minus its last extension, so the TGZ named .zip came out as a single TAR file. IronBZip2Archive unpacked a TAR only from a .tar.bz2 name, not from .tbz2. The extract GZIP example calls ExtractArchiveToDirectory in its first code sample and the TGZ call in its second.

What does IronZIP do with a password it cannot use?

Check the protected ZIP files in out/intake-results.csv against these rules:

- A file with no listed password is Protected with reason no-password.
- A file whose listed password fails is Protected with reason wrong-password.

Name the IronZIP call that first rejected the wrong password.
Base that on out/entries.csv together with out/intake-results.csv.
Then write out/password-scan.csv, listing every file under out/.
Each row says yes or no for whether that file holds any password from config/passwords.csv.
Read the passwords inside the program at run time, and never pass one on a command line.
Report the match count from that file.
Text

Extraction was the first call to reject the wrong password, with an ArgumentException whose message reads Invalid password!!

Why is the right password rejected?

Codex accepts images passed with -i (long form --image) on the command line, codex exec resume included, or pasted into the composer.

The image attached to this turn with -i is a Delta Freight support ticket.
It concerns delta-rates-2026-10-09.zip.
Read it, and reproduce the error with the project's own code.
Decide which of these is true:

- The password in config/passwords.csv is wrong.
- IronZIP refuses it for another reason.

Write out/delta-check.csv with these columns:

- IronZIP call
- which file the password came from
- outcome
- exception type

Change code only where that evidence calls for it.
Tell me which of the two it is.
Text

The listed password is correct. Every way of opening that archive with it, the constructor from a path, bytes or a stream and FromArchive, threw System.Exception with Invalid Password!, while ExtractArchiveToDirectory with the same password wrote the rate card with a matching hash. The archive holds a single entry.

How do you debug incorrect intake output end to end?

The nightly log calls 16 archives ok.
Yet Feedback/warehouse-2026-10-11.md lists five of them that reached the warehouse wrong.
Send the explorer agent through Jobs/NightlyIntake.cs and Logs/nightly-2026-10-11/.
The explorer edits nothing.

Work out how each of those five got past the job's success check.
Name the lines responsible.
Suggest the narrowest change and a command that would confirm it.
Save the diagnosis as out/nightly-diagnosis.md, and tell me what it found.
Edit no code in this turn.
Text

A sound diagnosis finds two causes. The job stages each upload under a hashed name that keeps only the last extension, so IronZIP never sees .tar.gz or .tar.bz2. It writes each decompressed TAR as one file and names each single-file upload after the hash. Nothing compares the extracted files with a checksum or a CRC, so the damaged ivy entry passes as ok.

How do you turn one-off code into reusable, tested components?

Have the worker agent fold the intake modes into a public IntakeJob class, set up like this:

- It's resolved through Microsoft.Extensions.DependencyInjection, version 9.0.20, which it adds.
- A public IntakeOptions record holds its inbox, output root, passwords file and checksums folder.
- IntakeJob.cs stays under 200 lines, with XML doc comments.

Keep these behaviors:

- the byte-based format choice
- the folder creation before TAR extraction
- the name-based staging for GZIP and BZIP2
- the hash check
- the password rules
- the cleanup

Run it over Drop/inbox/, writing out/final/ and out/final.csv.
Confirm every row matches Drop/manifest.csv on status and reason.
Stop after three fix rounds, and tell me how many rows match.
Text

A refactor that drops the folder creation or the hash check still builds, so the prompt ends with a full rerun against the manifest.

Add an xUnit project at tests/DropIntake.Tests with these packages:

- xunit 2.9.3
- xunit.runner.visualstudio 3.1.5
- Microsoft.NET.Test.Sdk 18.0.1

Add <Compile Remove="tests/**" /> to DropIntake.csproj.
Put both projects in one DropIntake.sln at the repository root.
Call Startup.ApplyIronZipKey before the first IronZIP call.

Test IntakeJob on real inbox files, with a separate output folder per test, for these cases:

- fern-logs-2026-10-09.tar yields its four logs in their folders.
- juniper-routes-2026-10-09.zip is read as TAR.GZ.
- ivy-orders-2026-10-09.zip is Unreadable with reason damaged.
- elm-claims-2026-10-09.zip is Protected with reason wrong-password.
- delta-rates-2026-10-09.zip is Extracted.

Run dotnet test into out/tests/ with a trx logger.
Report the passed and failed counts, quoted from the .trx file.
Text

Assert on statuses and extracted file hashes, never on archive bytes.

$ironzip Open IronZip.xml in the ironzip folder of the NuGet package cache and answer two questions:

- Which method extracts an archive, class by class?
- Which archive classes can list their entries without extracting?

Confirm each answer by compiling a probe under scratch/, which DropIntake.csproj must not compile.
Name any member of that IronZip.xml that does not compile, or say that none failed.
Then show the line in IntakeJob that picks the extraction call for each format.
Text

On 2026.10.2 the object reference lists five static calls, ExtractArchiveToDirectory on each archive class plus ExtractTGZArchiveToDirectory.

How do you reuse these prompts on another archive drop?

The same prompts work for another inbound drop after its paths, status rules and checksum lists change. The AI coding assistants guide runs an acceptance test that starts from an empty folder.

What did the prompts produce in a real run?

All 14 prompts ran, in order, in a single unattended Codex CLI session through codex exec. Every figure below comes from our own checks afterward, among them a Release build with 0 errors and 0 warnings and a Python rehash independent of IronZIP.

  • The first extractor reported 16 Extracted, 3 Protected and 6 Unreadable, and 23 of its 25 rows matched the manifest.
  • After the ticket prompt, 24 of the 25 rows matched.
  • The final job reported 18 Extracted, 2 Protected and 5 Unreadable, and all 25 rows matched on status and reason.
  • The rehash matched all 314 files from the 18 Extracted uploads against the partner lists.
  • Nothing was left on disk for the other seven uploads.
  • A rerun of the final job on a copy of the code took 3.9 seconds and wrote identical bytes.
  • All 5 tests passed with the key, and all 5 failed in a rerun without it.
  • The Quickstart listed 2 of the 8 sample files, with 18 entries and none encrypted, and logged one ArgumentNullException and five ZipExceptions for the rest.
  • The inventory flagged exactly the five uploads named above.
  • The explorer agent's copy differed from the script's on 10 of 25 rows, nine in format wording and one with seven of the eight opening bytes.
  • Listing wrote 310 entry rows for the 16 ZIP and TAR uploads, and 13 matched the manifest's file counts.
  • The protected ZIP with no password, the single-entry ZIP and the truncated upload could not be listed.
  • With the key removed from the child process, 8 of 8 calls threw the licensing exception.
  • The password scan read 344 output files and matched none.
  • The nightly diagnosis named both causes and changed no code.
  • A replay of the nightly job logged the same 16 ok and 9 failed, and five of the 16 failed the partner checksums.
  • Some steps ran differently from the page. Codex wrote the package reference by hand as IronZip, so dotnet list package worked at once. The first extractor already created the TAR folders and staged GZIP TARs under a .tgz name, so the rows that disagreed were delta-rates and grove-stock. The format prompt fixed neither in three rounds, because its probe passed IronTarArchive a CSV that IronBZip2Archive had already unpacked. The ticket prompt fixed delta-rates and the refactor fixed grove-stock. The refactor prompt asked to keep name-based staging for BZIP2, which a .tar.bz2 name makes unnecessary. The final results file names an IronTarArchive call for that row that the code no longer makes. IntakeJob.cs came to 32 lines because the workflow moved into a second partial file of 382 lines. The four agents ran as spawned threads with no agent type, so no built-in explorer or worker role was recorded.

The Google Antigravity guide found the same single-entry password failure in a download service and checked archives by extraction and SHA-256 instead. In the GitHub Copilot guide, IronZIP's TAR writer stored each log under its bare file name, so same-named logs collided. The Codex version, model and timing are in the shared run record.


Troubleshooting


Questions?

If you have any questions, reach out to support@ironsoftware.com

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

Read More

Ready to Get Started?

Nuget Downloads 24,698Version:2026.10just released