Creative ops and iOS release managers still burn time when AppIcon.appiconset PNGs disagree with Contents.json, triggering late Xcode failures and App Store surprises. Here is a 2026 reproducible remote Mac playbook: configure OpenClaw, run a batch validator that compares measured pixels to JSON expectations, write a Markdown fix report, and optionally wire a debounced folder watch or launchd slice so design delivery automation stays predictable. Cross-check slot math with our iOS App Icon delivery matrix.
Table of Contents
Why catalog drift still happens
- Scale math errors: one master is copied to 2× and 3× without recomputing pixels; filenames match
Contents.jsonwhile geometry does not. - Stale JSON: PNG renames without updating every
imagesentry create orphans and missing references. - Silent resizes: optimizers or padding steps change edge lengths while previews still look fine.
A gate before merge or upload turns these into single-line report rows instead of midnight build breaks.
Choose your automation shape
| Mode | Best when | Trade-off |
|---|---|---|
| Manual CLI run | One-off audits before App Store submission | Low setup; easy to forget under time pressure |
| OpenClaw + debounced watch | Designers drop exports into a shared inbox on the remote Mac | Requires idle-window tuning so partial writes never validate |
OpenClaw + launchd slice |
Predictable batches every fifteen minutes or nightly | Simpler capacity planning; slight delay until the next tick |
Install, configure, and run (five moves)
- Install OpenClaw and helpers: install OpenClaw on the worker using the project’s standard bootstrap, add
jq, and confirmsips -g pixelWidth -g pixelHeightworks on sample PNGs. - Pin the target catalog: export
APPICON_DIR=/path/to/AppIcon.appiconsetandREPORT_PATH=./logs/appicon_fix_report.md. Recordgit rev-parse HEADat the top of the report for traceability. - Lint
Contents.json: runplutil -lint Contents.json. Fix syntax before any pixel logic; malformed JSON causes false negatives. - Compute expected pixels: for each
images[]item with afilename, parsesizelike60x60andscalelike2x. Expected edge length equals base points multiplied by the integer scale factor (2× → 2, 3× → 3). - Measure and diff: for every referenced PNG, read actual width and height. Append a Markdown row when they differ. Exit non-zero if any mismatch remains so CI or OpenClaw can quarantine the job.
Watch hook and batch script templates
Debounced watch: after inbox/appicon/ is idle ~45s, copy to work/, validate, promote to out/ with report.md, or move failures to failed/.
Batch slice: loop all *.appiconset trees under Assets.xcassets for white-label repos; concatenate nightly Markdown.
#!/usr/bin/env bash
set -euo pipefail
DIR="${1:?path to AppIcon.appiconset}"
REPORT="${2:-./appicon_validation_report.md}"
JSON="$DIR/Contents.json"
{
echo "# AppIcon validation"
echo "- host: $(hostname)"
echo "- path: $DIR"
echo ""
echo "| filename | expected | actual | status |"
echo "|---|---:|---:|---|"
} > "$REPORT"
while read -r name w h; do
[[ -z "${name:-}" ]] && continue
fp="$DIR/$name"
if [[ ! -f "$fp" ]]; then
echo "| $name | ${w}x${h} | missing | FIX: add file |" >> "$REPORT"
continue
fi
read -r aw ah < <(sips -g pixelWidth -g pixelHeight "$fp" \
| awk '/pixelWidth/ {w=$2} /pixelHeight/ {print w, $2}')
if [[ "$aw" -eq "$w" && "$ah" -eq "$h" ]]; then
echo "| $name | ${w}x${h} | ${aw}x${ah} | OK |" >> "$REPORT"
else
echo "| $name | ${w}x${h} | ${aw}x${ah} | FIX: re-export |" >> "$REPORT"
fi
done < <(jq -r '.images[] | select(.filename!=null)
| [.filename,
((.size|split("x")[0]|tonumber) * (.scale|sub("x";"")|tonumber)),
((.size|split("x")[1]|tonumber) * (.scale|sub("x";"")|tonumber))]
| @tsv' "$JSON")
echo "Wrote $REPORT"
Extend the jq filter for ipad-only rows or missing scale; always derive expected pixels from JSON. After geometry passes, stack PNG QA batch for alpha, ICC, and byte caps.
Numbers and policies worth quoting
- Classic scales: 1× / 2× / 3× map to multipliers 1, 2, and 3 for edge length from
sizeinContents.json. - Debounce & retention: use thirty to sixty seconds idle on watched trees; keep ~thirty days of Markdown or JSONL beside
logs/for diffable release history.
FAQ: common errors
jq: error or parse error on Contents.json
Run plutil -lint first. Remove merge conflict markers and ensure the file is UTF-8 without a BOM. Validate against a known-good template from a fresh Xcode asset catalog.
sips cannot read the PNG
The file may be zero bytes, mislabeled WebP, or still being written. Enforce the idle window, reject empty files, and require a .done sidecar if your export plugin supports it.
Everything measures correctly but Xcode still complains
Check idiom-specific rows, alpha on the 1024 marketing asset, and inclusion of mandatory slots for your deployment target. Geometry validation is necessary but not sufficient for App Store policy.
Run this flow on a dedicated remote Mac so laptops stay free for creative work while OpenClaw owns overnight validation. Browse the full Tech Insights library for adjacent automation articles.
Compare Mac nodes and deploy your App Icon validation worker
Open pricing and rental options on MacPng without signing in, then follow the help center for SSH or VNC access to paste the same scripts on your rented host.