Output Compression
AI agents dump raw command output into the context window — build logs, test suites, stack traces, progress bars. The vast majority of this output is noise the agent doesn’t need.
Warden’s truncation filter runs on the output of the commands it recognises as verbose:
- Preserves: errors, warnings, the final result, working-set file paths
- Removes: progress bars, passing tests, redundant log lines, npm install output
- Compresses: stack traces to relevant frames, build logs to error summary
How much that saves depends on the command. A clean build log is almost entirely noise; a failing one is almost entirely signal, and compression leaves it nearly untouched.
Which Commands Get Filtered
Compression is not applied to every tool output — only to commands known to be noisy, and only when the output exceeds the filter’s line budget. The list covers cargo build|check|clippy|test, dotnet build|test|publish|restore|pack, npm/pnpm/yarn/pip/bundle installs, test runners (pytest, vitest, jest, go test, dotnet test), linters (eslint, biome, ruff, mypy, tsc), git log|diff, docker build|logs|ps|images, docker compose up|logs, kubectl, terraform plan|apply, go build|vet, mvn, sbt, gradle, make, cmake, aws/gcloud/az, ansible, file listings (ls, eza, tree, fd, find), and knip|madge|depcheck.
Every filter keeps errors, warnings, and the final result line — a failing build loses its progress noise, never its failures. Short output is passed through untouched: a filter only engages past its line budget, so a clean ten-line build reaches the model in full.
The Problem in Detail
Consider what happens without compression. The agent runs dotnet build on a solution with a type error. The raw output is hundreds of lines: restore output, per-project build lines, warnings in unrelated files, and then the one error the agent needs. All of it goes into the context window. Multiply that by every build attempt in a debugging session and a large share of the context budget has gone to build noise.
The same applies to:
npm install— 200+ lines of dependency resolution, tree printout, audit warnings. The agent needs to know if it succeeded and whether there were errors. That’s 2-3 lines.- Test suites — A 500-test suite produces 500 lines of passing test names. The agent only needs the 3 that failed.
git log— Fifty commits of history when the agent asked for the last change.ls -laon node_modules — Thousands of entries when the agent wanted to check if a package exists.
Before and After Examples
The transcripts below show the shape of a filtered result. What you actually save depends on the command.
Build log compression (dotnet build, build mode):
Before — restore output, one line per project, then the error:
Determining projects to restore...
Restored /src/Api/Api.csproj (in 412 ms)
... (dozens more restore and project lines)
Core -> /src/Core/bin/Debug/net10.0/Core.dll
/src/Api/Handlers/Login.cs(42,20): error CS0029: Cannot implicitly convert type 'string' to 'int'
After — the filter writes a header, then the lines it kept:
--- BUILD OUTPUT (filtered: 203 lines -> 6 kept, errors + warnings) ---
/src/Api/Handlers/Login.cs(42,20): error CS0029: Cannot implicitly convert type 'string' to 'int'
Build FAILED.
Test suite compression (npm test, test mode):
Before (raw output, ~300 lines):
PASS src/utils/format.test.ts (0.8s)
PASS src/utils/parse.test.ts (0.4s)
... (95 more passing suites)
FAIL src/handlers/auth.test.ts (1.2s)
● login() › should reject expired tokens
Expected: 401
Received: 200
After:
--- TEST OUTPUT (filtered: 312 lines -> 6 kept, failures + summary) ---
FAIL src/handlers/auth.test.ts (1.2s)
● login() › should reject expired tokens
Expected: 401
Received: 200
Test Suites: 1 failed, 97 passed, 98 total
What’s Preserved vs Removed
| Preserved | Removed |
|---|---|
| Error messages and stack traces | Progress bars and spinners |
| Warning lines | Passing test names |
| Final summary/status lines | Dependency compilation output |
| File paths in the working set | Redundant blank lines |
| Exit codes and failure indicators | npm audit informational output |
| Build error locations (file:line) | Download progress percentages |
Command Filters
Warden uses command-specific filters to apply the right compression strategy. When it sees cargo build, it uses the build filter. When it sees jest or vitest, it uses the test filter. When it sees npm install, it uses the install filter.
Each filter has a strategy:
| Strategy | Behavior |
|---|---|
strip_matching | Remove lines that match a pattern (e.g., strip progress bars) |
keep_matching | Keep only lines that match a pattern (e.g., keep only errors) |
dedup | Remove duplicate consecutive lines |
head_tail | Keep the first N and last N lines, drop the middle |
passthrough | No compression (for commands where full output matters) |
Built-in Filter Coverage
Warden ships with compiled filters for common tools:
| Command | Strategy |
|---|---|
npm install / pnpm install / yarn install | Strip progress bars, keep warnings + errors |
pytest / vitest / jest | Strip passing test names, keep failures + summary |
git log / git diff | Truncate to relevant output |
docker / kubectl | Keep status and error lines |
A full test suite output with a few failures compresses down to the failures and the summary line. The ratio depends entirely on the command and how noisy its output was.
Filters are TOML-extensible: define custom filters in ~/.warden/rules.toml or .warden/rules.toml using any of the five strategies above. Custom filters merge with the compiled defaults.
Compression Tightens As The Session Runs
How much output survives depends on where the session is. Early on, more gets through; as context fills, the filters get stricter.
Late-session context is the expensive kind — you’re closer to the context limit, and every token matters more. The agent is also more likely to be running repetitive commands (rebuild, re-test) where full output adds no new information.
Custom Filters
You can define custom command filters in ~/.warden/rules.toml or .warden/rules.toml:
[[command_filters]]
match = "my-custom-build-tool"
strategy = "keep_matching"
keep_patterns = ["error", "warning", "FAIL"]
strip_patterns = ["^\\s*ok\\s"]
max_lines = 40
Custom filters are merged with the compiled defaults. They’re useful for project-specific build tools, test runners, or deployment scripts that produce verbose output your agent doesn’t need.