How to Use IronPrint with ChatGPT Codex

Curtis Chau
Curtis Chau
Updated: October 19, 2026

A warehouse prints a picking list for every order each night. Some orders need one copy for the picker, others need a second for the packer and a third for the invoice clerk. When the copy count is wrong, nothing fails. The packer finds a sheet with no partner copy, or the invoice desk receives nine sheets of one order, and the print log still reports those orders as sent.

ChatGPT Codex, OpenAI's coding agent, edits the files of a repository, runs dotnet run and other commands, and reports what it did. It works in the ChatGPT desktop app, an IDE, a terminal and the cloud. IronPrint, Iron Software's .NET printing library, sends PDF and image files to an installed printer, silently or through the operating system's print dialog, with paper size, orientation, DPI, grayscale and the number of copies set on one PrintSettings object.

Codex receives a night of picking-list orders and a manifest of expected results. Every copy count Codex reports comes from a CSV file, and the whole batch is planned before any job is sent to a printer.

Quickstart
NuGetInstall with NuGet

PM > Install-Package IronPrint

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

Run Codex inside a .NET console project with an Orders folder.

$ironprint Install IronPrint 2026.10.1 from NuGet in this console project.
Program.cs should then plan the six orders in Orders/sample/ without sending a job.

Give each sample PDF a row in out/quickstart.csv. The columns are:

- file
- copies, from that order's row in Orders/manifest.csv
- printer, the PrinterName in appsettings.json
- found, yes or no, whether Printer.GetPrinterNames lists that printer

Read the total copies back from that CSV and show it.
Program.cs gets the key from IRONPRINT_LICENSE_KEY by itself.
Don't show the key's value anywhere, and don't list environment variables.
Keep the PrintCapture.Install line first in Program.cs.
Don't call Print, PrintAsync or ShowPrintDialog yet.
Stop after three failed builds or runs, and tell me what came out.
Text

The $ironprint mention loads IronPrint's skill into the session.



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

Codex's CLI documentation explains installation and terminal use, and its source code and releases are on GitHub.

Codex relies on training data and on the files in its context for IronPrint, and a wrong member name fails the build.

IronPrint supports Windows, macOS, iOS and Android. The project in this guide targets net9.0-windows.

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

An IronPrint batch prompt names the input (every order in Orders/manifest.csv), the printer and the source of its name (appsettings.json, checked against Printer.GetPrinterNames), the settings for each job (the copy count from the manifest, paper size, portrait, grayscale and 150 DPI), the proof (a plan CSV with one row per order), the ground truth (the expected statuses in the manifest) and the constraints (an exact printer name and no call to ShowPrintDialog).

Codex searches the working directory and every directory above it, up to the repository root, for an .agents/skills folder. Each skill folder holds a SKILL.md file whose frontmatter gives a name and a description. With IronPrint's skill.md copied to .agents/skills/ironprint/SKILL.md, the $ironprint mention resolves. The single-file example in the skill pins IronPrint 2026.8.1, and the Quickstart installs 2026.10.1.

Before any work, Codex loads the AGENTS.md files on the path from the repository root to the working folder. It reads no more than one per directory, and where two conflict, the file nearer the working folder takes precedence. Running /init produces a starting draft.

The test machine has no printer that finishes a job without a dialog, and a dialog stops an unattended run. The test repository therefore includes a small capture class that intercepts the job IronPrint sends to Windows and writes it to an XPS file, so no job is spooled. A project with a working printer leaves it out.

Write a root-level AGENTS.md containing a section called Nightly picking lists.
These are its rules:

- IronPrint is the only printing library. Its package and namespace are both IronPrint.
- The target framework stays net9.0-windows.
- For the API, check the ironprint skill in .agents/skills/ironprint/.
- The installed IronPrint.xml settles any doubt about a member.
- Orders/ is read-only.
- The printer name comes from appsettings.json and has to appear in Printer.GetPrinterNames.
- The first line of Program.cs installs PrintCapture. It stays first, and Capture/ stays as it is.
- Print and PrintAsync run only from Program.cs, after that line.
- Tests never call them, and code that runs never calls ShowPrintDialog.
- The key lives in IRONPRINT_LICENSE_KEY. No output, log or file ever contains its value.
- A count in a reply has to come from a CSV that the same turn wrote.
- Name that CSV in the reply.

