CLI
Run it
pnpm add -g @agntn/ciphers
ciphers caesar "ATTACK AT DAWN" --shift 3
# DWWDFN DW GDZQ
First argument not a subcommand? Then it's a cipher name and the CLI encodes. ciphers caesar ... and ciphers encode caesar ... are the same call, because typing encode every time gets old fast.
| Command | Description |
|---|---|
ciphers encode <cipher> <text> | Encode with a cipher |
ciphers decode <cipher> <text> | Decode with a cipher |
ciphers brute <text> | All 25 Caesar shifts |
ciphers frequency <text> | Letter histogram and index of coincidence |
ciphers ciphers | List the registered ciphers, -v adds the options |
ciphers info <cipher> | One cipher's family, options and keyspace |
ciphers mcp | Run the MCP server over stdio |
Examples
ciphers encode caesar "ATTACK AT DAWN" --shift 3 # DWWDFN DW GDZQ
ciphers decode atbash "ZGGZXP ZG WZDM" # ATTACK AT DAWN
ciphers encode vigenere "ATTACK AT DAWN" --key LEMON # LXFOPV EF RNHR
ciphers encode alberti "ATTACK AT DAWN" --key ALBERTI --period 4
ciphers encode affine "AFFINE CIPHER" --a 5 --b 8 # IHHWVC SWFRCP
ciphers encode rail-fence "WEAREDISCOVEREDRUNATONCE" --rails 3
ciphers encode playfair "HIDE THE GOLD" --key "PLAYFAIR EXAMPLE"
ciphers encode columnar "ATTACK AT DAWN" --key ZEBRA
ciphers encode bifid "FLEE AT ONCE" --key BICONDITIONAL --period 5
ciphers encode enigma "ATTACK AT DAWN" --positions MCK --rings BDF --plugboard "AV BS CG"
ciphers encode morse "SOS" # ... --- ...
ciphers encode tap-code "HELP" # 2 3 1 5 3 1 3 5
ciphers brute "KHOOR" # shift=3 → HELLO
ciphers frequency "DWWDFN DW GDZQ" --lang en
ciphers ciphers -v
ciphers info enigma
Flags
encode and decode read the same flags. A flag the cipher doesn't use is ignored, no complaint.
| Flag | Alias | Ciphers |
|---|---|---|
--shift <n> | -s | caesar |
--key <word> | -k | vigenere, alberti, playfair, polybius, columnar, adfgvx, bifid |
--rails <n> | -r | rail-fence |
--period <n> | alberti, bifid | |
--a <n>, --b <n> | affine | |
--positions <ABC> | enigma | |
--rings <ABC> | enigma | |
--plugboard "AB CD" | enigma |
frequency takes --lang en or --lang pl (-l).
The two library flags preserveCase and stripNonAlpha are not on the CLI. Quote the text and the shell keeps its case. When a puzzle wants a block, tr -cd A-Z does it in a pipe.
Exit codes and output
The transformed text goes to stdout, one line, nothing else. So it composes:
ciphers rot13 "$(ciphers atbash "HELLO")"
A CipherError - unknown cipher, missing key, shift out of range - prints its message to stderr and exits 1. No stack trace. Anything else is a bug in the library and still gets one, on purpose.