Create an archive
glyphive create serializes one directory tree, compresses the complete archive
stream, encodes it as checked printable lines, paginates those lines, and writes
text, PDF, or Word output.
Basic command
glyphive create -f backup.txt -C project .
-C project . means “archive the project directory as the root.” The alpha
CLI accepts exactly one root; put multiple inputs beneath a common directory.
--mode: measured codec/font/size/width/margin presets
--mode {conservative,standard,max} bundles the codec, font, font size,
--line-width, and margin choice into one measured preset, so you don't have
to hand-pick each one. standard is the default (omitting --mode is the
same as --mode standard). Any of --codec/--font/--font-size/
--line-width/--minimal-margins passed explicitly overrides just that one
field from the preset — e.g. --mode max --font-size 8 keeps max's codec,
font, width, and margins but uses 8pt instead of its default 6pt. That holds
for any value you pass, including one that happens to equal a preset's own
or the pre-0.3.0 default of 11: --font-size 11 renders at 11pt, it is not
folded back into the preset.
| Mode | Codec | Font | Size | Width | Margins | Why |
|---|---|---|---|---|---|---|
conservative |
base16g-crc16-rs | dejavu-sans-mono | 8pt | auto (≤60, OCR-measured-safe) |
regular | Lowest density; this project's oldest verified-safe baseline. |
standard (default) |
base16g-crc16-rs | dejavu-sans-mono | 6pt | max |
regular | The most blur-tolerant combination measured — survives a real Gaussian blur ladder up to radius 1.5 on both stock and tesseract-glyphive, beating Courier and Consolas at the same settings. |
max |
base16g-crc16-rs | dejavu-sans-mono | 6pt | max |
minimal | Same measured OCR robustness as standard, smallest page count (minimal margins). |
These are real create → rasterize → OCR → extract → diff restore-gate
measurements, not guesses — see
benchmarks/results/FONT_CANDIDATES.md
("Local font/size sweep" and "Blur-tolerance stress test", both 2026-07-23)
for the full data, including why Consolas (which looks strong on a clean
scan) was not chosen: it fails at a lower blur radius than DejaVu on both
engines, with a non-monotonic pass/fail pattern that indicates an unstable
margin, not a real safety margin.
One direction is not expressible: --minimal-margins is a store-true flag, so
it can be turned on over a preset that leaves it off, but there is no
--regular-margins to turn max's minimal margins back off. Choose
--mode standard (or conservative) instead — the two differ in nothing else.
--line-width max on a format with no physical font metrics (text/docx/qr)
would normally be a hard error — but when max comes from a --mode preset
(not an explicit --line-width max), it quietly falls back to auto
instead, since a mode is meant to work sensibly across every output format.
The output format is inferred from -f: .pdf selects PDF, .docx selects
Word, and .txt or .text selects text. An unknown or missing extension falls
back to text, and an explicit --format always wins. Compression selects
zstd when the optional
dependency is available and otherwise uses gzip. Select behavior explicitly
when reproducibility across installations matters:
glyphive create \
-f backup.txt \
--format text \
--codec base16g-crc16-rs \
--compression gzip \
--metadata none \
-C project .
Short command alias: glyphive c.
Output formats
pip install "glyphive[pdf]"
glyphive create -f backup.pdf --font courier --font-size 8 -C project .
pip install "glyphive[docx]"
glyphive create -f backup.docx --font Consolas --font-size 10 -C project .
PDF output accepts the built-in FPDF families courier, helvetica, times,
symbol, zapfdingbats, and arial, the bundled ocr-b and
dejavu-sans-mono options, an existing .ttf/.otf path, or an installed
system font's name (e.g. --font Consolas or --font "Cascadia Mono") —
glyphive searches the OS font stores for a match, embeds it, and errors
listing what it searched if none is found. Resolution tries a fast filename
match first (e.g. CascadiaMono.ttf for "Cascadia Mono"), then falls back
to reading each candidate file's real font-family name (e.g. Windows'
consola.ttf, whose filename doesn't match "Consolas" but whose family
name does) — so any installed font is reachable by its real display name, not
just fonts whose file happens to be named after their family. Any system font
used this way is measured with the same OCR gate as a bundled one before
relying on it for recovery. Word output
accepts an installed Word font name (bundled fonts are embedded only in PDF;
DOCX references them by name, so a reader without the font installed sees a
substitute). dejavu-sans-mono is bundled under the permissive DejaVu Fonts
License and is the shipped default PDF font: it was one of only two fonts
(with Courier) that held up under the tesseract-glyphive profile in real
scan/restore testing and passed its byte-for-byte restore gate, so it is
preferred for recovery robustness even though Courier measures denser per page.
Pass --font courier for a zero-embedding, higher-density alternative (see the
font ledger for the full comparison and the default-font decision).
OCR-B is bundled under the SIL Open Font License 1.1. It is not the shipped
default, but --font ocr-b --font-size 6 is a measured
dense preset: 5,050 usable bytes/page versus Courier 8pt's 4,125, and it
measured safe (0% character error, 0% line-insertion) on both Tesseract and
PaddleOCR with the project's base16g-crc16-rs alphabet — see
benchmarks/results/FONT_CANDIDATES.md
for the full matrix. Any other font must still be measured with the intended
OCR model before relying on it: a smaller font fits more characters on a
page, but it must be validated on the intended printer, scanner, resolution,
and OCR engine — nominal density is not the same as recoverable density.
Small fonts are a large density lever
Font size scales chars-per-page by roughly (8/size)**2 (both page dimensions
shrink), so a smaller font is a bigger density lever than a wider alphabet. What
matters is not the raw OCR character-error rate but whether the whole page still
restores byte-for-byte — the per-line CRC + Reed-Solomon correct a surprising
amount of small-font OCR noise before decode fails.
End-to-end restore was validated (real create → 300 DPI render → stock
Tesseract with the base16g whitelist → extract → byte-diff) on the default
base16g codec:
| size | density vs 8pt | restores byte-identical (stock OCR)? |
|---|---|---|
| 8pt | 1.0x | ✅ yes |
| 5pt | 2.6x | ✅ yes |
| 4pt | 4.0x | ✅ yes (clean and Gaussian-blurred) |
| 3pt | ~7x | ✅ yes (OCR-B; monospace fonts marginal at 3pt) |
So --font-size 4 roughly quadruples density and still restores with plain
Tesseract — no trained model required (the format's error correction does the
work). Caveats: validate on your actual printer/scanner/DPI/engine (nominal
density is not recoverable density), and pick OCR-B for the smallest sizes.
Note on trained OCR models: none are needed. Byte-restore-gated evaluation (2026-07-19 through 2026-07-22) settled what a trained model buys over stock Tesseract, and the answer is nothing: -
base16grestores byte-for-byte on stock down to 4pt and across row widths. -base32gwas measured to restore on stock as of the 2026-07-22 format fixes, on Tesseract 4.1.1 — but a 2026-07-23 re-gate on Tesseract 5.4.0 found it failing at the same sizes that measurement recorded as passing (see the warning below). Currently NOT recommended pending re-resolution — usebase16ginstead. -base64/base64gcannot be rescued by a model at all: no conflict-free 64-glyph set exists in printable ASCII (the maximum mutually-distinct set is 55, 52 usable), so their alphabets must double-book OCR-confusable classes. They stay encode-only.Every model this project trained — on synthetic lines, on framed pages, and on page rasters — either matched stock or lost to it. The published
glyphive-ocrmodel-*packages were trained on the wrong data and should not be relied on. Stocktesseract-glyphiveis the recommended engine for every codec.
Choosing a denser codec: base32g currently NOT recommended (2026-07-23)
Do not use
base32gon stock OCR right now. A re-gate on 2026-07-23 (benchmarks/results/FONT_CANDIDATES.md, "Local font/size sweep") found that Courier itself — the only font ever confirmed to work — fails to restorebase32gat 8pt and 10pt/width-60 on Tesseract 5.4.0, the exact cells the table below (measured on Tesseract 4.1.1) recorded as passing. A base16g Courier sanity control on the same setup restored fine, so this isbase32gregressing between Tesseract versions/builds, not a broken test. As of this writing, no font/size/width combination has been confirmed working on a current Tesseract build — usebase16g(the default) instead until this is re-resolved.
base32g-crc16-rs carries 5 bits per character instead of 4, so it is ~25%
denser than the default. The table below is the superseded 2026-07-22
measurement (Tesseract 4.1.1, VM) kept for reference, not current guidance:
| font | 4pt | 5pt | 6pt | 8pt | 10pt |
|---|---|---|---|---|---|
| Courier | ✅ (4.1.1 only — FAILED on 5.4.0 at 8/10pt, see warning above) | ✅ | ✅ | ⚠️ | ⚠️ |
| OCR-B | ❌ | ❌ | ❌ | ❌ | — |
| DejaVu Sans Mono | ❌ | ❌ | ❌ | ❌ | ❌ |
(width 60; Courier also restored at width 90 from 5pt up on 4.1.1 — not
re-verified on 5.4.0. — is a geometry refusal, not an OCR failure.)
The cause is the alphabet: base32g adds ?@!&+= to the base16g set, and those
punctuation glyphs are the ones OCR drops or mangles on OCR-B and DejaVu. A
dropped glyph shortens the line, which desynchronizes the frame parse — a
failure Reed-Solomon cannot repair, unlike an ordinary misread character.
So: use base32g only with Courier. For any other font, base16g is the
correct choice; a smaller font size buys far more density than a wider alphabet
anyway (4pt is ~4× denser than 8pt and still restores on stock).
The number of rows per page is calculated from the selected font size and page
geometry. Use --minimal-margins to reduce all margins from 36 points to 12
points and use more of the sheet. Confirm that the resulting printable area is
inside the limits of the intended printer and scanner before relying on it:
glyphive create -f dense.pdf --format pdf --font-size 8 --minimal-margins -C project .
PDF creation also measures the selected font's widest safe glyph and clamps the
payload width to whichever is smaller: what fits between the margins at the
requested size/spacing, or 60 characters -- the one width every OCR-safety
measurement in this project (including the OCR-B "dense" preset) was actually
taken at. A font whose glyphs are narrow enough to geometrically fit more than
60 characters does not automatically get a wider row: the raw per-character
OCR error rate climbs as rows get denser (measured, e.g., on OCR-B 6pt's own
~90-char geometric fit), so 60 is the width that is safe across every font and
size. A wider row can still restore byte-for-byte once the frame CRC + RS
correct that extra noise (see the --force note below), but that margin is
font/size-specific, not guaranteed — which is why the conservative width is the
default rather than the maximum. Text and Word output retain 60 by default for
the same reason, on top of not exposing reliable physical font metrics.
--line-width accepts three spellings:
auto(the default) — the OCR-measured-safe capacity (≤ 60). Same as omitting the flag.max— the largest row that physically fits the font/size/margins. This may exceed 60 and is not OCR-verified; choosing it is the explicit opt-in past the safe cap. On text/Word output (no physical font metrics)maxis an error — useautoor an integer.- an integer ≥ 2 — an explicit column count. An integer above the safe cap
needs
--force(and must still fit the geometric width); below the cap it is accepted directly. On formats without font metrics no cap is enforced.
A wider-than-60 row (max, or a forced integer) is past the conservative
default cap, but it is not automatically unsafe. A byte-restore benchmark
(create → 300 DPI raster → OCR → extract → byte-diff) over Courier base16g
restored byte-for-byte at row widths 60, 75, and 90 (50% past the cap) at
both 8pt and 5pt, clean and lightly blurred — the frame CRC + Reed-Solomon
absorb the extra OCR noise a denser row adds. The 60 default stays because it
is the width every OCR-safety measurement was taken at and the safe width across
all fonts/sizes; wider rows are font- and size-specific and the render-time
guard still fails loud if a frame physically overflows the page (at 8pt Courier
the geometric fit is ~98 characters, and create refuses anything past it).
Decode infers row width from the frames, so no separate restore option is
needed.
Create uses disk-backed temporary spools so archive-sized payloads and encoded
page lists do not have to remain in memory. Spools use the system temporary
directory by default; advanced users can select a same-filesystem location with
--temp-dir PATH and tune sequential I/O with --chunk-size BYTES (default:
1 MiB). Temporary files are removed on both success and failure. DOCX generation
still retains python-docx's in-memory document model, while text and PDF output
are written directly to their destinations.
PDF and DOCX output can center each fixed-width line with
--horizontal-alignment center, or distribute its characters across the full
printable width with --horizontal-alignment justify. Use
--character-spacing POINTS for a smaller, fixed amount of extra tracking. For
example:
glyphive create -f spaced.pdf --font ocr-b --font-size 8 \
--horizontal-alignment center --character-spacing 0.2 -C project .
These controls change physical placement. For PDF, character spacing can also
reduce the automatically selected payload width; use --line-width when an
experiment requires identical wire rows across layout variants. justify uses
different tracking on lines of different lengths, so
center plus modest fixed spacing is usually the better starting point for a
character-grid OCR workflow. Treat either option as experimental until it has
passed the same print/rasterize/OCR benchmark as the chosen font and size.
Text output preserves exact line endings and separates pages with a form-feed character. Do not reflow or word-wrap a transcript.
Compression
| Name | Dependency | Notes |
|---|---|---|
none |
none | Useful for isolating encoding and OCR behavior |
gzip |
none | Portable stdlib compression |
zstd |
glyphive[zstd] |
Optional whole-stream compression |
The legacy --none, -z/--gzip, and --zstd flags remain aliases. They are
mutually exclusive, and a legacy flag that disagrees with --compression
causes the command to stop before writing output.
-L/--level forwards a compression level to the selected implementation.
Redundancy and whole-page recovery
Three independent layers protect a printed document, tuned separately:
- In-line parity (
--line-parity {0,2,4}, default2) puts a small Reed-Solomon field on each printed line, covering that line's own index and payload. A line with one or two bad characters is corrected in place — re-rendered and re-checked against its own CRC — so it never spends any of the document-level budget below. This is the cheap insurance that matters for aged or lightly damaged paper:2costs about 6.9 % more printed characters,4about 12.3 %, and0restores the classic three-token frame with no overhead. Measured effect at the default: documents survive roughly a 0.5 % character error rate where they previously failed below 0.1 %. - Document-wide Reed-Solomon (
--parity-ratio FLOAT, default0.12) heals what the in-line layer could not — a line too damaged to correct becomes a known erasure and is rebuilt from parity carried on other lines. Lower values shrink the page count but leave less correction budget.--simpleis a documented low-redundancy preset (0.04) for small, disposable, or easily re-typeable documents. - Whole-page parity (
--parity-pages K, default0) emits K extra pages of document-level Reed-Solomon parity over the data pages, so the document survives up to K wholly lost pages (physically destroyed, unscannable, or dropped) — not just character noise. Costs K extra printed pages. Data pages plus K must not exceed 65,535 (a create-time error names the cap). Documents of 255 blocks or fewer use Reed-Solomon over GF(2^8); larger ones switch automatically to GF(2^16), which pairs adjacent bytes into 16-bit symbols so the codeword limit rises from 255 to 65,535. The choice is recorded in the protected header, so restore selects the right field without being told, andglyphive inspectreports which one a document uses. Encoding a 1,000-page document with--parity-pages 8measures ~2.7 s.
glyphive create -f resilient.pdf --parity-pages 2 -C project .
# Maximum in-line correction (widest per-line parity), for paper you expect to age
glyphive create -f archival.pdf --line-parity 4 --parity-pages 2 -C project .
# No per-line parity — smallest page count, relies on the document-wide layer
glyphive create -f compact.pdf --line-parity 0 -C project .
Even with --parity-pages 0, a missing page is no longer an immediate failure:
restore lets the per-line Reed-Solomon try to recover it from the surviving
pages, and only fails if that budget is exceeded. Dedicated parity pages make
that recovery guaranteed up to K lost pages regardless of the per-line budget.
Metadata profiles
--metadata noneis the default. It archives paths, file contents, and explicitly empty directories.--metadata basicalso records ordinary permission bits and modification time rounded to integer milliseconds.
Metadata restoration is best-effort because filesystems and operating systems do not all expose the same permissions or time resolution.
Header line
Page 1 begins with a compact, human-readable summary:
#!glyphive v1 base16g-crc16-rs,zstd files=25 bytes=211233 pages=61
This line is display-only — restore reads every authoritative value from the
CRC-protected H frames, never from this prose (see the
wire format). It deliberately omits the SHA-256 and metadata
profile, and any line starting with #! is treated as a comment on the read
path. Pass --no-header to omit the line entirely for the tightest possible
page; the document still restores identically because nothing depends on it:
glyphive create -f tight.txt --no-header -C project .
Ignore behavior
Glyphive reads .gitignore and .ignore only at the archived root. Matching
files and directories are excluded, and .git/ is always excluded. Nested
ignore files are not currently applied.
Use --no-ignore to archive everything except .git/:
glyphive create -f complete.txt --no-ignore --compression gzip -C project .
Symbolic links, junctions, and special files are rejected rather than followed; the current archive format has no link or device record.
Verify the result
Inspect the protected header and file manifest before printing:
glyphive list -f backup.txt
For important backups, perform a full restore into a new directory and compare it with the source before treating the printout as the only copy.