I ran a perfectly successful test suite and watched it dump 1,476 lines into my coding-agent session. Nothing was wrong. There was nothing to diagnose. The useful information was basically one bit: the tests passed.
That run, a real Tape test suite, produced 136,262 bytes across those 1,476 lines. All of it was correct output; almost none of it was necessary.
The outcome the agent actually needed to act on was simply:
✓ tests passed
So why are we giving coding agents terminal output designed for human eyes?
Two kinds of output
It’s tempting to file this under “tokens are expensive” and move on. That’s not quite the argument.
Terminal output from build and test tools tends to mix two different kinds of information.
First, there is information needed for the next decision:
- Did it build?
- Did the tests pass?
- If not, what failed?
- Where did it fail?
- What’s the likely cause?
Then there is output generated because a tool assumes a human is watching:
- Lifecycle banners
- Progress messages
- Successful plugin execution
- Repeated module headings
- Package-by-package confirmations
- Formatting intended to make a long terminal session readable
A developer watching a terminal skims past most of this without much cost. Human eyes are good at ignoring repetition.
A coding agent doesn’t get the same free visual filtering. Whatever lands in the session becomes context the system may have to retain, attend to, summarize, or eventually compact.
The goal here is not to minimize output, but to retain the minimum sufficient output for the next action.
The numbers
To test this, I built small wrappers in agent-scripts around a few common build and test tools: mvn-lite, npm-lite, and go-lite.
They collapse routine successful runs and keep failures diagnostic-oriented. When a supported run fails, complete raw output is retained separately.
Here’s what that looked like across a handful of real projects:
| Workflow | Normal output | Compact output | Reduction |
|---|---|---|---|
| Tape tests | 136,262 B / 1,476 lines | 12 B / 1 line | 99.99% |
| Scriptella Maven reactor | 66,812 B / 928 lines | 17 B / 1 line | 99.97% |
| Spring Maven build | 5,564 B / 70 lines | 16 B / 1 line | 99.71% |
| Apache Commons CLI Maven | 15,079 B / 203 lines | 17 B / 1 line | 99.89% |
| Vitest | 2,260 B / 43 lines | 25 B / 1 line | 98.89% |
| Jest | 2,491 B / 68 lines | 24 B / 1 line | 99.04% |
Give your coding agent quieter tools. Install mvn-lite, npm-lite, and go-lite from agent-scripts. The optional Agent Skill is installed separately and teaches supported agents when to use them.
The Tape result is the most extreme: 136,262 bytes across 1,476 lines became ✓ tests passed, a byte reduction of 99.99%.
The Maven example was almost as striking. A successful multi-module reactor build produced 928 lines and nearly 67 KB of output. Almost none of those 928 lines helped the agent decide what to do next. The important result was that the build passed.
I explored the Maven side in more detail in I Taught Maven to Be an Introvert, including how mvn-lite preserves exit status, extracts actionable failures, and retains complete raw logs.
These wrappers do not make Maven, npm, or Go faster. The underlying command still does the same work and takes whatever time it takes.
This is an interface optimization, not a build-performance optimization.
Success and failure are different problems
If a build succeeds exactly as expected, there is usually very little to reason about. A result like this may be enough:
✓ 153 tests passed
The agent can move on.
Failure is different. A useful failure result should tell the agent enough to decide what to inspect or change next. That means preserving things such as:
- The real process exit status
- The failing test, package, goal, or module
- Useful nearby diagnostics
- The location of the complete raw log
- A way to revert to ordinary full output
The rule I ended up with is simple: Success should be cheap. Failure should be informative.
The wrappers therefore treat failure as a separate path rather than simply applying the same aggressive compression.
Interestingly, compact failure output is not always smaller than the original. Some naturally short Vitest or Jest failures can become slightly larger after adding diagnostic framing and a pointer to the retained full log.
And that’s fine. If the objective were simply “minimize bytes,” that would be a failure. But the actual objective is to make the next action as obvious as possible, and sometimes a few extra bytes are exactly what that needs.
Successful doesn’t always mean uninteresting
There is an obvious limitation to this approach. Exit status is useful, but it is not a perfect definition of “nothing worth seeing.”
A build can succeed while printing a deprecation warning. A test suite can finish successfully after retrying a flaky test. A command can return zero while still printing something the developer would have wanted to notice.
The current wrappers don’t pretend to solve that generally. For some supported workflows, they trust the underlying command’s exit status. That means warnings from a successful run can be hidden.
This is a real tradeoff. The more aggressively a wrapper tries to classify every warning and unusual message, the closer it gets to becoming a full parser for Maven, npm, Vitest, Jest, Go, and every tool invoked underneath them.
The hard part is not truncating output. It is deciding what can safely be collapsed. My preference so far has been to keep the wrappers small and explicit about that limitation instead of inventing a generic warning detector that looks smarter than it is.
What happens to those 1,476 lines afterward?
Coding agents carry state across a session. Depending on the agent and harness, previous tool output may remain directly available, be summarized, compacted, truncated, or otherwise continue influencing later turns.
I cannot responsibly claim that 136 KB of output costs another 136 KB on every future turn. Different systems manage context differently, and I don’t have a clean cross-agent benchmark demonstrating that multiplier.
But the weaker claim is still something: once irrelevant output enters a coding session, it becomes context that the system has to somehow manage.
If 1,476 lines contain almost no information useful after a successful test run, keeping them out of the session in the first place seems better than relying on later compaction to clean them up.
Small wrappers, not replacement build systems
I put these tools into an open-source project called agent-scripts.
The main wrappers are:
mvn-litenpm-litego-lite
They are very specifically meant to be small. mvn-lite is not a replacement for Maven. npm-lite is not another Node build system. go-lite is not a new Go test runner.
They run the normal underlying tools and change the amount and shape of output the coding agent consumes. That is the whole idea.
Teaching agents the new contract
The wrappers only help if the coding agent knows they exist.
Command installation and skill installation are separate. First install the command-line tools and make them available on PATH.
Then add the optional lite-tools Agent Skill. It explicitly teaches supported agents to prefer mvn-lite, npm-lite, and go-lite for routine build and test workflows, while keeping full output available when needed:
npx skills add ejboy/agent-scripts --global --skill lite-tools
Maybe agents need different tool contracts
Most coding-agent environments today still look roughly like this:
developer tool → human-oriented stdout → coding agent
We inserted an AI into an interface that was designed for a person. That works surprisingly well, but it doesn’t mean the interface is ideal.
Humans and agents have different constraints:
- For humans: rich, progressive, visually scannable, and verbose when useful.
- For agents: bounded, predictable, decision-oriented, cheap on routine success, and detailed on failure.
That suggests developer tools may eventually benefit from different presentation contracts.
That doesn’t mean every compiler, test runner, and package manager needs an --ai flag. Thin wrappers may be enough. Structured output may be enough. Sometimes simply changing defaults for a known agent workflow may be enough.
But I think the question is worth asking more broadly:
What should a developer tool output when the consumer is no longer a human reading a terminal?
The wrappers are small. The Agent Skill is small. The point is the contract behind them: routine success should be cheap, failures should be informative, and agents should know when to use the quieter interface.
Developer tools designed for human terminals are not necessarily good interfaces for agents with context windows instead of eyes.
Give your coding agent quieter tools. Try the compact wrappers, inspect the source, or read the narrower Maven case study. If agent-scripts saves useful context in your workflow, star the project so others can find it.