# lowfat filters command output before it reaches an agent's context

> lowfat is a Rust CLI that strips noise out of command output and file content before an agent reads it, with a three level compression scheme, a plugin DSL, and a measured reduction table for commands like git diff, git log and docker ps. The project is explicit that its percentages bound the output slice rather than your total token bill.

**zdk/lowfat** — lowfat - slim your command output. strips noise, saves tokens.

- Repository: https://github.com/zdk/lowfat
- Stars: 582 · Forks: 17
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/zdk-lowfat

## The unit of saving is one command's output

lowfat is a lightweight CLI tool that reduces AI token costs by filtering CLI output and file content before it reaches your agent, and the README is careful about what that means. The reduction table is measured on the bundled samples under crates/lowfat-plugin/embedded, and the reproduction is a pipe through the filter binary with a sub and a level argument. The numbers are per command: git diff at minus 16 percent in lite, minus 38 percent in full and minus 96 percent in ultra, git log at minus 53, minus 80 and minus 91, git status at minus 62, minus 62 and minus 74, docker ps at minus 38, minus 38 and minus 85, docker images at minus 48, minus 58 and minus 86, and ls -la at minus 2, minus 75 and minus 87. The project then states the caveat three times over, that these percentages are the reduction of a single command's output and not your end-to-end agent token usage, that savings depend on how much of your context is command output and how lossy a level you pick, and that the table should be treated as a ceiling on the output slice rather than a promise on the total.

## What a filtered git status actually looks like

The before and after in the README make the mechanism concrete. The raw git status output includes the branch line, the up-to-date notice with origin, the two parenthetical hints about using git add and git restore, the modified and untracked file lists, and a closing line about no changes added to commit. The lowfat version keeps the branch line, the not-staged heading and the two modified files, and the untracked heading with its path. What disappears is the boilerplate: the hints that tell you how to fix the state, and the final reassurance that nothing is staged. The design assumption is that a human or an agent reading the output needs to know what changed, and the surrounding instructions are recoverable from the tool's own help. The filtering is per plugin and per sub-command, which is why the reproduction command names both a plugin and a sub, and it is why ls -la barely changes at lite while git diff changes a lot.

## Three integration paths: hooks, shell wrapper and direct prefix

You wire lowfat in one of three ways, and the README presents them as a choice. The first is a Claude Code hook, added to .claude/settings.json, with a PreToolUse hook on Bash that runs lowfat hook and a PostToolUse hook on Read that runs lowfat post-read. The PreToolUse hook rewrites Bash commands through the filters, and the PostToolUse hook compresses file content after a read, stripping comments, collapsing function bodies and summarizing lock files. The README notes that Anthropic recommends this filtering pattern, but via lowfat.

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "lowfat hook" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Read",
        "hooks": [{ "type": "command", "command": "lowfat post-read" }]
      }
    ]
  }
}
```

The second is shell integration, which auto-activates inside agent environments detected through CLAUDECODE=1 and CODEX_ENV, or you can set LOWFAT_ENABLE=1 to force it on any shell.

```sh
echo 'eval "$(lowfat shell-init zsh)"' >> ~/.zshrc   # or ~/.bashrc
```

The third is direct usage, where you prefix any command yourself.

```sh
lowfat git status
lowfat docker ps
lowfat ls -la
```

## The OpenCode plugin needs the right variant for the version

The OpenCode integration is a single command with no configuration editing.

```sh
lowfat opencode install   # v1.x → plugins/lowfat.ts, v2.x → plugins/lowfat-v2/index.js
```

What follows is the most useful warning in the README, because it describes a failure that looks like success. The install detects your OpenCode version through opencode --version and places the matching plugin shape, and the v2 variant is required because 2.0.x changed the plugin API, with the v1 shape loading but silently doing nothing there. After installing you restart OpenCode and commands are rewritten transparently before they run, and the uninstall command removes whichever variants are present. The same shell-prefix trick works for the Pi agent, where the setting is a single key in the agent settings file.

```json
{ "shellCommandPrefix": "eval \"$(lowfat shell-init zsh)\"; " }
```

## Compression levels, plugins and the audit trail

The everyday commands are grouped by intent, and the usage highlights in the README are a good map of the tool. The info command shows the status badge and active filters, with a per pipeline variant and a full resolved config flag. The stats command reports lifetime token savings and an audit mode listing recent plugin executions, and history ranks commands by potential savings, which is the number to look at first because it tells you where the noise actually is. The level command sets the aggressiveness, with a one-off override through the LOWFAT_LEVEL environment variable. Plugins are written with a scaffold command that creates a directory under your lowfat folder, and a doctor command checks plugins and pre-installs any Python dependencies. A filter can also be tested against a sample without installing it, which is the sane way to develop one.

```sh
# See what's configured and how loud each filter is being
lowfat info                       # status badge + active filters
lowfat info git                   # pipeline for `git`
lowfat info --config              # full resolved config

