Guide

CLI

The ciphers command, seven subcommands, and the flags each cipher reads.

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.

CommandDescription
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 ciphersList the registered ciphers, -v adds the options
ciphers info <cipher>One cipher's family, options and keyspace
ciphers mcpRun 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.

FlagAliasCiphers
--shift <n>-scaesar
--key <word>-kvigenere, alberti, playfair, polybius, columnar, adfgvx, bifid
--rails <n>-rrail-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.

@agntn/ciphers·MIT license· Classical ciphers, for lessons and puzzles. Not for protecting anything, ever.