Skip to main content

cartoon

Token-optimized output for any CLI. Prefix cartoon onto a command and its output becomes TOON — a compact structured format built for LLM agents. Same exit codes, same behavior, far fewer tokens: 43–89% less than a verbose test run in the benchmark (~70% is the rough average; against already-quiet flags like pytest -q the gain is small).

A cartoon is a compressed rendering of reality. So is this.

Why

Agents (Claude Code, Cursor, Codex, ...) read CLI output formatted for humans: banners, progress noise, hundreds of PASSED lines. You pay for every token. cartoon keeps what the agent needs — counts, failures, tracebacks — and drops the rest.

Install

uv tool install cartoon        # or: pipx install cartoon
npm install -g cartoon-wrap    # installs the `cartoon` binary
cargo install cartoon          # build from source
cargo binstall cartoon         # prebuilt binary via cargo-binstall
brew tap abhijitbansal/cartoon https://github.com/abhijitbansal/cartoon
brew install cartoon           # macOS / Linux Homebrew (this repo is the tap)
curl -fsSL https://raw.githubusercontent.com/abhijitbansal/cartoon/main/install.sh | sh

Prebuilt binaries cover Linux (x86_64, aarch64), macOS (x86_64, arm64) and Windows (x86_64). The Linux binaries are static (musl), so they run on any distro: old glibc, Alpine, python:* images. PyPI also ships an sdist, so pip builds from source (needs a Rust toolchain) where no wheel fits.

install.sh puts the binary in ~/.local/bin (override with CARTOON_INSTALL_DIR; pin a release with CARTOON_VERSION=0.7.0) after checking it against the release's SHA256SUMS. Release tarballs also carry build provenance: gh attestation verify cartoon-<target>.tar.gz -R abhijitbansal/cartoon.

The Homebrew formula lives in this repo (Formula/cartoon.rb) and installs the release tarballs; the tap needs its URL because the repo isn't named homebrew-cartoon. Upgrade with brew upgrade cartoon.

The Claude Code plugin's hooks need the binary. Without it, the plugin tells the agent once per version (SessionStart) how to install it, and it hints when the binary is older than the plugin.

For agents (Claude Code, Codex, Copilot, Cursor, …)

Teach your agent to use cartoon automatically — and to install it when missing — with the skills shipped in this repo:

# Claude Code (plugin)
/plugin marketplace add abhijitbansal/cartoon
/plugin install cartoon@cartoon
# Everything else (skills.sh CLI auto-detects 40+ agents)
npx skills add abhijitbansal/cartoon

Copy-paste blocks for AGENTS.md / copilot-instructions.md and the full integration matrix: docs/agents.md.

Auto-wrap hook (Claude Code, Copilot CLI, VS Code Copilot Chat)

Instructions only ask the agent to wrap; a PreToolUse hook guarantees it. The hook rewrites noisy shell commands to run under cartoon automatically — no skill recall needed. One cartoon hook rewrite serves every supported agent; install it where each one looks:

cartoon hook install              # Claude Code        → ~/.claude/settings.json
cartoon hook install --vscode     # VS Code Copilot Chat (same Claude-format file)
cartoon hook install --copilot    # Copilot CLI        → ~/.copilot/hooks/cartoon.json
cartoon hook install --copilot --project   # repo-shared .github/hooks/cartoon.json
cartoon hook status               # where it's active, per agent
cartoon hook uninstall [--copilot | --vscode] [--project]

Per agent:

  • Claude Code and Copilot CLI (≥ v1.0.24) support transparent rewrite (updatedInput): the wrapped command runs in place.
  • VS Code Copilot Chat reads the same Claude-format ~/.claude/settings.json (its hooks are Preview), so --vscode installs there — one entry covers both it and Claude Code. Chat has no rewrite field, so the hook denies the raw command with a "re-run wrapped" suggestion — still deterministic, just one extra round-trip. (Plain cartoon hook install already covers Chat too; --vscode is the explicit, VS-Code-labelled form.)
  • The repo-shared --copilot --project file (.github/hooks/cartoon.json) is written in Copilot-CLI format (camelCase preToolUse) for the Copilot CLI and coding agent — it is not the VS Code Chat format.
  • If your Copilot CLI prompts on every rewrite (a known v1.0.24 bug), use cartoon hook install --copilot --deny for the smoother deny-and-suggest flow. cartoon hook rewrite --deny-mode forces deny anywhere.

