zplCore.comzplCore.com

Checks & simulation

Know it prints and scans before it prints

Rendering is only the start. zplCore.com checks labels against GS1 and carrier rules, reads every barcode back, simulates printers including their faults and makes labels testable like code. All offline, in your own process and in CI.

Compliance pre-check

84 rules in 8 packs: GS1 logistic label, Sunrise 2027, Amazon FBA, UPS, FedEx, DHL Paket, UDI and RFID. Measured on the rendered label (X-dimension, quiet zones, human-readable text, AI formats, check digits); every finding with line, position and source, as JSON, SARIF or an annotated PNG. A pre-check, not a certification.

ZplCompliance.Check · zplcore comply

Live demo → Docs →

Scan-proof

Every barcode is read back from the rendered image by two independent decoders and compared with the intended data. X-dimension, quiet zones, height and overlaps are measured, plus an A–F grade as a digital pre-check modelled on ISO/IEC 15415/15416. It does not replace a verifier on the printed label.

ZplScanProof.Verify · zplcore verify

Live demo → Docs →

ZPL → editable model

Existing ZPL becomes a data-bound template: text, barcodes, shapes, images and RFID as typed items, ^FN fields as data fields. Every item is checked pixel by pixel; all 318 files of the test corpus round-trip pixel-exact.

Label.FromZpl · zplcore import

Docs →

Label understanding & GDPR redaction

Reads recipient, sender, tracking numbers with check digit, SSCC, GTIN, dates and weights from the ZPL, with location and confidence. Redaction replaces personal data in the same layout, also in comments and 2D codes, and searches again afterwards. Rule-based, no network; review the output before sharing it.

ZplExtract · ZplRedact · zplcore redact

Live demo → Docs →

GS1 Digital Link & Sunrise 2027

Finds the GTIN in EAN/UPC, GS1-128, ITF-14 or DataBar and adds a QR Code with a GS1 Digital Link URI or a GS1 DataMatrix in free space, with quiet zone and a Sunrise pre-check. Builds and parses Digital Link URIs per URI Syntax 1.7.0.

ZplGs1Migration.Migrate · zplcore gs1 migrate

Live demo → Docs →

RFID Studio

Encodes and decodes EPCs per GS1 EPC Tag Data Standard 2.3 (SGTIN, SSCC, SGLN, GRAI, GIAI and the TDS 2.0 plus schemes) with the matching ^RF commands. Checks that the tag carries the same SSCC or GTIN as the printed label.

ZplRfid.EncodeEpc · zplcore rfid

Docs →

Printer Twin

Will this label print on this model? 24 device profiles (including ZD421, ZD621, ZT411, ZT610, ZQ630*) report fields beyond the printhead width, missing options such as cutter or RFID, firmware limits, fonts and memory, plus a print time estimate. Every profile fact cites its source or is marked unknown.

ZplPrinterTwin.Check · zplcore twin

Live demo → Docs →

Chaos printer & cutter

The virtual printer on TCP 9100 fails on request: paper or ribbon out, head open, disconnects, timeouts, scripted and reproducible. ~HS and ~HQES answer like a printer. The cutter simulation shows after which labels the printer cuts, with cut lines in PNG, SVG and PDF.

ZplVirtualPrinter.Faults · zplcore serve --chaos

Live demo → Docs →

Testing+ & GitHub Action

Test labels like code: ZplAssert.Label(zpl) checks that the SSCC barcode decodes to the expected data, plus overlaps, clipping, compliance, printer profile, pixel and semantic snapshots. Failures name the element, its position and the ZPL line. zplcore check and a GitHub Action comment on pull requests with before/after images.

ZplCore.Testing · zplcore check

Docs →

MCP server for coding agents

zplcore-mcp gives Claude Code, Claude Desktop, VS Code and Cursor 26 tools: render, lint, compliance, scan-proof, redaction, printer twin and more. stdio only, no network port; every call runs in its own worker process with time and memory limits and no access to files or the network.

claude mcp add zplcore -- zplcore-mcp

Docs →

PDF/SVG → native ZPL

Vector-Lift turns carrier and ERP PDFs or SVGs into real ZPL instead of a ^GF raster image: text as ^A0 fields, barcodes regenerated and read back, lines and boxes as ^GB/^GC/^GE. With measured agreement per label and element.

VectorLift.Convert · zplcore lift

Docs →

NativeAOT-compatible

SDK, testing package, CLI and MCP server build without trim and AOT warnings. As a NativeAOT container on runtime-deps:10.0-noble-chiseled-extra (~79–105 MB), everything starts without a .NET runtime – verified on macOS, Linux (arm64/x64) and as a local label print server on a Synology DS923+ (793/793 outputs identical to JIT, 24 % faster).

dotnet publish -p:PublishProfile=aot

WindowsLinuxmacOSDockerRaspberry Pi

Docs →

Compliance pre-check: pallet label with findings ZPL3104 and ZPL3110 marked
Compliance: findings on the label
Product label after the Sunrise migration: EAN-13 plus a QR Code with GS1 Digital Link
Sunrise 2027: Digital Link QR Code added
Printer Twin: 4×6 in label on a 72 mm printhead, clipped area hatched red
Printer Twin: what a 72 mm printhead cuts off
Cutter preview: six labels with cut lines after labels 3 and 6
Cutter: cut after labels 3 and 6

Real engine output, generated from the documentation examples.

Quality Gates

Test labels before they go live

