Kind85 — the code, free

MIT licensed — use it, sell it, break it, no strings. I'm not sure anyone needs to encode 4 bytes into 5 characters with forgiveness… but maybe it helps someone. I wouldn't have been able to build my things if the parts had been paywalled — so here's my part, unpaywalled. Three small Python files, standard library only.

⬇ kind85.zip — everything
kind85.py pack.py reconstruct.py LICENSE.txt README.txt
# Kind85 — MIT License, (c) 2026 Mark Whiskeyman. See LICENSE.txt.
"""Kind85 - base85 with a forgiving decoder (Postel's Law: strict out, lenient in).

Shared by the Packer (author) and the Reconstructor (student). Because both import
THIS file, they can never disagree about the alphabet, the aliases, or the checksum.
"""
import zlib

# --- the 85 canonical glyphs: printable ASCII minus 9 look-alikes ---
_EXCLUDE = set("OolI|TB:`")            # these are NEVER emitted by the encoder
KIND85 = "".join(chr(c) for c in range(0x21, 0x7F) if chr(c) not in _EXCLUDE)
assert len(KIND85) == 85, f"alphabet is {len(KIND85)}, need 85"

_VAL = {ch: i for i, ch in enumerate(KIND85)}      # glyph -> value 0..84

# --- forgiving decode: each look-alike collapses to its canonical twin ---
_ALIAS = {"O": "0", "o": "0", "l": "1", "I": "1", "|": "1",
          "T": "7", "B": "8", ":": ";", "`": "'"}
for _a, _c in _ALIAS.items():
    _VAL[_a] = _VAL[_c]

# Typographic "corrections" a word processor loves to make (smart quotes, em-dashes,
# ellipsis). We UNDO them on decode so publishing can't quietly corrupt a line.
_TYPO = {
    "“": '"', "”": '"',        # curly double quotes  ->  "
    "‘": "'", "’": "'",        # curly single quotes  ->  '
    "–": "-", "—": "-",        # en / em dash         ->  -
    "…": "...",                      # ellipsis             ->  ...
}


def canonical(text: str) -> str:
    """Undo smart-punctuation, strip whitespace, collapse look-alikes to canon."""
    for _bad, _good in _TYPO.items():
        text = text.replace(_bad, _good)
    text = "".join(text.split())
    return "".join(KIND85[_VAL[ch]] for ch in text)   # KeyError = a truly invalid char


def encode(data: bytes) -> str:
    """Strict base85: 4 bytes -> 5 canonical glyphs. Pads data to a multiple of 4."""
    if len(data) % 4:
        data += b"\x00" * (4 - len(data) % 4)
    out = []
    for i in range(0, len(data), 4):
        n = int.from_bytes(data[i:i + 4], "big")
        g = []
        for _ in range(5):
            n, r = divmod(n, 85)
            g.append(KIND85[r])
        out.append("".join(reversed(g)))
    return "".join(out)


def decode(text: str) -> bytes:
    """Forgiving base85: accepts look-alikes and whitespace. 5 glyphs -> 4 bytes."""
    text = canonical(text)
    out = bytearray()
    for i in range(0, len(text), 5):
        n = 0
        for ch in text[i:i + 5]:
            n = n * 85 + _VAL[ch]
        out += n.to_bytes(4, "big")
    return bytes(out)


def crc4(text: str) -> str:
    """4-glyph checksum (~52 million combos) of a CANONICAL string."""
    n = zlib.crc32(text.encode("utf-8")) % (85 ** 4)
    g = []
    for _ in range(4):
        n, r = divmod(n, 85)
        g.append(KIND85[r])
    return "".join(reversed(g))

What the other two do: pack.py turns any file into numbered, checksummed book lines (file → lzma → Kind85, self-tests its own round-trip). reconstruct.py is the reader's side: type lines in any order, each is verified on the spot (line number folded into the CRC), then the file is rebuilt byte-perfect. See it run live in the Kind85 demo.

Standing on two older wheels that weren't supposed to fit together: Ascii85 supplied the density (4 bytes → 5 characters) and Crockford Base32 supplied the manners (a decoder that accepts O for 0 and l for 1 instead of punishing the typist). The two are natural enemies: forgiveness needs spare characters to sacrifice, and density hoards them all. Crockford could afford kindness because Base32 uses 32 symbols and leaves plenty on the table. Base85 needs 85 of the 94 printable ASCII characters — exactly 9 left to burn. Count the look-alikes worth banning (O o l I | T B : `): exactly nine. The two schemes should collide, and they miss by zero — that coincidence is the whole invention.