ID@agntn/encodingsv0.0.0
Decode it. Don't eyeball it.
Ask a model what a base58 string says and it reads the vibe. This reads the bytes. Base64, base58 with its checksum, bech32 down to the witness program, and the rest. Written from the RFCs and BIPs. One call in TypeScript, the terminal and your agent. No network, nothing to configure.
- Encodings
- 20
- in 11 families
- With checksum
- 3
- 4 agent tools on top
- Network calls
- 0
- every value computed in place
$ pnpm add @agntn/encodingsBase64
Three bytes as four characters. MIME, data URLs, PEM.
Alphabet
- Size
- 12 bytes → 16 chars
- Overhead
- +33% · 13 of 64 used
- Padding
- = to a whole block
- Standard
- RFC 4648 §4
Same call, every encoding
Pick a name, hand it bytes, get text back. Then do it backwards. This file walks through 20 encodings and none of it is a recording. Your browser runs every line with the same TypeScript the package ships. Round trip true, every time? That's the whole point. Bech32 is the fun one, its prefix comes back in details instead of hiding in the bytes.
- encode(name, input) and decode(name, text). That's the whole API you need on day one
- Strings go in as UTF-8. A Uint8Array goes in as it is
- Names forgive you: Base 64, base_64 and b64 all find base64
Round trip
import { decode, encode, identify } from "@agntn/encodings";// Base64, RFC 4648 §4const text = encode("base64", "hello world!");// "aGVsbG8gd29ybGQh"const { bytes, details } = decode("base64", text);bytes.length; // 12, details {}encode("base64", bytes) === text; // trueidentify(text)[0]?.encoding;// "base64"A guess that shows its work
Someone pastes MZXW6=== and asks what it is. A model squints and says base64, probably. identify tries every encoding it knows and ranks the ones that actually decode. Each score comes with its reasons, so you can disagree with it. The confidence ranks, it doesn't promise. And when nothing fits? It says so, instead of inventing an answer.
- A checksum that matches beats everything. Base58Check and bech32 prove themselves
- Then framing: padding that fits, <~ ~>, a begin line, =XX escapes
- Then text that reads like text, then the smaller alphabet
base64, it is
Decodes to readable text.
- base64"hello world!"0.371
- base64url"hello world!"0.371
- base32-crockfordhex 543795c1106893e5c2f10.043
Twenty encodings, five ways to spell bytes
Bit groups, where every character carries the same few bits. Base58, which treats the whole input as one huge number. Fixed blocks like Ascii85 and basE91. Bech32, where a checksum catches your typos for you. And two mail formats older than most of the internet. Three of them check themselves on decode. Every one written from its RFC, BIP or reference code, with no codec library underneath.
Importimport { encodings, create } from "@agntn/encodings"
Big number
Four tools, one executor
Ask a model to decode base58 and it decodes the vibe. Give it encodings_decode and it decodes the string. encodings mcp, the Pi and OMP extensions and @agntn/encodings/ai all call the same executors. This page runs them too, so the dialog shows exactly what a model reads for "hello world!".
- encodings_encode, encodings_decode, encodings_identify, encodings_info
- A misspelled argument is an error, not a silent default
- Bytes come back as text when they read as text, as hex when they don't
Base64
The bytes come out of the executor, not out of the model's imagination. Readable text comes back as text, anything else as hex.
- bytes
- 12 as utf8
- value
- hello world!
- carried
- nothing but data
Your own encoding is one object
Need octal because some puzzle printed od -b output? Write the object, register it, and the registry treats it like a built-in. Even identify picks it up. No plugin manifest, no base class to fight. Throw a DecodeError for text that's wrong, and the CLI and the MCP server report it like one of their own. The alphabet you declare even feeds the small alphabet score.
- A name, info(), encode and decode. That's the Encoding interface
- register(encoding) and encode, decode and the tools see it
- identify tries it too, no extra wiring
import { DecodeError, encode, identify, register, type Encoding } from "@agntn/encodings";const octal: Encoding = { name: "octal", info: () => ({ /* label, family, standard, alphabet, options */ }), encode: (input) => /* three octal digits per byte, spaced */, decode(text) { /* split, check 000 to 377, parseInt */ },};register(octal);encode("octal", "hi"); // "150 151"identify("150 151")[0]?.encoding; // "octal"Start with one command
One install gets you the library, the encodings CLI and the MCP server. Name an encoding, hand it text or bytes, done. Got a string and no idea what it is? That's what identify is for.
- PinPre-1.0, so pin exact versions.
- Not auditedFine for puzzles and tooling. Not for your savings.
- OfflineNothing to fetch, no key to sign up for, nothing to configure.
First call
$ pnpm add @agntn/encodingsimport { base58check, decode, encode, identify } from "@agntn/encodings";encode("base64", "gm"); // "Z20="base58check.decode("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"); // 21 bytes, version 0x00decode("bech32", "bc1qw508…").details; // { prefix: "bc", witnessVersion: 0 }identify("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa")[0].encoding; // "base58check"