Agent-optimized output compressor for Python tooling.
Status: alpha. The pytest adapter is the only one so far.
Python tools write for humans: progress indicators, a full traceback per problem, colour codes, a summary table. When an AI agent runs one of those tools, it pays for all of it. A green run of a thousand tests tells the agent one thing ("everything passed") and charges thousands of tokens to say it.
Pymmary detects that a coding agent is running the tool and replaces that output with compact JSON. Outside an agent, nothing changes: no agent detected, no compression, byte-identical output for humans.
It is a decision of the project, not of the agent's environment. Add it as a dev dependency and any agent that clones the repo and runs your tools benefits, with no per-machine setup.
Each tool gets its own adapter, its own extra, and its own page. The payload speaks that tool's vocabulary rather than a normalized one, so the details live with the adapter:
| Tool | Install | Docs |
|---|---|---|
| pytest | pymmary[pytest] |
pytest adapter |
Planned: unittest.
- Automatic agent detection via environment variables, no configuration
- Strict no-op fallback: no agent, no change to output
- One shared envelope across adapters, with a payload in each tool's own vocabulary
- Zero runtime dependencies in the core; each adapter ships behind its own extra
- Hooks into the host tool's native extension points, no global monkey-patching
- Python 3.10+
Adapters add their own, listed on each adapter page.
pip install pymmaryWith an adapter:
pip install pymmary[pytest]Nothing to wire up after that. Adapters register themselves through the host tool's own plugin mechanism, so installing as a dev dependency is the whole setup.
Every adapter emits these four keys, so an agent recognizes any pymmary output at a glance:
| Key | Meaning |
|---|---|
tool |
Which tool produced this |
result |
"passed" / "failed", the one-word verdict |
duration |
Seconds, float, rounded to 3 decimals |
summary |
Counts, in the host tool's own outcome vocabulary |
Adapters add top-level keys where their tool has more to say. The pytest adapter adds exit_code and failures, for example, and a green suite of 1002 tests comes out as one line:
{"tool":"pytest","result":"passed","exit_code":0,"duration":0.32,"summary":{"collected":1002,"passed":1002}}Two rules hold across every adapter:
resultfollows the tool's exit code, never our own tally. A run that broke before it could report anything is never called a pass.summaryuses the tool's own words. pytest counts passed and xfailed, mypy counts errors and notes. Normalizing them would throw away the thing that makes the payload useful.
| Agent | Signal |
|---|---|
| Claude Code | CLAUDECODE set to any non-empty value |
| Cursor | CURSOR_TRACE_ID set to any non-empty value |
| Devin | TERM_PROGRAM=Devin exactly |
| Gemini CLI | any variable starting with GEMINI_CLI_ |
Anything else, plain shells and generic CI included, falls through and leaves output untouched. No TTY checks, no parent-process inspection, no network.
Two environment variables, no config file and no CLI flags:
| Variable | Effect |
|---|---|
PYMMARY_FORCE=1 |
Compress even when no agent is detected, useful to see what an agent sees |
PYMMARY_MAX_FAILURES=N |
How many problems to spell out, failures and warnings alike. Default 20; 0 keeps every one of them |
PYMMARY_CAPTURE=1 |
Include what a failing test printed and logged. Off by default, it is the most expensive thing pymmary can add |
The cap is about diminishing returns, not size: an agent facing 400 failures fixes a handful and runs again, so the rest cost context and buy nothing. summary always counts the whole run, and whatever was left out is declared in failures_omitted and warnings_omitted.
Tokens, not bytes, since tokens are what an agent pays for. On pytest output the saving runs from 1.6× to 28× depending on the shape of the run: best on large green suites, worst on suites with many failures, since failure bodies barely compress. The full table and the method are on the pytest adapter page.
Companion to pyssertive (assert phase) and pyrrange (arrange phase). Pymmary covers the report phase, for AI consumers.
Inspired by laravel/pao, the PHP original.
MIT