Byte-exact raster encoder for the Brother PT-P750W (primary; PT-P710BT and PT-E550W also work). A layout library, a TOML preset format for declaring new label types, and a QR / image decorator that snaps onto any label. Adding a new category is usually ~10 lines of data, not a Python class. Driveable from a CLI, an HTTP service, or a Claude Code skill. Dry-run by default.
Four layers, deliberately small.
Byte-exact against Brother's command reference, cross-checked against treideme/brother_pt in CI. Handles every TZe width (3.5–24 mm), half-cut, multi-label batches, and the 32-byte status packet so real sends can be gated on "loaded tape matches the job."
A small set of pure functions — render_two_line_label, TwoLineLayout, fit_text_to_box, icon placement, QR composition — that compose a Pillow image at 180 DPI for a given tape width.
~30 of the shipped labels are declarative data: a schema, a primary line, a secondary line, optional conditionals. Adding a new one is an entry in presets.toml. No Python required.
The few labels that need custom geometry — cable flags that wrap around a cable, polarity icons, GHS hazard pictograms, the QR + image primitives — stay as Python classes. Five of the 36 ship today.
Cross-cutting additions (QR codes, arbitrary bitmaps) are --link / --image flags that snap onto any template's output. A QR next to a pantry jar doesn't need a new template.
lp print and lp batch encode + write bytes to a file but never drive the printer unless you add --send. Same for POST /print — send: true is opt-in.
Pass wire=ethernet or 18AWG and the wrap section is sized to the cable's outer diameter. 40+ keywords plus every AWG built in.
~50 curated Lucide icons bundled. Install the full ~1500 Lucide set or ~7000 Material Design Icons with one lp icons install-* command.
Ship your own templates — preset + bespoke mix — as a separate pip package. External packs register via standard Python entry points, with a safe-mode env var for supply-chain caution.
A handful of labels that show what the engine does, grouped by how they're built. Everything here renders at 180 DPI on 12mm tape. The full catalog — 36 templates across 12 packs — lives in lp list; there is no point in listing them on a web page.
Most labels are a preset entry: a name, a schema, a primary line, a secondary line. The preset loader builds the Template at registry init. No Python required.
Optional Lucide icon on the left, optional expiry on the right. The `icon_field` preset key wires a named field to the icon slot.
primary = "{name}"
secondary = [
"{purchased}",
{ if = "expires", text = " · exp {expires}" },
]
icon_field = "icon"

Four required fields, two optional temps — joined with · separators only between parts that are actually set.
secondary_join = " · "
secondary = [
"{brand}",
"opened {opened}",
{ if = "nozzle_temp", text = "N {nozzle_temp}°C" },
{ if = "bed_temp", text = "B {bed_temp}°C" },
]

A derived eat_by field computed from cooked + eat_within_days, so the label shows both dates without the caller doing the math.
[[presets.derived]]
name = "eat_by"
kind = "date_offset"
from_field = "cooked"
days_field = "eat_within_days"
secondary = [ "{cooked} → eat by {eat_by}" ]

The fragile flag is a string field; the conditional appends · FRAGILE to the headline only when the value is truthy (and "no" / "false" / "0" count as falsy).
primary_parts = [
"{room}",
{ if = "fragile", text = " · FRAGILE" },
]
The few labels that need something the two-line mould can't express — a wrap-around wire flag, polarity icons, a GHS pictogram — stay as Python classes. Five of the 36 ship today.

Two faces printed back-to-back with a wrap section in the middle sized from the cable's outer diameter (π·OD + adhesive overlap). Pass wire=ethernet, wire=18AWG, or a literal wire="5mm". 40+ cable keywords and every AWG built in.

Voltage · current on the headline, a centre-positive polarity ring drawn in the same raster pass. Not worth expressing as a preset — the icon placement is the whole point.

GHS pictogram on the left (flammable, corrosive, toxic, etc.), hazard name + regulatory code on the right. Pictograms are SVG assets composited into the label.
--link and --image snap onto any template's output. Adding a QR or a bitmap doesn't require a new template — a cable flag, a pantry jar, a tool tag can all carry one.

Same pantry preset, plus a QR that points at the canonical note in your Obsidian vault. Claude decodes the QR from a phone photo later, so the QR content is opaque to the phone's native scanner — it can be vault:kitchen/sauces/sriracha.
lp render kitchen/pantry_jar \ -f name=SRIRACHA -f purchased=2026-04-17 \ --link vault:kitchen/sauces/sriracha

Any bitmap — a personal logo, a project sigil, an asset-ID barcode — can be composed onto the right edge. The decorator fits it to tape height, threshold-converts to monochrome, and leaves the template's own layout untouched.
lp render three_d_printing/tool_tag \ -f tool=Calipers -f owner="aes / 3d-printing" \ --image ~/assets/logo.png
Everything in the Brother "Raster Command Reference" family. Anything outside it needs a new encoder.
128-pin head · 180 DPI · half-cut · USB + Wi-Fi
Cube Plus — same command set; half-cut bit silently ignored (no hardware for it)
Same raster command reference, same 128-pin head
Original Cube — different (simpler) protocol
Cube Pro — different command set, wider head (36mm)
Completely different protocols
# discover lp packs # installed template packs lp list [--category kitchen] # templates in a pack lp show <category>/<name> # field schema # render (no transport touched) lp render <template> -f k=v ... # PNG + raster preview lp render-image <file.png> # raster-encode an arbitrary image # print — dry-run default, --send opt-in lp print <template> -f k=v ... # single label lp print <template> -f k=v ... --send # really print lp batch <spec.json> # chained multi-label job (half-cut) # hardware lp status # loaded tape + error flags (Phase 5) # extras lp wires # cable-keyword → outer-diameter lp icons list | preview <name> # bundled Lucide icons lp icons install-lucide | install-mdi # clone full icon sets lp serve --host 127.0.0.1 --port 8765 # FastAPI HTTP service