Show me the file once it's written.
Text

How do you ask Codex to add IronPrint and check the license?

Show me the IronPrint PackageReference in PickingBatch.csproj and the version that restore picked.
Then quote each IronSoftware package from the output of dotnet list package --include-transitive.
Don't touch any package reference.
Text

On nuget.org, IronPrint 2026.10.1 lists three dependencies, IronSoftware.Common 2026.4.2, IronSoftware.Abstractions 2026.1.2 and IronSoftware.System.Drawing 2026.8.2. In our run, restore also added IronSoftware.Drawing.Abstractions 2026.1.2. Each build copies IronPrint's native runtime files into the output folder. Review the IronPrint changelog before pinning a release.

Printer.GetPrinterNames, Printer.GetPrinterTrays and a new PrintSettings all succeed without a key, so a printer list proves nothing about licensing. A print call without a key throws a licensing exception before any job is created, and its message reads Production License Required. The synchronous Print wraps it in an AggregateException, while PrintAsync throws it directly. Code outside IronPrint 2026.10.1 cannot reference the licensing exception type. A handler therefore catches Exception and compares the type name.

Create Startup.ApplyIronPrintKey and make it the call right after PrintCapture in Program.cs.
It copies IRONPRINT_LICENSE_KEY into License.LicenseKey and reports License.IsLicensed.

Next, show me what IronPrint does with no key.
Run the program twice as child processes with the variable cleared for that child only:

1. A --licence-check run that lists the printers and builds a PrintSettings for PL-1023.
2. A --licence-check --send run that also calls Printer.Print once on Orders/sample/PL-1023.pdf.

Both runs use the printer from appsettings.json.
Log every call in out/licence-check.csv.
Its columns are run, call, result, exception type, inner type and message.
Give up after three repair attempts.
Text

IronPrint leaves IRONPRINT_LICENSE_KEY unread, so the program copies its value into License.LicenseKey. A key can also go in appsettings.json, Web.config or App.config, as the license keys page describes.

How does IronPrint print several copies of one document?

The copies guide sets NumberOfCopies once and sends one job, instead of calling Print in a loop. A calibration probe sent three copies of a two-page picking list, and IronPrint built one job of two pages with a copy count of 3 in its print ticket. The printer driver makes the extra copies. Microsoft Print to PDF converted that ticket into one six-page file, collated as pages 1, 2, 1, 2, 1, 2.

