Runs a shell command through an LLM and reduces the output to at most six words
README.md

mand #

mand runs a shell command (or reads piped input), sends the output through an LLM, and reduces it to at most six words. Information loss is explicit and accepted.

Named after the Dutch meme: one word, maximum conviction, minimum information. MAND.

mand and korter are two settings of that same idea — cap how much an AI says. mand is the meme's limit case, a hard cap of six words; korter keeps just enough structure to stay useful day to day: same aggression towards bloat, but steps instead of grunts.

What's in this repo #

Two things, one idea:

  • mand — this CLI (reduces output to ≤ 6 words) and an agent skill with the same rules for when there's no CLI in reach: skills/mand.
  • korter — the korter CLI (terse steps, ~120 words) plus the agent skill: mand's more talkative cousin — terse, action-first, no hard word cap. The daily driver: skills/korter.

Install and always-on setup for both: Agent skills.

Usage #

mand "df -h"                       # mand runs the command, summary on stdout
df -h | mand                       # or pipe the output in
mand "df -h" | zegff               # spoken (with zegff, if you have it)
mand --hint "failed units" "systemctl --failed"
korter "time npm ci"               # korter: terse numbered steps (~120 words)
mand --help                        # usage and flags
mand --version                     # mand 0.1.0

The output of the summarised command is stdout+stderr combined, truncated at 200 kB before summarising.