Cover what the hook can't: the instructions directive

The hook deliberately won't rewrite a piped command — pytest | tail is split on |, and because a rewrite auto-approves the call, an allowlisted segment must never smuggle the rest past the prompt, so the whole compound is left raw. That's safe, but it means a piped test run silently escapes cartoon (and VS Code Copilot Chat can only deny, never rewrite). The fix the model can act on is an instruction: wrap, and don't pipe.

cartoon instructions writes that directive into your agent's instruction file as an idempotent, marker-delimited block (re-run to update; uninstall removes exactly it, never your own text):

cartoon instructions install            # → ./CLAUDE.md if present, else ./AGENTS.md
cartoon instructions install --agents   # → ./AGENTS.md (force the cross-agent file)
cartoon instructions install --copilot  # → ./.github/copilot-instructions.md
cartoon instructions install --claude   # → ./CLAUDE.md (force)
cartoon instructions status             # per-file: installed / not installed
cartoon instructions uninstall [--copilot | --claude | --agents]
cartoon instructions print              # emit the block (manual paste)

Set up both layers at once — and hook install will hint about the pipe gap (and on a terminal, offer to write the directive for you):

cartoon hook install --instructions     # install the hook AND the directive

No hook? Shell shims (any agent)

For agents without hooks — or as a belt-and-suspenders layer — cartoon shim writes shell functions that shadow the bare tool names and re-invoke them through cartoon. Functions beat both PATH and venv-local binaries, so an activated venv's pytest is still caught, with no agent cooperation:

cartoon shim install     # writes ~/.config/cartoon/shims.sh + activation help
cartoon shim print       # emit the functions to stdout (eval/source them)

Activate for the non-interactive shells agents spawn with export BASH_ENV=~/.config/cartoon/shims.sh; disable per-shell with CARTOON_NO_SHIM=1. Shims wrap the same allowlist as the hook, but (unlike the hook) can't see surrounding pipes, so keep them to tools you run bare.

No hook? MCP server (Cursor, Codex, Windsurf, Claude Desktop)

cartoon mcp serves cartoon over the Model Context Protocol (stdio): a run tool that behaves exactly like cartoon -c '<command>', plus logs_grep, logs_list, last, diff and stats.

claude mcp add cartoon -- cartoon mcp                          # Claude Code
# Cursor / Claude Desktop / Windsurf: {"mcpServers": {"cartoon": {"command": "cartoon", "args": ["mcp"]}}}
# Codex (~/.codex/config.toml): [mcp_servers.cartoon] command = "cartoon", args = ["mcp"]

run executes arbitrary shell commands; your client's tool-approval prompt is the only gate. Config locations, timeouts and the tool reference: docs/agents.md.

Copilot tips & limitations

Tips:

  • Confirmation dialog on every wrapped command? Some Copilot CLI v1.0.24 builds prompt even when the hook approves the rewrite. Reinstall with cartoon hook install --copilot --deny (blocks-and-suggests, no modal). cartoon hook rewrite --deny-mode forces deny anywhere.
  • Share it with the team / coding agent by committing .github/hooks/cartoon.json (cartoon hook install --copilot --project).
  • cartoon hook status reports every surface at once; cartoon shim status shows the shim file.

Limitations:

  • VS Code Copilot Chat can only deny, not rewrite (no updatedInput field exists), so wrapping costs one extra round-trip while the agent re-issues the command.
  • Requires Copilot CLI ≥ v1.0.24 for transparent rewrite; older builds ignore updatedInput — use --deny there.
  • Install to ~/.copilot/hooks or .github/hooks, not a plugin directory — plugin-defined Copilot hooks currently don't fire.
  • Shims can't see pipes/redirection and path-invoked binaries (./gradlew, ./node_modules/.bin/jest) bypass shell functions entirely. Tools whose names aren't valid shell identifiers (pre-commit), plus python -m pytest and xcodebuild, aren't shimmed — the hook covers them.