A broken template that shows up in production gets expensive: barcodes that do not scan at the dock, lines that stop, shipments the carrier rejects, and waves of errors across every site. zplCore checks every template where it is made: in the commit, in the pull request, in the pipeline and already in the container build.

  1. Git
    Commit

    template changed in Git

  2. Gate
    Pull request

    before, after and diff images in the PR comment, findings as SARIF in code scanning

  3. Gate
    CI pipeline

    zplcore check with JUnit XML and SARIF; exit code 1 stops the build

  4. Gate
    Container build

    a check stage in the Dockerfile: no image is built with a broken template

  5. Staging

    virtual printer with cutter and RFID: cuts, EPCs and VOID as on the real device

  6. Production

    only checked and approved templates

What the gates check

  • Compliance84 rules in 8 packs, e.g. GS1 logistic label and DHL Paket
  • Scan-proofevery barcode read back, minimum grade with --min-grade
  • Printer fitprinter twin: printhead width, options, firmware, fonts
  • Snapshotspixels plus semantics: what changed, not only how much
  • Layout & contentoverlaps, clipping, fields, texts, number of labels
  • Base comparison--baseline: which data and positions the PR changes
  • Cutswhere the cutter cuts: ^MM, ^PQ, ~JK, ^CN
  • RFIDwhich EPC goes on which tag, matching the printed barcode

What a stopped gate looks like

# real output, shortened
PASS templates/dhl-100x150.zpl
FAIL templates/express-100x150.zpl
  FAIL comply gs1-logistic
    :38:1 error ZPL3104 X-dimension 0.375 mm < 0.495 mm
    :38:1 error ZPL3105 bar height 13.0 mm < 31.75 mm
  FAIL scan-proof
    :32:1 error ZT1301 QR Code grade D, required B
  ok   printer ZD421d (ZD421d-203)
FAILED (fail-on error) · exit 1

Checked automatically, explained by AI

  • The gates decide deterministically: same template, same result, exit code 0 or 1.
  • A coding agent (Claude Code, GitHub Copilot, Cursor) checks changes through zplcore-mcp, explains the findings and proposes the fix as a commit.
  • Approval stays with you, e.g. with required reviewers for label changes through CODEOWNERS and branch protection.
  • Also in Azure DevOps, GitLab CI or Jenkins: CLI, exit codes and JUnit XML.

MCP tools:complyverifyprinter_checkrenderdiff

CI gateany pipeline

# exit code 1 on errors, reports for the pipeline
zplcore check templates/ --pack gs1-logistic \
  --verify --min-grade B --printer ZD421d-203 \
  --junit out/labels.junit.xml --sarif out/labels.sarif

Gate in the container buildDockerfile

# build stage: check the templates before an image is built
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS label-gate
WORKDIR /src
COPY nuget.config ./
COPY .config/ .config/
COPY templates/ templates/
RUN dotnet tool restore \
 && dotnet zplcore check templates/ --pack gs1-logistic \
      --verify --min-grade B --printer ZD421d-203

FROM mcr.microsoft.com/dotnet/aspnet:10.0
# only checked templates end up in the image
COPY --from=label-gate /src/templates /app/templates

Unit testxUnit · NUnit · MSTest

[Fact]
public void Shipping_label_prints_and_scans()
{
    ZplAssert.LabelFile("templates/dhl-100x150.zpl")
        .NoOverlaps().NoClipping()
        .Complies(CompliancePacks.Gs1LogisticLabel)
        .FitsPrinter(PrinterProfiles.Get("ZD421d-203"))
        .Barcode("SSCC").Decodes("(00)390012340047110001")
        .HasGrade(atLeast: 'B');
}

Where it cuts and what goes on the tag

A small change to ^MM or ^PQ suddenly cuts every label or none; a fixed ^RF writes the same EPC to every copy. Both usually show up only on the line. In the gate they are settled beforehand.

  1. 1…0000
  2. 2…0000
  3. 3…0000
  4. 4…0000
  5. 5…0000
  6. 6…0000
  • passedcut after labels 3 and 6 (^MMC, ^PQ6,3)
  • gate stoppedZPL3909: 6 labels, the same EPC 3156…8000000 six times, the gate stops
  • passedfixed: one format per pallet, EPC = printed SSCC (00)390012340047110001
Real output: virtual printer (zplcore serve --rfid) and RFID check. Also checked: EPC matches the barcode (ZPL3904), memory bank and PC bits, ^RS/^HV, locks without password.
// cuts: where the cutter cuts
var plan = ZplCutPlan.Analyze(zpl);
Assert.Equal([2, 5], plan.CutAfter);   // after labels 3 and 6
Assert.Empty(plan.Diagnostics);

// RFID: EPC matches the barcode, no duplicate EPC
ZplAssert.Label(zpl)
    .Complies(CompliancePacks.Rfid)
    .FitsPrinter(PrinterProfiles.Get("ZT411-203")
        .WithOptions(PrinterOption.Cutter | PrinterOption.Rfid)
        .AsPrinterFit());
# CI: RFID pack in the gate, show the EPC per label
zplcore check templates/ --pack gs1-logistic,rfid
zplcore rfid simulate templates/palette.zpl

# staging: simulate a printer with cutter and RFID
zplcore serve --profile ZT411-203 --option cutter,rfid \
  --rfid --cut-marks

Available in the SDK today: ZplCore.Testing, zplcore check and zplcore-mcp. The GitHub Action ships with it (tools/github-action); publishing it on the Marketplace as zplcore/label-check is planned. Compliance and grades are pre-checks, not certifications.