compression with a quality contract

Shell output shaped at the source

The proxy digest folds a tool result after the agent has read it, and an agent that wants what was folded runs the command again. distil sh works one step earlier: it runs the command, applies one small deterministic filter chosen by what the command is, and prints the result. The compact form is the only one that ever enters the context. Opt-in; design and boundaries in ADR 0026.

$ distil sh -- python -m pytest -v tests/   # run one command shaped
$ distil hook install --shell              # Claude Code: rewrite Bash test runs to distil sh
$ distil hook uninstall --shell
$ distil hook --stats                       # receipts, by filter (sh:pytest, sh:git-status, …)

What it does to the output

FAILED tests/test_m.py::test_bad - AssertionError: boom
=================== 1 failed, 31 passed in 0.02s ===================
[distil sh sh-v1: 31 passing-test lines elided; failures, errors and the summary are verbatim above. Full output: `distil expand 24d14dad`]

The full output is written to distil's encrypted restore store and read back byte-exact before that line is printed; if it cannot be, you get the lossless form. distil expand <handle> | grep … recovers a slice.

Which commands

FilterCommandsTier
git-statusgit statuslossless
pytestpytest, py.test, python -m pytestelide
unittestpython -m unittest, Django runtests.pyelide
cargo-test · go-testcargo test · go testelide
js-testnpm|yarn|pnpm test, jest, vitest, npx jest|vitestelide

Never rewritten: search and listing (grep, rg, find, ls), git diff/log/show, file reads. Search output is the agent's map of the code; in 1.56.3, digesting it cost extra steps on SWE-bench, so it stays verbatim. Any other command run through distil sh is executed untouched.

Subscriptions

The same rule as the post-tool hook: on a Claude Pro/Max login only the lossless tier runs, unless you install with --digest (distil hook install --shell --digest) or run distil sh --digest -- …. On a metered API key the elide tier is on. Installing the rewrite is itself an explicit command; nothing installs it for you.

Fail-open, and your permissions

What it is worth, measured offline

On real tool output from synthetic projects (tests/fixtures/shell/), the lossless tier removes 15.9% of the tokens and the elide tier 61.3%. On the commands a SWE-bench Lite agent actually ran (300 tasks, 1,390 bash calls), only 27 calls match and 0.06% of bash-output tokens go: that workload is mostly grep and sed -n, which stay verbatim. So expect it to matter where agents run test suites, not on SWE-bench. It is opt-in until an outcome run shows it is non-inferior; the distil-sh arm of the SWE-bench harness exists to run that comparison. Numbers: benchmarks/results/2026-10-05/shell_replay*.json, regenerated by benchmarks/shell_replay.py.

Claude Code only for the automatic rewrite: Cursor's pre-shell hook can allow or deny but not rewrite, and Gemini CLI's and Codex CLI's were not verified to rewrite input. Any agent can be told to call distil sh -- itself.