What it wraps: dev-loop commands only — test runners, linters, typecheckers, builds (pytest, jest, vitest, tsc, eslint, ruff, mypy, make, cargo build|test|check|clippy, go test|build|vet, npm test|t|ci, npm|pnpm|yarn run test, mvnw test, …), including those run through uv (uv run pytest, uvx ruff check, uv run -m pytest). Because a rewrite auto-approves the call, the allowlist is deliberately conservative: infra CLIs (docker, kubectl, terraform, gh, aws) and mutating subcommands (cargo publish, npm install) are never wrapped, a uv run carrying package-adding flags (uv run --with <pkg> …) is left for the normal prompt, commands that change shell state (cd, export, source) pass through untouched, and anything unrecognized is left alone (fail-open). The net-savings guard still applies — worst case the output is byte-identical.

What the hook will not auto-approve (0.7.0)

Because a rewrite is emitted with permissionDecision: "allow", the allowlist is deliberately narrow; anything below reaches your normal permission prompt instead (0.7.0 tightened it further — marked new):

  • A leading NAME=value prefix rides along only for benign names (CI, RUST_LOG, NO_COLOR, …). PATH=… pytest, LD_PRELOAD=… cargo test, NODE_OPTIONS=… jest are left alone.
  • ruff is gated to ruff check; ruff format, --fix, eslint --fix, eslint -c <path>, swiftlint --fix / autocorrect are never wrapped.
  • npx/bunx/pnpx launch only jest, vitest, tsc, eslint.
  • new: flags that load or run code from outside the project are refused per tool: go test -exec/-toolexec, cargo --config/-Z/+toolchain, make -f/-C/NAME=value, jest|vitest --config/--setupFiles…, pytest -p <plugin>/-c/--rootdir, mypy --config-file, gradle -I/-D/-P, mvn -s/-f, dotnet -p: and the like.
  • new: .. paths or absolute paths outside the project, ;/|/|| compounds, and anything with $, backticks, backslashes or globs are never rewritten (only && compounds of eligible commands are).
  • new: PYTEST_ADDOPTS=… no longer rides along; pre-commit is wrapped for run only.
  • make and pre-commit run stay allowlisted by explicit decision: they are the canonical dev-loop entry points and the agent already has write access to the repo. Install with --deny if you disagree.
  • cartoon hook install --deny on an existing install switches the mode in place (and back without the flag).

cartoon doctor shows what is installed where and which allowlisted tools still have no adapter.

Disabling & overhead

  • Disable for a session — set in the environment your agent runs in: export CARTOON_NO_WRAP=1 (hook) or export CARTOON_NO_SHIM=1 (shims). Any non-empty value disables; unset to re-enable.
  • Disable permanently — cartoon hook uninstall [--copilot | --vscode] [--project] and/or cartoon shim uninstall (then drop the BASH_ENV / source line). cartoon hook status shows what's active.
  • One command raw — cartoon --raw <cmd> runs it untouched.
  • Overhead — the per-command hook check is a tiny, fail-open process (negligible). When wrapping, cartoon buffers output (the report prints when the command finishes, not live) and adds parse/encode time proportional to output size — milliseconds in practice, dwarfed by the command itself. Use --raw when you want live streaming.

Use

