szr
is a Go-native CLI proxy that reduces noisy terminal output before it reaches an LLM context.
It keeps the useful signal, preserves the wrapped command's exit code, and helps you spend fewer tokens on logs, diffs, and test output.
- wraps the commands you already run
- rewrites supported tools into more compact machine-friendly output when possible
- summarizes noisy output without hiding the important anchors
- records local history so you can inspect token savings over time
Fidelity is a runtime guarantee, not a promise. A built-in retention verifier checks every render against the raw output — error lines, file:line
anchors, diagnostic codes, failing test names — and repairs anything a filter dropped by appending the missing detail. Failing commands can never render content-free, explicit flags you pass are never overridden, and exit codes always match the wrapped command.
Compression is never worse than raw. The finished display — retention repairs and artifact pointers included — never costs more tokens than relaying the raw output; when it would, szr emits the raw output instead. This holds for failure renders too: failure detail expansion stays within raw size. (Ultra-compact mode opts out — there the reshaped display is the point.) Profiles that read a single stream still surface the other stream's message when theirs is empty, so kubectl's No resources found
on stderr renders as a compact line instead of a raw fallback.
Re-runs cost almost nothing. Agents run git status
, git diff
, and test suites over and over. When output is byte-identical to a recent run, szr emits a two-line reference instead (unchanged from previous run (39s ago, x3 identical) [ref: …]
) — and szr expand <ref>
recovers the original byte-exact, on demand. The store is machine-level, so concurrent agents share it automatically: what one agent already saw, another can reference.
Edit-test loops render as deltas. When a rerun's outputchangedinstead of repeating, szr can emit a compact change digest —since last run (2m ago): +3 -1 lines
plus the changed lines themselves — but only when that is strictly cheaper than the normal summary, and never at the cost of a critical line: a newly-failing test always appears in the digest. The baseline stays oneszr expand <ref>
away.Agent fleets get their own scope. ExportSZR_SESSION=<id>
before launching parallel agents and the whole fleet shares one dedup/delta scope: what one agent rendered, its siblings reference. Runs without the variable stay in the machine scope and never cross-match scoped sessions;szr expand
resolves refs from any scope.
Anomalies are the payload. List and table summaries always keep the rows that differ — the one stopped instance among 800 running, the past_due
row in a result set — plus exact counts. Uniform JSON arrays render as a compact table that halves the token cost of list-shaped API responses at equal information.
Everything is recoverable. Whatever a summary omits is preserved in a local artifact with an exact pointer — compression never costs you the ability to look at the full output.
Install the CLI with Go:
go install github.com/devr-tools/szr/cmd/szr@latest
szr self doctor
Or build from a local checkout:
make build
./bin/szr self install
szr self doctor
Homebrew install via tap:
brew install devr-tools/tap/szr
szr self doctor
npm (installs a prebuilt binary, no Go toolchain required):
npm install -g @devr-tools/szr
szr self doctor
pip (installs a prebuilt binary per platform):
pip install szr
szr self doctor
Run your normal commands through szr
:
szr git status
szr git diff
szr go test ./...
szr find . --name "*.py"
Transparent wrapper prefixes — env KEY=VAL
, env -u NAME
, command
, nice [-n N]
, bare time
, and leading VAR=value
assignments — route to the inner command's profile, so szr env -u GOROOT go test ./...
compresses like szr go test ./...
. Prefixes stack, work inside sh -c "..."
strings, and the wrapper words themselves always execute verbatim. A bare env
with no wrapped command is a command of its own (the env-print
profile compacts its dump and redacts secret-looking values).
AI bootstrap targets:
| Tool | Install command | Uninstall command | Description |
|---|---|---|---|
| Codex | szr install codex |
||
szr uninstall codex |
|||
Writes ~/.codex/szr.md (or $CODEX_HOME/szr.md ) and patches the repo AGENTS.md to reference it. |
|||
| Claude Code | szr install claude-code |
||
szr uninstall claude-code |
|||
Installs ~/.claude/szr.md , a Claude hook script, and a settings.json hook registration. |
|||
| Cursor | szr install cursor |
||
szr uninstall cursor |
|||
Installs ~/.cursor/hooks.json plus a preToolUse hook script under ~/.cursor/hooks/ . |
|||
| Gemini | szr install gemini |
||
szr uninstall gemini |
|||
Installs ~/.gemini/settings.json BeforeTool registration plus a hook script under ~/.gemini/hooks/ . |
External agents, hooks, and plugins can call szr rewrite --json
to reuse the same shell-routing policy that powers the built-in Claude, Cursor, and Gemini integrations.
Example:
szr rewrite --json --command 'git diff HEAD~1..HEAD --stat | tail -30'
Example response:
{
"command": "git diff HEAD~1..HEAD --stat | tail -30",
"rewrite": "szr proxy git diff HEAD~1..HEAD --stat | tail -30",
"hint": "szr git diff ... --stat or szr proxy git diff ... -- path/to/file | head -200",
"reason": "wrap noisy producer inside shell pipeline",
"auto_rewrite": true,
"wrap_mode": "proxy",
"producer_only": true,
"already_routed": false
}
Use this surface when you want to:
- apply the same routing logic from custom Codex tooling or future plugins
- distinguish between safe auto-rewrites and hint-only guidance
- avoid re-encoding
git diff
,grep
,find
, and pipeline policy in multiple places
Drop a JSON spec into the filters/
directory next to config.json
and szr loads it as an extra profile — a match
section routes commands, and the same declarative reducer keys the builtins use (keep_patterns
, strip_patterns
, head
, tail
, dedup_consecutive
, …) shape the output. Project-local specs in .szr/filters/
load too, once advanced.project_filters
is enabled via szr settings
(off by default). Name collisions with project rules, builtins, or earlier user filters are skipped with a warning, never silently shadowed. szr profiles
marks loaded specs with source: user
or source: project
.
See docs/FILTERS.md for the spec format and a worked example.
szr spread
summarizes recorded savings; three additions make the numbers actionable:
appends an estimated-cost section: dollars avoided at a USD-per-million-input-tokens rate, raw versus emitted output cost, and aszr spread --cost
≈ N× a 200k-token context
anchor. The rate resolves from--rate <usd-per-mtok>
first, then thecost_rate_per_mtok
config key, then the default3.00
; passing--rate
implies--cost
. With--json
, the figures appear as acost
object.szr gain
accepts the same flags. -
scans local AI-agent session transcripts (szr discover
~/.claude/projects/
) for shell commands that ranwithoutszr, routes each through szr's own profile matching, and estimates the missed token savings using your own per-profile history ratios (60% fallback for profiles without enough history). Read-only and local-only: transcripts are never modified or transmitted. By default it covers the current project's transcripts from the last 30 days;--all
scans every project,--since <days>
widens or narrows the window,--top <n>
sizes the command table (default 15), and--json
emits the full report. -
joins the two sides: per agent session it reports the model-billed tokens recorded in the transcripts (fresh input, cache reads, output — exact, as recorded by the agent runtime) next to szr's estimated emitted and avoided tokens for that session, including szr's share of fresh input and how much larger fresh input would have been without szr, plus a per-subagent breakdown (anszr usage
agents
column, and a per-agent table when--session
matches one session). Records are correlated by session scope when present (SZR_SESSION
), otherwise by directory and session time window; cache reads are always excluded from the derived percentages. On a terminal, an interactive picker lets you drill into any listed session's agents (--no-input
disables it). Flags:--all
,--since <days>
(default 7),--session <id-prefix>
,--json
,--no-input
. -
streams local, sanitized execution events for agent or IDE integrations. Events contain reducer and token/latency measurements only—never commands, paths, rendered output, tee artifacts, or transcript content. Addszr watch --jsonl
--once
for a snapshot instead of following the stream. Seethe integration guidefor the stable event contract and a minimal live-results consumer. -
Optional diagnostics export can send the same allowlisted event schema to an HTTPS gateway. It is disabled by default; when enabled, szr queues events in a bounded, owner-only local outbox, retries them in background batches, and makes one final bounded delivery attempt on command exit. Export failures never change the wrapped command's result. Configure an explicit endpoint inconfig.json
:
{
"diagnostics": {
"enabled": true,
"endpoint": "https://gateway.example/v1/events",
"max_outbox_mb": 8
}
}
Gateway requests are JSON objects with
version
and anevents
array. Events never include command text, paths, output, tee artifacts, or transcript content. A gateway may emit aprovider_usage_aggregate
with only opaque gateway correlation and aggregate szr/provider token counters; it must not contain agent/provider session IDs, prompts, transcripts, model names, or account identifiers. -
inspects local event and pending-export storage without making a network request, including exporter endpoint host, drops, last success/failure, and next retry.szr diagnostics status [--json]
is an explicit, five-second-bounded export attempt; it is never run on a wrapped-command path.szr diagnostics flush
explicitly removes local event, outbox, and exporter-status stores.szr diagnostics purge --yes
- stdin pipe mode for filtering output already in flight
- broader reducer coverage and better fallback handling for noisy real-world commands
| Command | Description |
|---|---|
szr git status |
|
Run common Git commands through szr with reduced output. |
|
szr go test ./... |
|
| Compress noisy test output while preserving failures and anchors. | |
szr find <path> --name "*.py" |
|
| Find files or directories with repo-noise suppression and a bounded match summary. | |
szr grep <pattern> <path> |
|
| Group search matches by file via ripgrep-backed summaries with conservative repo-noise excludes. | |
szr run /usr/bin/grep ... |
|
Preserve exact grep semantics while still routing output through szr . |
|
szr rewrite --json --command '<cmd>' |
|
| Return the shared shell-routing decision for external agents and integrations. | |
szr spread |
|
| Show token savings, usage patterns, hotspot summaries, and per-profile fallback and empty-result rates. | |
szr spread --history |
|
| Inspect savings history across recent commands. | |
szr spread --cost [--rate <usd-per-mtok>] |
|
| Append estimated dollar figures and a 200k-context anchor to the savings summary. | |
| `szr discover [--all | --since <n> |
| Scan local agent transcripts read-only for commands that ran without szr and estimate the missed savings. | |
| `szr usage [--all | --since <n> |
| Compare model-billed tokens per agent session and subagent against szr-side emitted and avoided estimates. | |
szr watch --jsonl [--once] |
|
| Stream sanitized local execution diagnostics as JSON Lines. | |
szr diagnostics status [--json] |
|
| Inspect local diagnostics event and outbox health without network access. | |
szr diagnostics flush |
|
| Explicitly attempt one bounded upload of the diagnostics outbox. | |
szr diagnostics purge --yes |
|
| Explicitly remove local diagnostics events and pending exports. | |
szr gateway hints-refresh |
|
| Fetch, verify, and atomically install signed gateway budget hints. | |
szr doctor [--json] |
|
| Check runtime diagnostics and local history health. | |
szr self doctor [--json] [--refresh] |
|
Check install state, PATH , config, cache, and version details; --refresh bypasses the release-check cache for a live lookup. |
|
szr settings |
|
| Open the interactive settings menu for update checks, auto update, and other local preferences. | |
szr expand <ref> |
|
| Recover the byte-exact original output behind a dedup or delta baseline reference. | |
SZR_SESSION=<id> szr <cmd...> |
|
| Scope dedup and delta references to one agent session; export it fleet-wide so parallel agents share a scope. | |
szr tee --latest |
|
| Inspect the latest preserved full-output artifact. | |
szr explain go test ./... |
|
| Show the matched profile, budget, and rewrite decisions for a command. | |
szr commands |
|
| Show the full command catalog for power users and agents. | |
szr profiles |
|
| List built-in and user-defined reducer profiles. |
Reasoning budget modes:
standard
: balanced for human readabilityagent
: tighter defaults for agent loopsaggressive
: smallest previews for spread-heavy workflows, including tersergit diff
summaries
- Interactive shells:
szr
can print update notices onstderr
when update checks are enabled. - Agent or non-interactive tool runs: inline update notices are suppressed to keep tool output stable.
- Hosts can poll
szr doctor --json
orszr self doctor --json
and render their own user-facing notification with the returnedupdate
object; add--refresh
to force a live release lookup instead of the cached one. - Opt-in auto update is available for recognized Homebrew or
go install
installs:
{
"update_check": {
"enabled": true,
"interval_hours": 24,
"auto_update": true
}
}
Full-output captures are tee'd into the local data directory so compressed renders stay recoverable. Retention is bounded by default:
- a single artifact is capped at 4 MiB; a larger capture keeps the head and tail of the stream around a truncation marker that records how many bytes were omitted
- the tee directory is pruned oldest-first past 200 files or 256 MiB total; the newest artifact always survives, and pruned files are dropped from the tee index so lookups never dangle
- orphaned in-progress captures are cleaned up after one hour
All three caps are adjustable via szr settings
(tee max file mb
, tee max dir files
, tee max dir mb
) or in the config file:
{
"tee_max_file_mb": 4,
"tee_max_dir_files": 200,
"tee_max_dir_mb": 256
}
Zero or negative values fall back to the defaults rather than meaning "unlimited".