A command that prints nothing still gets a summary: mand casts its exit status into words — exit 0 becomes done, success; bash conventions get names (126 not executable, 127 command not found, 128+N the signal's word, e.g. 137 killed, 143 terminated); anything else stays failed, exit N — and summarises that:

mand's own exit status stays 0 when the summary succeeds; the command's status lives in the words only.

Real examples (openai/gpt-oss-120b via OpenRouter):

$ mand "df -h /"
Root filesystem 1.9 TB, 21 % used

$ mand --hint "how full is root" "df -h /"
Root filesystem is 21 percent full

Providers #

[generate] picks how the prompt is answered:

provider what it does needs
openai (default) OpenAI-compatible /chat/completions via go-openai model + API key in an env var
openrouter OpenRouter (same code path, base URL preset) model + OPENROUTER_API_KEY
ollama local Ollama (same code path, OpenAI-compatible /v1) model, Ollama running

The openai provider covers OpenAI itself plus anything compatible (OpenRouter, Groq, Typesafe, …) via base_url. The API key is read from an environment variable: OPENAI_API_KEY by default, OPENROUTER_API_KEY when the base URL is openrouter.ai, or whatever api_key_env names.

Configuration #

~/.config/mand/config.toml (override with MAND_CONFIG); a missing file means defaults (openai provider, api.openai.com — set a model and key):

[generate]
provider    = "openai"                      # openai | ollama
model       = "openai/gpt-oss-120b"
base_url    = "https://openrouter.ai/api/v1"
api_key_env = "OPENROUTER_API_KEY"
timeout     = "90s"

# ollama instead (local, no key):
# provider = "ollama"
# model    = "gpt-oss:20b"
# base_url = "http://127.0.0.1:11434/v1"    # default

korter reads the same [generate] schema from ~/.config/korter/config.toml, falling back to ~/.config/mand/config.toml when it has none of its own (KORTER_CONFIG overrides the path).

mand setup walks you through provider, model, base URL, and key. Known key environment variables are detected. A pasted key lands in ~/.config/mand/key.env (chmod 600). The wizard ends with a one-word probe call, and an existing config is kept as config.toml.bak.

Install #

```bash
go build -o ~/.local/bin/mand   ./cmd/mand
go build -o ~/.local/bin/korter ./cmd/korter
mand setup                        # provider, model, key + probe

The module path is deliberately plain mand: no remote go install, the binaries simply land in ~/.local/bin. One engine (*.go at the root), two thin mains under cmd/. Requires bash (the summarised command runs via bash -c).

Bench: the skills on a clean model #

The site charts use a fresh three-arm run (none, mand, korter) on OpenRouter deepseek-flash: PROVIDER=openrouter MODELS='~deepseek/deepseek-flash-latest' RUNS=2 bench/run.sh. The harness takes a PROVIDER override and retries empty replies (three attempts per run). Raw files: results/raw/~deepseek_*.json.

Best quotes from the logged benches (no tools, deepseek-v4.1-flash via ollama-cloud; mand data in bench/RESULTS.md, korter in bench/VARIANTS.md):

mand (≤ 6 words) vs unshaped baseline:

scenario none (default) mand
"How full is root?" — df says 1.9 TB, 21 % "21% of 1.9 TB ≈ 0.4 TB (~400 GB) used, leaving about 1.5 TB free." (41 w run1, 12 s; run2 rambles to 101 w) 21% full. (2 w) · 21% full. (2 w)
"Why did the deploy fail?" — registry token expired 20 min ago 164-223 w of cause-analysis Expired registry token blocked push. (5 w) · Expired registry auth token blocked push. (6 w)
"Tests fail: connection refused on localhost:5432" 271-345 w tool-disclaimer essays Start PostgreSQL before rerunning tests. (5 w) · Start the PostgreSQL service first. (5 w)

korter (shipped skill) vs unshaped baseline:

scenario none (default) korter
"node_modules huge, build 9 min, CI times out" 541-552 w tool-disclaimer preamble, then options 98 w: 1. Split the 9 minutes: install or build? du -sh node_modules && time npm ci → cache installs keyed on lockfile → dedupe → remote cache → separate typecheck. Closes: "node_modules size is rarely the cause; install caching plus build caching fixes CI timeouts far more than pruning does." (7 s)
"Just cloned this Go repo, get productive" run1 stalls at 16 w (<function=list_files> tool stub); run2 344 w of apology + prose 59-76 w: step 1 go version && head -1 go.mod, step 2 go mod download, step 3 go build ./..., step 4 go test ./..., step 5 grep -rl "func main" --include=*.go . (2-6 s)
"CI pipeline: push→lint→test→build→push→registry-watch→staging→smoke→prod. Where can it stall?" 415-416 w with assumption caveats 96-105 w: 5 stall points ranked, each one line, then the ASCII chain diagram (8-12 s)
"login→auth→DB→JWT→gateway→redis→backend. Where are the failure points?" 483-559 w prose-wrapped diagram 117-128 w: failure points ranked, then a compact flow diagram (9-12 s)

How tested: every quote comes from a logged run — bench/run.sh, bench/variants.sh (naked ollama-cloud API calls, no tools, skills, or extensions), system prompt = the skill rules, one JSON per run in results/raw/ (none + mand arms) and results/variants/ (korter arm and its base no-skill baseline, deepseek-v4.1-flash only). The mand table and the korter table's first two rows use the none arm (results/raw/deepseek-v4.1-flash.none.*); the diagram-scenario rows exist only in the variant bench, so their baseline is that bench's base arm (results/variants/base.*). Reproduce with RUNS=2 bench/run.sh and RUNS=2 bench/variants.sh. Full data with per-scenario medians, variant comparison (korter's b5esc prompt measures –61% words vs baseline), bench limitations, and the mand cap-miss notes: bench/RESULTS.md, bench/VARIANTS.md, bench/DIAGRAM.md.

Agent skills #

The idea ships as a skill too (skills/mand/SKILL.md).

The repo also carries the sibling skill korter (skills/korter/SKILL.md): mand's more talkative cousin — terse, action-first output with numbered steps, state restating and visible progress, instead of the hard six-word cap. Where mand is the extreme, korter is the daily driver.

Install both with

./install-skill.sh                             # ~/.agents/skills/{mand,korter}
./install-skill.sh ~/.pi/agent/skills          # or any runtime dir
./install-skill.sh --bin                       # build + install both binaries
./install-skill.sh --remove                    # uninstall both

Explicit invocation only: say /mand and every reply comes back in at most six words. Levels: /mand lite|mand|MAND|off. /korter keeps the reader action-first without the word cap; stays on until "stop korter".

Always-on (optional, both skills) #

Like korter's SessionStart hook: create the flag file, and every session starts with the full ruleset injected — no /mand needed.

mkdir -p ~/.claude && touch ~/.claude/.mand-always        # mand always-on
# korter upstream sets its own flag: ~/.claude/.korter-always

Register the mand hook in Claude Code settings.json:

{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command",
  "command": "/abs/path/to/mand/hooks/always-on.sh" } ] } ] } }

touch ~/.claude/.korter-always re-enables korter's own hook when its plugin is installed; delete either flag to turn always-on off for good.

License #

MIT — see LICENSE.

The bundled korter skill itself is a derived work: action-first rules from i-have-adhd (MIT), compression mechanics from caveman (Apache-2.0). Full credits: crooy/korter#credits.