Compress command output
Build logs, test runs, and compiler diagnostics are the other half of agent context bloat.
ctxctl exec runs a command and returns only the lines that matter: key error/warning lines with
their file:line locations, plus a head/tail summary, with everything else collapsed to one
marker line.
The default pipeline is already useful
Section titled “The default pipeline is already useful”With no flags, exec keeps lines matching error, warning, failed, panic, fatal
(case-insensitive), keeps diagnostic location lines (--> src/foo.rs:12:34, rustc/cargo style)
so kept errors retain context, and shows 5 head + 5 tail lines:
ctxctl exec "cargo build"$ cargo builderror[E0308]: mismatched types --> src/main.rs:12... [34 lines omitted]warning: unused variable: `x` --> src/server.rs:88 = note: 2 warnings emittedSaved ~70% (1,240 -> 372 tokens)Collapsing only kicks in past 20 output lines (the collapse threshold), so short commands pass through untouched. The wrapped command’s exit code passes through — 0 means success regardless of compression; on Unix, a signal-killed child yields exit code 128 + signal.
Choosing –keep patterns
Section titled “Choosing –keep patterns”--keep appends one extra regex (rg syntax) to the configured defaults — it does not replace
them:
# Test verdicts alongside errorsctxctl exec "cargo test" --keep 'FAILED|passed'
# Go builds: surface package-level failuresctxctl exec "go build ./..." --keep 'cannot|undefined'Pick patterns that match verdict lines, not noise:
- Good: status words (
FAILED,passed), your framework’s failure tags (E0308), assertion markers (AssertionError). - Risky: generic words like
test,run, or file names — they match most lines and defeat compression (see the warning below).
Tuning head/tail
Section titled “Tuning head/tail”The head preserves the command echo; the tail carries the final summary (“N tests passed”, “N warnings emitted”). Tune both per call:
ctxctl exec "cargo test" --head 10 --tail 15Or change the defaults project-wide in .ctxctl/config.toml:
[exec]keep = ["error", "warning", "failed", "panic", "fatal"]head_lines = 5tail_lines = 5collapse_threshold = 20Set collapse_threshold = 0 to always collapse when there is anything to fold; an empty
keep list (keep = []) disables mid-output retention entirely instead of keeping every line —
location-line keeps stay active either way.
Over-broad patterns get called out
Section titled “Over-broad patterns get called out”If folding ran but saved at most 10% — the signature of a --keep pattern that matches nearly
every line — ctxctl appends a deterministic warning: line at the end of the text output.
The output stays byte-stable; the warning is just part of the deterministic result. Treat it as
a hint to tighten the pattern, not an error. In JSON mode (--json) it appears as a top-level
warning field instead.
No shell inside exec
Section titled “No shell inside exec”exec splits commands shell-word style and runs them directly — there is no interactive shell,
so pipes, redirections, globs, and && chains do not work as-is. Wrap compound commands in
an explicit shell:
# Wrong: pipe would be split as plain argumentsctxctl exec "cargo build 2>&1 | tee build.log"
# Right: hand the whole string to a shellctxctl exec 'sh -c "cargo build 2>&1 | tee build.log"'This is the single most common first-day stumble — agents in particular tend to assume a full shell is present. If output looks like flag soup, this is why.
CI log workflow
Section titled “CI log workflow”Log triage is where exec shines because the input is unbounded but the interesting content is
tiny. A scripted-agent benchmark task analyzing a 1,914-line deterministic build log landed at
−84% task cost versus raw reads:
# Local: compress any command's output on the spotctxctl exec "npm run build" --keep 'error|warn'
# CI: re-run or replay the failing step through a shell so only key lines surfacectxctl exec "sh -c './ci.sh 2>&1 | tee ci.log'" --keep 'FAIL|error'ctxctl exec "sh -c 'grep -nE \"(error|failed)\" ci.log'"The simplest CI pattern is to run the failing step under exec and let the compressed transcript
go straight into the issue report or the agent’s context. Compression streams incrementally with
bounded memory, so gigabyte-scale logs are safe.
Scripting: JSON mode
Section titled “Scripting: JSON mode”When orchestrating from scripts or pipelines, add --json (alias of --format json) for the
machine contract: a fixed envelope and a stable schema version. In text mode errors go to stderr,
but in JSON mode the error envelope — {"error": {"code": <exit-code>, "message": "<text>"}} —
prints to stdout, so machine consumers always get exactly one parseable stream. Exit-code
semantics are unchanged: exec passes through the wrapped command’s exit code.
For reading source files with the same discipline, see Explore unfamiliar code; for exposing these commands to agents as tools, see Wire up coding agents. The full flag list lives in Commands.