Output Checker for the Christmas card project
The Christmas card project script makes hundreds of print files every night during the season: order forms, Christmas cards, gift labels, calendars, mugs, keyrings, fridge magnets and so on. Each file must contain exactly what the parents ordered: the right number of pages for every pupil, with the right name, class and school on it. Nobody can check thousands of pages by eye, so I made an Output Checker that does it automatically after each run.
It’s not an InDesign script. It’s a small Python program plus a set of instructions (a skill) for Claude, the AI assistant. You can run the program on its own from the command line, or simply ask Claude to “check the result” and it runs the program, looks at the pages it flagged and writes a short report.
What it checks
The checker reads the same Excel workbook the script uses and compares it with the PDF files in the Print Files folder of the school. It knows nothing about InDesign and doesn’t trust the script’s own logs: it only looks at the input and the final result.
- Pupils and scans. The number of pupils in every class tab must match the number of scans in the class folder. One missing name moves every following name onto the wrong drawing.
- Page counts. For every product, it calculates how many pages each pupil must get from the order columns: for example, one pack of Christmas cards is 3 pages of 4up cards, a value pack adds two more packs of cards and a pack of gift labels, and a 3 for 2 offer gives three packs. Then it counts the pupil’s pages in the PDF.
- Texts. The name, class and school of the pupil must be printed on his or her pages. A value marked as hidden in the spreadsheet (for example,
**Bobby**) must not be printed on the products. - Order forms. One form for every pupil, 8 per sheet, front and back. For online order forms, the reference and PIN of each pupil must be on the form; the order deadline comes from the spreadsheet.
- School-level files. Products that are pooled for the whole school, like keyrings 21up, fridge magnets 18up and the sticker sheets, must hold exactly as many items as were ordered in all classes together.
- Cards with a message. Every front page must be followed by an inside page with the pupil’s own message.
- Blank or broken files. A PDF that’s too small for its number of pages, or has blank pages, usually means the artwork or background wasn’t placed.
The checker reads the text on every page, including mirrored text (the backs of folded cards are printed upside down) and rotated text, and assigns each page to a pupil by the printed name. It checks only the products that were actually made in this run, and lists the ones that were ordered but not produced, so nothing is forgotten.
The rules
All the knowledge about the products is kept in a plain text file, rules.yaml, not in the program. For each product it says which column of the spreadsheet feeds it, how many packs one unit means, how many pages one pack takes, the file name of the PDF and which texts must be printed. Here’s the rule for the Christmas cards:
Christmas cards:
pdf: "Christmas cards 4up - {class} - {school} - Print Files.pdf"
pages_per_pack: 3 # 12 cards = 3 pages x 4up
sources:
- {column: K, packs: 1} # Christmas Cards
- {column: O, packs: 3} # 3 for 2 = 3 packs
- {column: Y, packs: 2} # Value Pack = 2 packs of Christmas cards
mirrored_text: true
check: [name, class, school]
Every season, the products and the spreadsheet change a little: a product is dropped, a column moves, a new offer appears. In this case, only the rules file has to be edited, and my client and I can both do it, since the checker lives in a shared Dropbox folder. A check that turns out to be wrong can be switched to a warning, so it’s still reported but doesn’t mark the school as a problem.
The report
For every school, the checker writes a _Check report.md file next to the school’s workbook. It starts with OK or PROBLEM, then lists each product: the file, the number of pages found and expected, and only the problems, grouped so that one missing pack in ten pupils is one line, not ten. When Claude runs the checker, it also opens the flagged pages to say why they failed (pages missing, a name printed in another form, a hidden value printed) and compares the findings with the script’s own error log and run summary.
For example, on the first test of this season, the checker found that the order deadline was missing on the order forms. The reason turned out to be a one-row shift in the new spreadsheet: the script was reading the cell above the deadline. That’s exactly the kind of error that’s easy to miss in a print file and expensive to find after printing.
How to run it
It needs Python 3 with three libraries: openpyxl to read the workbook, pdfplumber to read the PDFs and pyyaml for the rules:
pip install openpyxl pdfplumber pyyaml python scripts/check_output.py "path/to/Schools/Some School"
Point it at one school folder or at the whole Schools folder to check every school in one go. Use --products "Christmas cards" to check only certain products.
Or, in a Claude chat connected to the project folder, just write “check the result” after the script has finished.