cartoon pytest                 # asymmetric test report in TOON
cartoon jest src/              # same for jest
cartoon vitest run             # same for vitest (watch mode passes through)
cartoon python -m unittest     # same for unittest
cartoon ruff check .           # lint diagnostics as a compact TOON table
cartoon npx eslint src/        # same for eslint
cartoon npx tsc --noEmit       # same for tsc type errors
cartoon aws ec2 describe-instances --output json   # any JSON CLI → TOON
cartoon make                   # safe tier auto-on: ANSI/progress/dupe collapse
cartoon --compress=aggressive make   # opt-in lossy: level filter, diag tables, windowing
cartoon -c 'cd app && make -j4'      # wrap a shell command string
cartoon ingest ci-run.log      # compress a log you already have
some-cmd | cartoon -           # same, from a pipe
cartoon --raw pytest           # escape hatch: no transformation
cartoon stats --since 7d       # how many tokens you've saved
cartoon learn                  # mine your own runs for config suggestions
cartoon adapters               # list built-in adapters
cartoon init                   # suggest a .cartoon.toml for project wrapper scripts
cartoon --tag api pytest       # tag the archived run
cartoon logs                   # list archived raw logs
cartoon logs --last --stdout   # full raw output of the newest run
cartoon logs grep ERROR --last # search a raw log instead of re-reading it
cartoon last                   # re-show the newest run's report, no re-run
cartoon diff                   # fixed / still failing / new vs the previous run
cartoon --fast pytest          # opt-in: parallel via pytest-xdist (-n auto)
cartoon --junit build/test-results/test gradle test   # any runner that writes JUnit XML
cartoon --max-tokens 1500 make       # hard ceiling: head + tail kept, middle disclosed
cartoon --merge-streams make         # stdout+stderr compressed in arrival order, on stdout
cartoon -c 'pytest -v | tail -5'     # pure output filters are dropped; the report replaces them
cartoon doctor                 # health report: hook, config, allowlist gaps, ledger damage

Pipes inside -c

Agents write pytest -v | tail -5 because they want less output — which is cartoon's whole job. When the string is <adapter-detected command> | <pure output filter> (head, tail, grep, wc, cat, less, more), cartoon runs the adapter and drops the filter, disclosing it as pipe_filter_dropped: "tail -5" in the report. Anything else (tee, xargs, sort, redirections, two pipes, a non-adapter command) keeps the plain sh -c behavior. The hook still never auto-approves a piped compound; this applies only when cartoon -c is invoked explicitly.

--junit: any runner that writes JUnit XML

cartoon --junit <file-or-dir> <cmd> (or [command.<cmd>] junit = "path" in config) renders the XML the command wrote as the same test report pytest gets — gradle, maven, dotnet test --logger junit, phpunit --log-junit, anything. A directory means every *.xml inside, merged. A file older than the run is stale (the build failed before tests ran) and is ignored with a warning so a green report never hides a red build.

--max-tokens: a hard ceiling

cartoon --max-tokens N <cmd> (or CARTOON_MAX_TOKENS=N, or max_tokens in config) guarantees no result exceeds N tokens: the head and tail are kept in whole lines and the middle is replaced by one marker that is itself a ready-to-run cartoon logs grep command. Opt-in, because with a ceiling set even passthrough output may be cut — that is the point. The raw log is archived as always.

cartoon last and cartoon diff: the edit → run → fix loop

Each adapter run (tests, lint, typecheck, build) stores its structured report next to the raw log. cartoon last [--cmd <substring>] re-shows the newest run's report without re-running anything (a run no adapter parsed gets a short summary and its raw_log path). After an edit and a re-run, cartoon diff compares the newest adapter run with the previous run of the same command in the same directory (or cartoon diff <id-a> <id-b>):

command: pytest
previous:
  id: 20261005-225301-ae02
  exit: 1
  failed: 2
current:
  id: 20261005-225302-87f5
  exit: 1
  failed: 2
fixed[1]{id,loc}:
  "test_loop.py::test_alpha","test_loop.py:1"
still_failing[1]{id,loc,msg}:
  "test_loop.py::test_beta","test_loop.py:7","AssertionError: beta is broken"
new_failures[1]{id,loc,msg}:
  "test_loop.py::test_gamma","test_loop.py:11","AssertionError: gamma is broken"

Tests match by id; diagnostics by file + rule + message, so a warning that only moved lines is not reported as fixed. The re-run itself already ends with a one-line vs_previous: fixed 1; still 1; new 1 (cartoon diff) footer. diff exits 0, or 1 when there is no comparable pair. Only these forms are reserved: cartoon diff a.txt b.txt still wraps the system diff.

--merge-streams: keep stdout/stderr interleaving

