receipt-print routes commands through receipt-print serve at
http://127.0.0.1:9100 when that service is healthy. If no service is
available, the CLI retains direct printer access under the same device lock
used by the daemon. Set RP_PRINT_MODE=service to require the daemon or
RP_PRINT_MODE=direct to bypass it explicitly.
The service serializes jobs, streams raw output in bounded USB transfers, and
journals X-Receipt-Print-Job-Id values so a lost response cannot cause an
automatic duplicate. Print jobs have no total-duration cutoff by default. Set
RP_SERVE_JOB_TIMEOUT and RP_SERVICE_DELIVERY_TIMEOUT to positive seconds to
impose explicit server and client deadlines. The client retries a lost HTTP
response once with the same identity.
A Unix-inspired CLI for printing content on thermal receipt printers.
A global installation is recommended, e.g. with uv:
uv tool install receipt-printUSB receipt printers usually need a udev rule before an unprivileged user can open them through libusb. For Epson printers:
sudo modprobe usblp
sudo tee /etc/udev/rules.d/70-receipt-print.rules >/dev/null <<'EOF'
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="04b8", MODE="0660", GROUP="lp", TAG+="uaccess"
SUBSYSTEM=="usbmisc", KERNEL=="lp[0-9]*", ATTRS{idVendor}=="04b8", MODE="0660", GROUP="lp", TAG+="uaccess", SYMLINK+="receipt-printer"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=usb --attr-match=idVendor=04b8
sudo udevadm trigger --subsystem-match=usbmiscOn headless systems, or systems without logind seat access, add your user to the selected group and start a new login session:
sudo usermod -aG lp "$USER"Print piped text:
echo "hello" | receipt-print
cat file.txt | receipt-printPrint text:
receipt-print text "hello" "world"
receipt-print text -l "line 1" "line 2" # use newlines instead of spaces
receipt-print text --size 3 "big text"Print file content:
receipt-print cat file1.txt file2.txtPrint images:
receipt-print image img1.png img2.png
receipt-print image https://example.com/photo.jpg
cat image_paths.txt | receipt-print image
pbpaste | receipt-print image # clipboard file or path
receipt-print image --tile 5 mural.png # print a set of sequential vertical segmentsPrint PDFs:
receipt-print pdf document.pdf
receipt-print pdf --pages 1,3,5 document.pdf
# print from clipboard (path or file)
pbpaste | receipt-print pdf # or paste from `wl-paste` / `xclip -selection clipboard -o`
# convert to text first
receipt-print pdf --format text document.pdfPrint Wi-Fi QR sheets:
receipt-print wifi # choose a stored Wi-Fi profile
receipt-print wifi --ssid "Sample Net" --password "example passphrase"
receipt-print wifi --ssid "Sample Net" --password "example passphrase" --omit-password
receipt-print wifi --ssid "Guest WiFi" --security nopassRun command(s) and print captured output:
receipt-print shell "ls -l" "git status"
receipt-print shell "hostname -I | awk '{print $1}'"Skip cutting:
receipt-print text --no-cut "hello"
cat file.txt | receipt-print --no-cut
RP_NO_CUT=1 receipt-print image img1.pngConfigure using environment variables (see python-escpos documentation):
RP_VENDOR: USB vendor ID (default: 04b8)RP_PRODUCT: Optional exact USB product ID. If unset,auto, or*, the first USB printer matchingRP_VENDORis used.RP_USB_AUTO_DISCOVER: Set to0to disable product-ID fallback discovery after an exactRP_PRODUCTmiss.RP_DEVICE: Exact device file path (e.g.,/dev/receipt-printeror/dev/usb/lp0). Uses the kernel driver instead of libusb.RP_DEVICE_AUTO_DISCOVER: Set to0to skip automatic/dev/receipt-printer*and/dev/usb/lp*discovery.RP_DEVICE_CANDIDATES: Comma-separated device paths to try before libusb whenRP_DEVICEis unset.RP_PROFILE: Printer profile (default: TM-T20II)RP_HOST: Network printer IP address (optional, fallback if USB fails)RP_CHAR_WIDTH: Character width per line (default: 72)RP_MAX_LINES: Maximum lines allowed without confirmation (default: 40)RP_NO_CUT: Set to1to disable automatic cutting