Make a throwaway console project in scratch/copies-probe/ on your own.
Exclude scratch/** from PickingBatch.csproj with a Compile Remove item.
Run it yourself to find what NumberOfCopies holds on a new PrintSettings.
It also tries 0, -1 and 1000 and records what reads back.

Then the explorer agent answers these from IronPrint.xml and the ironprint skill:

- What the XML says happens when a driver can't make several copies.
- What GetPrinterTrays returns for each installed printer.
- Whether PrintSettings.DefaultSettings is static or belongs to an instance.

Nobody sends a job, and Services/ and Program.cs stay as they are.
Write all the answers to out/copies-probe.csv.
Beside each answer, quote IronPrint.xml, the ironprint skill or the probe output.
Where a page and the probe disagree, say so.
Text

NumberOfCopies defaults to 1, and the property accepts 0, -1 and 1000. The copies guide states that 0 or a negative value falls back to a single copy. The print call refused 0 and -1 in calibration, with an ArgumentOutOfRangeException whose message is Value must be positive, and no job was created. The batch therefore rejects those orders before any settings are built. The XML remarks add that some platforms ignore the value and print one copy.

Each page goes to the printer as an image at the job's DPI, 1240 by 1753 pixels for an A4 page at 150 DPI. With Grayscale set, the output color in the print ticket was Monochrome.

How do you plan a nightly batch of print jobs?

Have the worker agent write Services/PickingPrinter.cs.
It applies Orders/README.md to every row of Orders/manifest.csv and follows these rules:

- A --printer option overrides the name in appsettings.json.
- An --inbox option picks the PDF folder. Orders/inbox/ is the default.
- Check the printer name against Printer.GetPrinterNames before reading any order.
- Match the name exactly, case included.
- An unknown name stops the run with a message that lists the installed printers.
- Build a new PrintSettings for each Ready order.
- NumberOfCopies comes from the copies column, and PaperSize from the paper column.
- Every order gets portrait, grayscale and 150 DPI.
- An empty file, or one without a %PDF header, is Unreadable.

Add a --plan mode that sends nothing and writes out/print-plan.csv with these columns:

- order_id and file
- status, always one of the README's four
- NumberOfCopies, PaperSize, PaperOrientation, Dpi and Grayscale as the job would send them
- printer

Add a --send mode that awaits PrintAsync once per Ready order, in manifest order.
It writes out/send-log.csv with order_id, file and NumberOfCopies, and no plan file.
Don't run --send yet.
Run --plan over Orders/inbox/ and report the status counts from print-plan.csv.
Text

IronPrint reports a damaged file only when a print call reads it. An empty file failed in calibration with an exception type from an obfuscated namespace whose message links to an IronPDF troubleshooting page, and a text file named .pdf failed with InvalidDataException. A check of the PDF header in the plan keeps both out of the job list.

How do you confirm what each print job carries?

PL-1028.pdf, one of the six sample orders, is a two-page A4 picking list with a bin and a quantity for each SKU, and the manifest gives it three copies.

Now run --send with --inbox Orders/sample/.
Orders whose PDF isn't in that folder count as Missing and aren't sent.
PrintCapture writes each job to out/captured/ and adds a row to out/captured/jobs.csv.

Match send-log.csv to jobs.csv in sending order.
Then write out/sample-send.csv with one row per sent order and these columns:

- order_id and the NumberOfCopies it was sent with
- copies, pages, media and color from its jobs.csv row

Tell me whether each order went out as a single job carrying its copy count.
Text

Output

The PDF below is the job that IronPrint built for PL-1028 in the test run, converted page for page from the captured XPS file.

Picking list PL-1028 as IronPrint built the job, captured to a file in place of a printer. The job holds two A4 portrait pages at 150 DPI in grayscale, and its print ticket requests three copies.

What happens when the printer name does not match?

The printer name guide states that a name must match the operating system's exactly, case included, and that a mismatch "will fail silently or throw an error". The calibration jobs raised no exception. A job for Warehouse Laser 01, a queue that does not exist, and a job for adobe pdf in lower case both were routed to Microsoft Print to PDF, which the test machine uses as its default printer.

IronPrint sends a job with an unknown printer name to the Windows default printer.
Show me that PickingPrinter refuses before that can happen.

Run --plan two times, passing each of these names with --printer:

1. "Warehouse Laser 01", a queue this machine doesn't have.
2. "adobe pdf", the installed name in the wrong case.

Neither run may change out/print-plan.csv.
Write out/printer-check.csv with the columns run, printer, exit code, message and plan rows written.
Tell me which printers the message listed.
Text

How do you diagnose a sheet that printed incorrectly?

The -i flag (--image) attaches an image to the first prompt of a session or to the prompt that resumes it, and the interactive composer accepts a pasted image.

I attached a scan of a picking list with -i.
The packer found it alone, without the copies that should have come with it.
Read the order number from the image.
Look that order up in out/print-plan.csv and Orders/manifest.csv.
Tell me the copy count and paper size that the plan sends.
Also say whether the page in the image fits that paper.
Don't change any code.
Text

How do you debug incorrect batch output end to end?

Find out why last night's run printed the wrong number of picking lists.
Logs/nightly-2026-10-14/print.log reports these five orders as sent.
Orders/warehouse-complaint.csv lists what the warehouse counted by hand for them.

Have the explorer agent read Jobs/NightlyPrint.cs and that log before you write anything.
Your findings go in out/nightly-diagnosis.md, covering:

- the cause behind each count in the complaint file
- the smallest fix
- a --plan command that proves the fix without sending a job

Don't run or edit any code.
Then tell me what you found.
Text

Read the diagnosis before allowing an edit. A sound diagnosis also explains why the log reports success, since the log records each call and not the printed sheets.

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

Put the worker agent on a PrintQueueService class, built like this:

- Install Microsoft.Extensions.DependencyInjection and resolve the service from its container.
- Configure it with a PrintOptions record holding printer, DPI, grayscale and plan-only.
- Keep the README rules and the printer check from PickingPrinter.
- PrintQueueService.cs stays under 150 lines, with XML doc comments.
- Nothing calls Jobs/NightlyPrint.cs.

Run it plan-only over Orders/inbox/ into out/final-plan.csv.
Then compare every status and copy count with manifest.csv and list any difference.
Text

A refactor can lose the printer check and still compile.

Add an xUnit project at tests/PickingBatch.Tests.
Keep it out of the main project's compile items, and put both projects in one solution.

Write tests on the real Orders/ files that check these:

- a 3-copy order gets NumberOfCopies 3 in a single PrintSettings
- a Letter order gets PaperSize.Letter, and an A4 order gets PaperSize.A4
- an order with copies 0 is Rejected and gets no settings
- the empty file and the text file are both Unreadable
- an unknown printer name is refused with a message naming the installed printers

Assert on settings objects and statuses.
Run the tests with dotnet test and a trx logger writing to out/tests/.
Report how many passed and how many failed, reading the trx file.
Text

Assertions on settings objects keep the suite from sending jobs, although the exact name check still needs the configured printer installed.

$ironprint Look in the installed IronPrint.xml.
List every Printer member that sends a job or opens a dialog, then tell me:

- Which ones take a byte array instead of a path?
- Which ones show the operating system's print dialog?
- Which ones are asynchronous?

Back each member with one compiling line in a probe project under scratch/.
Build that probe with dotnet build only, and never run it.
It's the one place a ShowPrintDialog call may appear.
Then show me the line in PrintQueueService that stops plan-only mode from sending a job.
Text

How do you reuse these prompts on another print batch?

With new file names, printer names and copy rules, the same prompts handle shipping labels or invoices. The IronPrint AI coding assistants guide covers the setup shared by every assistant.

What did the prompts produce in a real run?

Codex received the prompts above in order, in a single session. The .NET 9 project held 40 orders, their picking lists and a manifest with each order's expected status and copy count. Separate scripts rechecked every output file.

  • Before the batch, the manifest listed 35 Ready orders, 2 orders with zero copies, 1 missing file and 2 unreadable files.
  • The plan matched the manifest on all 40 orders.
  • Every Ready order in the plan had its manifest copy count and paper size, in portrait orientation at 150 DPI in grayscale.
  • Sending the six sample orders produced one captured job for each.
  • The copy counts in the six print tickets were 1, 2, 2, 1, 3 and 3, equal to the manifest.
  • The six jobs held 11 pages, which the copy counts raised to 20 sheets.
  • The Letter order was captured as 8.5 by 11 inch pages and the A4 orders as 210 by 297 mm pages.
  • Every page of the six captured jobs was a 150 DPI image with no colored pixels, so the red priority band was gray.
  • Without a key, the program listed the four printers and built the settings, and the print call failed with Production License Required.
  • Both incorrect printer names stopped the plan before any row was written, and the message listed the four installed printers.
  • From the scan, Codex identified order PL-1024 and reported three copies on A4 from the plan.
  • The nightly diagnosis traced the 9, 4 and 18 sheets to a loop that called Print once per copy with the full copy count already set.
  • It traced the sheet for the zero-copy order to a clamp that raised 0 to 1.
  • The refactored PrintQueueService had 51 lines, and its plan matched the manifest on every status and copy count.
  • All 7 tests passed in Codex's session and again in a fresh clone.
  • Codex listed the eight Printer members that send a job or open a dialog and built a probe for them without running it.
  • Some steps ran differently from the page. The Quickstart stopped after three failed attempts without writing its CSV. One license check attempt ran with the key still set, and the capture class intercepted its print call. The explorer answered the tray question from the XML instead of querying each printer. Codex reported that the plan-only check was in Program.cs, not in PrintQueueService.

The Google Antigravity guide builds an ASP.NET Core page that awaits the same asynchronous print call. In the Claude Code guide, each document type goes to its own printer and a subagent reviews the printer name check. For the Codex version, model, test machine and timing of this run, see 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 48,068Version:2026.10just released