# See what lowfat has saved you
lowfat stats                      # lifetime token savings
lowfat stats --audit              # recent plugin executions
lowfat history                    # rank commands by potential savings

# Dial the aggressiveness
lowfat level ultra                # max compression
LOWFAT_LEVEL=lite lowfat git log  # one-off override
```

The README also points to three documents in docs/, an architecture description with a diagram of the CLI, Runner, Plugins and Builtins, a configuration reference covering the .lowfat file, environment variables, the pipeline DSL and the built-in processors, and a plugin reference covering the lf-filter language with its .lf plugin DSL, named rules, the JSON output guarantee, shell escape hatches, PEP 723 with uv and the AI agent prompt.

## post-read compresses files by type, and skips what it cannot help with

The file side of the tool is a separate command, lowfat post-read, which compresses content before it enters the context of the agent that read it. The rules are per content type. Source code in Rust, Python, Go, Elixir, JavaScript and TypeScript, Java, Ruby, C and C++ and shell has its comments stripped and its blanks normalized, and at the ultra level function bodies collapse to signatures. Markdown loses badges and HTML comments and has code blocks and tables truncated. HTML, Vue and Svelte lose style elements, script elements and class attributes, and at ultra become text extraction only. JSON and JSONC have large arrays truncated and deep nesting collapsed. Lock files such as Cargo.lock, package-lock.json and yarn.lock are replaced with a summary giving a package count and the top dependencies. Anything unrecognised gets a head and a tail with a line count. The compression level follows the LOWFAT_LEVEL variable with the lite, full and ultra values, and files where the savings would be under 10 percent pass through unchanged, which is a sensible way to avoid mangling a file for no benefit.

## Where lowfat is the wrong tool

Three limits worth naming. The first is that the tool filters output, and filtered output is not the same as correct output. An aggressive level that drops a diagnostic line, a warning or a row from a list changes what the agent believes it saw, and the project is honest that higher levels drop more, so the question to verify is whether your agent still has what it needs. The second is that the savings are bounded by the slice lowfat controls. If most of your context is file contents the agent writes, or reasoning, or a tool result that is not command output, the percentages in the table will not show up in your bill. The third is the operational one. This is a tool that rewrites commands before they run, and the way it does that is a filter pipeline with a plugin DSL, so a bug in a filter is a bug in what your agent executes. The project offers the mitigations you would hope for, with a JSON output guarantee, shell escape hatches and a plugin doctor, but the trust model is the same as any shell wrapper that changes command lines. An alternative worth naming is doing the trimming inside your agent's own tool definitions, where the same rules live next to the prompt that uses them, at the cost of losing the cross-agent reuse that a standalone binary gives you. The README lists its own alternatives, including rtk, context-mode, lean-ctx, tokf and tamp, which is a fair set of names to evaluate against.

## Conclusion

Adopt lowfat if your agent spends a large share of its context on command output and you want to reduce that slice without giving up the signal, since the built-in filters cover the noisy commands and the level can be tuned per command. Skip it if your workflow already trims output upstream, or if you are working in an environment where a rewritten command would be wrong, because the filters change what the tool actually sees. Before you enable it broadly, run lowfat history to find the commands with the most potential savings and test the level you pick, since the project's own table is a ceiling on the output slice and not a promise about your end-to-end token usage.

## FAQ

### How do I install lowfat?

With cargo install lowfat, or from the Homebrew tap with brew install zdk/tools/lowfat, and pre-built binaries are published on GitHub Releases. The tool is a single binary and requires no telemetry.

### How do I set up lowfat for Claude Code?

Add a PreToolUse hook on Bash that runs lowfat hook and a PostToolUse hook on Read that runs lowfat post-read to .claude/settings.json. The first rewrites Bash commands through the filters and the second compresses file content after a read.

### What are the lite, full and ultra levels in lowfat?

They are the compression levels, set with the level command or the LOWFAT_LEVEL environment variable, where higher levels drop more. The README notes that savings depend on how lossy the level you pick, and that files with under 10 percent savings pass through unchanged.

### How much does lowfat actually save on my token usage?

The published table measures the reduction of a single command's output on the bundled samples, with git diff at minus 16 to minus 96 percent depending on level and git log at minus 53 to minus 91 percent. The README is explicit that these are not end-to-end agent token savings and should be treated as a ceiling on the output slice.

## Sources

- [Issues](https://github.com/zdk/lowfat/issues)
- [License: Apache-2.0](https://github.com/zdk/lowfat/blob/main/LICENSE)
- [README](https://github.com/zdk/lowfat/blob/main/README.md)
- [Releases](https://github.com/zdk/lowfat/releases)
- [zdk/lowfat on GitHub](https://github.com/zdk/lowfat)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zdk-lowfat