By default a transformed run writes its compressed stdout first, then its compressed stderr, so a reader of 2>&1 loses where a warning landed among the progress lines. cartoon --merge-streams <cmd> (or merge_streams = true under [compress] or a [command.<name>]; the flag wins, then the command entry, then [compress]) compresses the two streams as one text in arrival order and writes the result to stdout only:

  • Generic output: the ladder runs over the combined text and the guard compares against the combined original. A structured rendering of stdout (JSON as TOON, a sniffed or --junit report) comes first, followed by stderr.
  • Adapter reports: the report stays first on stdout. Any stderr the adapter keeps (an unexplained failure, a tool warning) follows it on stdout instead of going to stderr.
  • Passthrough (nothing paid for itself) is unchanged: both streams are replayed byte-exact to their own fds, in arrival order.

It is off by default because it changes fd semantics: with it on, cartoon --merge-streams cmd 2>/dev/null no longer hides the command's stderr, and a | grep sees stderr lines too. cartoon's own notices (cartoon: …) stay on stderr.

The auto-wrap hook turns it on: its rewrite is cartoon --merge-streams -c '<command>'. Agent shells (Claude Code's Bash tool among them) read a command's stdout and stderr on separate pipes and show stdout first, so the model never sees where a warning landed; merged, it does. The fd caveat above can't bite there: the hook never rewrites a command that carries a redirection or a pipe. Typed cartoon -c stays unmerged unless you pass the flag or set [compress] merge_streams = true.

Content sniffing

Output that arrives without a matching adapter — a ./build.sh that runs xcodebuild internally, fastlane's gym log, a runner printing JUnit XML to stdout — is recognized by shape: xcodebuild build/archive banners get the diagnostics table, XCTest's Test Case … passed/failed protocol gets the test report, JUnit XML gets the test report. Parse-only, never changes the command, and the net-savings guard applies as always.

cartoon doctor

One report for the ways an integration quietly stops saving tokens: hook installed or not per surface, whether the global and project config parse, wrap_scripts entries that do not exist on disk, allowlisted tools that have no adapter (ladder compression only), and ledger health (malformed lines, negative-saved runs, the biggest uncompressed commands). Paste it into a bug report.

Failing test run, before (pytest, ~4800 tokens) vs after (~300 tokens):

runner: pytest
summary:
  total: 48
  passed: 45
  failed: 2
  skipped: 1
  duration_s: 3.2
failures[2]{id,loc,msg}:
  "tests/test_auth.py::test_expiry","tests/test_auth.py:42",assert exp < now
  "tests/test_user.py::test_create","tests/test_user.py:88","KeyError: 'email'"
traces:
  "tests/test_auth.py::test_expiry"[2]: "tests/test_auth.py:42 in test_expiry",assert token.exp < now()

How it works

Every command (or ingested log) moves through one pipeline; the first stage that understands the content wins:

  1. Adapter match — known runners (pytest, jest, vitest, …) get their machine-readable format injected and re-rendered as a compact report.
  2. JSON detection — any JSON document in stdout is TOON-encoded.
  3. Ladder, safe tier (default) — ANSI stripping, progress-bar collapse (only frames that redraw or share one indicator — table rows with percentages are never folded), duplicate-line collapse, blank-run collapse. Deterministic and non-lossy in practice: CRLF line endings are preserved, trailing spaces and tabs are trimmed.
  4. Ladder, aggressive tier (opt-in) — log-level filtering (INFO/DEBUG to counts, WARN+ kept with context), near-duplicate templating, compiler-diagnostic extraction into a TOON table (gcc/clang one-liners and rustc multi-line blocks), error-anchored windowing.
  5. Net-savings guard — the transform plus the raw_log footer must beat the original token count, or the original is emitted byte-identically. Trying cartoon is zero-risk by construction.

Every rule is a pure function that no-ops when its pattern is absent, so plain prose is never mangled. Measured on the golden corpus by the test suite (tests/corpus.rs, part of cargo test; token reduction at the aggressive tier, signal lines asserted intact):

Fixture Reduction Signal kept
chatty service log (156 lines, 1 ERROR) −92.5% ERROR + WARN verbatim, ±2 lines context
real cargo build failure (3 errors) −61.5% all errors + locations in a TOON table
npm ERESOLVE conflict ±0% guard emits the original — never negative

Guarantees

  • Exit codes always mirrored — cartoon pytest && deploy behaves like pytest && deploy.
  • If parsing fails, the original output passes through untouched (one warning on stderr). The safe tier preserves all non-redundant text; lossy tiers are opt-in and always leave a raw_log pointer to the unmodified output. One exception, at any tier: output larger than 4 MiB (useless to an agent whole) is cut to its first 512 KiB, every error line from the middle (up to 200), and its last 1 MiB, behind a marker stating exactly what was omitted; the full text is in raw_log, and if the archive can't be written the original passes through instead.
  • A transform must pay for itself: if the TOON rendering (footer included) wouldn't beat the original token count, the original is emitted byte-identically. When an adapter injects a machine-readable flag (go test -json, --junit-xml, ...), the guard measures against what the command would have printed without that flag (reconstructed from the machine stream), and emits that native output when the report would not beat it — so savings are never negative relative to the command as you typed it (benchmarks).

Raw log archive

Every wrapped run keeps its full raw output under ~/.local/state/cartoon/runs/<run-id>/ (stdout.log, stderr.log, meta.json). Transformed output ends with a raw_log: line pointing at the archive — if the TOON summary dropped something you need, search it with cartoon logs grep <pattern> --last (capped, disclosed) or fetch it with cartoon logs <id> instead of rerunning. Passthrough and --raw output stay byte-identical (no footer) but are still archived. Retention is capped (keep_runs, default 50; max_archive_mb, default 50); keep_runs = 0 disables archiving.

Fast mode

cartoon --fast pytest appends -n auto so pytest-xdist runs the suite in parallel. Strictly opt-in — parallel execution is NOT "same behavior" (test order changes; shared-state tests can flake), so cartoon never enables it on its own and always discloses it with a fast: "-n auto" line in the report. Failures under --fast? Rerun without it before debugging. If pytest-xdist isn't installed, cartoon retries serially once and notes it on stderr. Other runners: no-op (jest is already parallel; unittest has no parallel runner).

Config

~/.config/cartoon/config.toml:

tokenizer = "o200k"  # or "approx" (bytes/4) for zero-cost estimates
trace_lines = 20     # per-failure traceback cap
keep_runs = 50       # archived raw logs to keep (0 disables)
max_archive_mb = 50  # max total archive size
# max_tokens = 1500  # hard output ceiling (see --max-tokens); unset = none

[compress]
level = "safe"       # default for non-adapter output: safe | aggressive
# merge_streams = true  # stdout+stderr in arrival order, on stdout (see --merge-streams)

[command.docker]
level = "aggressive" # per-command pin; CLI --compress wins over config

[command.gradle]
junit = "build/test-results/test"   # render the JUnit XML gradle writes

Compression precedence: --compress flag > --heuristic (deprecated alias for aggressive) > [command.<name>] > wrap_scripts member (aggressive) > [compress] > legacy heuristic key > safe.

cartoon stats reports malformed_lines when the ledger holds lines it could not parse (older versions could interleave two concurrent writes); cartoon learn sees through sh -c runs and explains why a piped command missed its adapter instead of suggesting a [command.sh] pin.

Stats live in ~/.local/state/cartoon/stats.jsonl.

Project config: wrapping build/test scripts

Some projects build through a wrapper script instead of calling a known runner directly — an iOS project's ./build.sh that internally runs xcodegen, then xcodebuild build, then simctl install. The hook's allowlist matches on the command's own first word, so ./build.sh never matches and its output — including xcodebuild's very verbose compile log — reaches the agent completely unwrapped. This is not a hypothetical: a real ./build.sh -d run produced 113,705 raw tokens; the exact same content compresses to 518 tokens (99.5% saved) at the aggressive tier once it's actually routed through cartoon.

Declare such scripts in a project-local .cartoon.toml (repo root, or any ancestor up to the .git boundary):

wrap_scripts = ["./build.sh"]

A declared script compresses at the aggressive tier by default — the safe tier compresses none of this kind of output (see the numbers above). Pin [command."./build.sh"] level = "safe" to override. Run cartoon init in the repo to scan for *.sh files that mention a known noisy tool (xcodebuild, swift test/build, pytest, cargo test/build, ...) and print this snippet ready to paste. The hook matches the script whether you invoke it as ./build.sh, build.sh, bash ./build.sh, or by absolute path.

A declared script is never auto-approved. The built-in allowlist (pytest, cargo test, swift test, ...) gets a transparent rewrite — permissionDecision: "allow" — because those are vetted, globally-known, read-mostly tools. A project's own script is arbitrary code: an iOS build.sh can install a build onto a physical device, or push model weights to one. .cartoon.toml is also repo-committed and agent-writable, so treating a declaration as license to bypass the permission prompt would turn adding one TOML line into a silent permission-bypass primitive. Instead, a wrap_scripts match always denies-with-suggestion: the raw command is blocked and the agent is told to re-run it as cartoon -c './build.sh -d', going through the normal permission flow for that explicit call. Want it frictionless? Allowlist that exact string in your agent's own permission settings — that's the right layer for that decision, not cartoon's.

Adapters

Adapter Trigger Source
pytest pytest, python -m pytest, uv run [-m] pytest, uvx pytest, poetry/pdm/hatch/pipenv/rye run pytest injected --junit-xml
unittest python -m unittest, uv run [python] -m unittest stderr text parse
jest jest, npx jest injected --json
vitest vitest run (watch mode passes through) injected --reporter=json
swift-test swift test injected --xunit-output + --parallel (merges XCTest + Swift Testing files)
xcodebuild-test xcodebuild test injected -resultBundlePath, parsed via xcresulttool … test-results summary (Xcode 16+)
ruff ruff check injected --output-format json
eslint eslint, npx eslint injected --format json
tsc tsc, npx tsc (not --watch) injected --pretty false
swift-build swift build stdout/stderr text parse
xcodebuild-build xcodebuild build / archive / -exportArchive (no test action) stdout/stderr diagnostics parse
pre-commit pre-commit, pre-commit run … stdout text parse (--color=never injected)
cargo-test cargo test, cargo nextest run stable text parse (never nightly JSON)
cargo-build cargo build, cargo check, cargo clippy injected --message-format=json (before --)
go-test go test injected -json
mypy mypy, python -m mypy, uv run mypy injected --output json
phpunit phpunit, vendor/bin/phpunit injected --log-junit
rspec rspec, bundle exec rspec injected --format json --out <file>
swiftlint swiftlint, swiftlint lint (never --fix/autocorrect) injected --reporter json
gradle gradle/./gradlew test, check, build, *Test tasks (not --continuous) nothing injected: the build/test-results/**/TEST-*.xml files this run wrote (every module), plus javac/kotlinc errors and failed tasks from the console
maven mvn/./mvnw test, verify, package, install (not -DskipTests) nothing injected: the target/{surefire,failsafe}-reports/TEST-*.xml files this run wrote (every module), plus compiler errors and failed goals
dotnet-test dotnet test (VSTest; not Microsoft.Testing.Platform) injected --logger trx --results-directory <temp> (a user's own trx logger / results directory is kept), one .trx per test project, plus MSBuild errors
golangci-lint golangci-lint run injected --output.json.path=stdout (v2) or --out-format json (v1), picked by --version
pkg-script npm test, npm run test, pnpm test, yarn test, bun run test when package.json's test script is a plain jest … / vitest … (no &&, pipes, quotes, pretest/posttest; a bare vitest only when it would not watch) the jest / vitest adapter's flags, forwarded to the script (after -- for npm)

No adapter match → content sniffing (xcodebuild / XCTest / JUnit shapes) → JSON auto-detection → compression ladder (safe tier by default, aggressive opt-in) → passthrough when nothing pays for itself. Hook-allowlisted tools with no adapter (make, dotnet build, bun test, an npm test whose script is not plain jest/vitest, …) get the ladder only; cartoon doctor lists them.

Want another runner (bun test, deno test, ...)? See CONTRIBUTING.md — adapters are one trait impl + fixtures. The roadmap lives in docs/superpowers/specs/2026-06-11-cartoon-v02-roadmap.md.

Support

If cartoon saves you tokens, a ⭐ on this repo helps other agent users find it — and cartoon stats will tell you exactly how much it earned one.

License

MIT

Metadata

Release files for cartoon 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cartoon 0.7.0
File Size Uploaded
cartoon-0.7.0.tar.gz 290.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cartoon 0.7.0
File
cartoon-0.7.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
cartoon-0.7.0-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
cartoon-0.7.0-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
cartoon-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
cartoon-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
cartoon-0.7.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
cartoon-0.7.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 26.6 MB

Release files / cartoon-0.7.0.tar.gz

Download URL cartoon-0.7.0.tar.gz
Size 290.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8c0004323a227b2d4a01f3f8dfa79129f6d5a08f18733246862201480ff5972b
BLAKE2b-256 checksum
How to use checksums
b75aa1fd9b39e4ccd12f9f3bcff6e418ca833ddb9ad1546be030843128b67474
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-win_amd64.whl

Download URL cartoon-0.7.0-py3-none-win_amd64.whl
Size 3.8 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
bbba3b73c0019c0576ed53510a71cbfe2ecf5a6b9e3f52acfa74ec9ce13a91d0
BLAKE2b-256 checksum
How to use checksums
d405ef25e11802c53b4cda629c5dee26a72202f2991bea431fbf0e9b686ffb5d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-musllinux_1_2_x86_64.whl

Download URL cartoon-0.7.0-py3-none-musllinux_1_2_x86_64.whl
Size 3.9 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
9c3168e2ca6962d6f507bca7ffd8fee2abac40c3e3e16dff7df1a47432586610
BLAKE2b-256 checksum
How to use checksums
732af0e3a47a94a57317789a003aa96b91972921dd9e8e12c3839b52d62aa3f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-musllinux_1_2_aarch64.whl

Download URL cartoon-0.7.0-py3-none-musllinux_1_2_aarch64.whl
Size 3.7 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
e10f9472999863a9d7f929ad873de415a69f752b89769a25aea84236336d877a
BLAKE2b-256 checksum
How to use checksums
93d18ad7e5b960b8db4fda1d08693a463993c7efe07baf8a57621d392ae766fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL cartoon-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 3.8 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
4dc88464ba77445a22aac612325d7d03ca7561134719d15e22680f7f569f0320
BLAKE2b-256 checksum
How to use checksums
0ae759ce66781584058d2bf220d610f377ad3bdf6aa41517ae06ae8ff84c85e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL cartoon-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 3.7 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
525c7e726d2a7c13b60a6e9dc2ff55a03ae1ad3ca11fd0c3c406be134eebaeb5
BLAKE2b-256 checksum
How to use checksums
21405e950c1ccdf09bb44dc58c22b8999feb233ecdf07bd6c08f202844d1409e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-macosx_11_0_arm64.whl

Download URL cartoon-0.7.0-py3-none-macosx_11_0_arm64.whl
Size 3.7 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
fbf9e0d879e68202f49e586f4b5279b4aa77eda921f80d28d547badef0f7531a
BLAKE2b-256 checksum
How to use checksums
b523bbdb7669d8ab460f9e32f7c32522f8bdf0daa24e890341e03ce1bbf1cbec
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release files / cartoon-0.7.0-py3-none-macosx_10_12_x86_64.whl

Download URL cartoon-0.7.0-py3-none-macosx_10_12_x86_64.whl
Size 3.7 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
c45534eb0fc1e1ca2e88a441407df47a37aabae1c8ecfdcb556e77d527aeac02
BLAKE2b-256 checksum
How to use checksums
5b495c736df2631ba2dd1877e4e626d7e281b7b3fdd5caa7b679ece6bdf26f73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.0 This release

8 release files

0.6.0

5 release files

0.5.1

5 release files

0.5.0

5 release files

0.4.0

5 release files

0.2.0

5 release files

0.1.1

5 release files

0.1.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page