@metacapsin/tooltrim
v0.1.0
Published
Strip the noise out of tool/test/build output before it hits an LLM. ANSI, npm chatter, deep stack frames, repeated lines and passing tests — gone. Pipe it: `npm test 2>&1 | tooltrim`.
Maintainers
Readme
tooltrim
Strip the noise out of tool/test/build output before it hits an LLM.
Agentic coding loops waste enormous numbers of tokens feeding raw command output back into the model — ANSI color codes, npm install chatter, download progress bars, hundreds of passing-test lines, and stack traces that are 90% node_modules frames. tooltrim compacts all of it, keeping the part that actually matters: the failures, the errors, and the one stack frame in your code.
Zero dependencies. Works as a library or a CLI you pipe into.
npm install @metacapsin/tooltrimCLI
npm test 2>&1 | tooltrim # feed compacted output to your eyes or an agent
npm run build 2>&1 | tooltrim -q # quiet: no savings summary
tooltrim < build.log # from a fileReal example — 19 lines of jest output in, 8 lines out:
⟪4 passing tests hidden⟫
resolving deps... done
✗ payments › charges card
AssertionError: expected 200 to be 402
at Object.<anonymous> (/app/src/payments.test.ts:42:18)
⟪… 3 stack frames in node_modules/node internals⟫
deprecation warning ⟪×3⟫tooltrim: 177 → 60 tokens (−66%), 19 → 8 linesTrimmed text goes to stdout; the savings summary goes to stderr, so piping stays clean.
CLI options
--no-ansi keep ANSI escape codes
--no-npm keep npm/pnpm/yarn install chatter
--no-tests keep individual passing-test lines
--no-stack keep full node_modules stack frames
--no-dedupe keep repeated consecutive lines
--no-blank keep blank-line runs
--max-lines <n> elide the middle if output exceeds n lines
--keep-head <n> lines kept from the start when truncating (default 60)
--keep-tail <n> lines kept from the end when truncating (default 60)
--json emit { text, stats } as JSON
--quiet, -q no savings summary on stderrLibrary
import { trim } from "@metacapsin/tooltrim";
const { text, stats } = trim(rawOutput);
// text -> compacted string
// stats -> { before, after, savedChars, savedTokens, savedLines, savedRatio }Perfect for wrapping a tool call in an agent before returning the result to the model:
const raw = await runShell("npm test");
return trim(raw, { maxLines: 400 }).text;What it does (and how to turn each off)
| Rule | Removes | Toggle |
| --- | --- | --- |
| stripAnsi | color codes, cursor moves | ansi: false |
| stripCarriageReturns | progress bars / spinners (keeps final state) | carriageReturns: false |
| stripNpmNoise | npm/pnpm/yarn install + funding + audit chatter | npmNoise: false |
| collapsePassingTests | runs of passing-test lines → ⟪N passing tests hidden⟫ | collapsePassingTests: false |
| foldStackTraces | consecutive node_modules / node-internal frames | foldStackTraces: false |
| dedupeLines | repeated identical lines → line ⟪×N⟫ | dedupeLines: false |
| collapseBlankLines | blank-line runs, trailing whitespace | collapseBlankLines: false |
| truncateMiddle | the middle of very long output (off unless maxLines set) | — |
Failures are never hidden: passing-test collapsing only matches positive markers (✓, PASS, PASSED, TAP ok) and bails on any line that also looks like a failure.
Custom pipeline
Every rule is an exported (text: string) => string you can compose yourself:
import { trim, stripAnsi, foldStackTraces, type Rule } from "@metacapsin/tooltrim";
const redactSecrets: Rule = (t) => t.replace(/sk-[A-Za-z0-9]+/g, "sk-***");
trim(raw, { rules: [stripAnsi, redactSecrets, foldStackTraces] });When rules is provided, the boolean toggles are ignored — you have full control of order.
Prove the savings with tokenlens
@metacapsin/tooltrim/tokenlens records the compacted tool output into a tokenlens
profiler session and tracks how much it saved — so you can show the reduction
next to your full token breakdown. tokenlens is an optional peer dependency;
the integration is structurally typed, so tooltrim has no hard dependency on it.
import { TokenLens } from "@metacapsin/tokenlens";
import { TrimReporter } from "@metacapsin/tooltrim/tokenlens";
const lens = new TokenLens();
const trimmer = new TrimReporter(lens);
// send the returned (compacted) text to the model; the lens records it
const output = trimmer.tool("npm test", rawTestOutput);
console.log(lens.format()); // where tokens went (already reduced)
console.log(trimmer.format()); // tooltrim saved 534 tokens across 2 tool calls (−84%, 634 → 100)Because the trimmed text is recorded (not just a count), tokenlens redundancy
detection still works — so the profiler can reveal the next bottleneck (e.g. a
file re-sent unchanged every turn) after tooltrim has handled the tool-output
noise. There's also a one-shot recordTrimmed(lens, label, raw, options?) if you
don't need the running tally.
Notes
- Token counts are a fast estimate (~chars/4), meant for reporting how much was trimmed, not billing.
- On tiny inputs the collapse markers can be larger than what they replace (negative savings). tooltrim is built for the large, noisy output that dominates agent context — that's where it pays off.
License
MIT
