CLI proxy that reduces LLM token consumption by filtering command outputs
Project description
pytk — Python Token Killer
CLI proxy that reduces LLM token consumption by 75–92% by filtering and compressing shell command outputs before they reach AI context.
When AI coding agents (Claude Code, Codex, Cursor, Hermes, etc.) run shell commands, the raw verbose output wastes thousands of tokens per session. pytk sits transparently between the agent and the shell — stripping noise, keeping only what matters.
Token Savings (30-min AI Coding Session)
| Operation | Frequency | Without pytk | With pytk | Savings |
|---|---|---|---|---|
ls / find |
10× | ~8,000 | ~2,000 | -75% |
cat / read |
20× | ~60,000 | ~12,000 | -80% |
grep / rg |
8× | ~10,000 | ~1,800 | -82% |
git status |
10× | ~6,000 | ~1,200 | -80% |
git diff |
5× | ~6,000 | ~600 | -90% |
git push/commit |
8× | ~1,600 | ~128 | -92% |
pytest / go test |
5× | ~10,000 | ~750 | -92% |
| Total | ~101,600 | ~18,478 | -82% |
Installation
# Recommended — installs as isolated global tool
uv tool install pytk
# Or with pip
pip install pytk
# Verify
pytk --help
Quick Start
pytk is a drop-in prefix — just add pytk before any supported command:
pytk ls -la src/
pytk git status
pytk git diff HEAD~1
pytk pytest tests/ -v
pytk grep "def run" src/ -r
pytk cat README.md
That's it. Same flags, same arguments — just compressed output.
Tutorial
1. See the difference
Let's compare raw vs filtered output side by side.
Raw git status (~800 tokens):
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update index)
(use "git restore <file>..." to discard changes in working directory)
modified: src/pytk/cli.py
modified: src/pytk/filters/git.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
tests/test_new.py
no changes added to commit (use "git add" and/or "git commit -a")
pytk git status (~80 tokens):
modified: src/pytk/cli.py
modified: src/pytk/filters/git.py
untracked: tests/test_new.py
2. Test output compression
Raw pytest (200+ lines, ~4,000 tokens):
collected 49 items
tests/test_cli.py::test_gain_no_stats PASSED [ 2%]
tests/test_cli.py::test_list_filters PASSED [ 4%]
tests/test_filters_git.py::test_git_status_strips_hints PASSED [ 6%]
... (46 more passing lines)
tests/test_filters_git.py::test_git_push_compressed FAILED [ 95%]
FAILURES
=========
...long traceback...
pytk pytest tests/ (~15 lines, ~300 tokens):
FAILED: tests/test_filters_git.py::test_git_push_compressed
AssertionError: expected 'ok main' got 'ok main → origin/main'
1 failed, 48 passed in 0.14s
3. Track your savings
Every filtered command appends stats to ~/.pytk/stats.json. View cumulative savings:
pytk gain
Output:
pytk Token Savings
┌──────────┬──────┬─────────────┬─────────────┬───────────┐
│ Command │ Runs │ Orig tokens │ Filt tokens │ Reduction │
├──────────┼──────┼─────────────┼─────────────┼───────────┤
│ git │ 12 │ 14,400 │ 1,440 │ 90% │
│ pytest │ 5 │ 40,000 │ 3,000 │ 92% │
│ ls │ 8 │ 6,400 │ 1,600 │ 75% │
│ grep │ 6 │ 7,500 │ 1,350 │ 82% │
│ cat │ 4 │ 12,000 │ 2,400 │ 80% │
│ TOTAL │ 35 │ 80,300 │ 9,790 │ 88% │
└──────────┴──────┴─────────────┴─────────────┴───────────┘
4. Escape hatch
Output looks wrong? Use passthrough to get raw unfiltered output:
pytk passthrough git log --oneline --graph
5. See all filters
pytk list-filters
AI Agent Integration
Claude Code
Run this in your project root:
pytk init --agent claude
Then paste the output into your CLAUDE.md. Claude will automatically prefix commands with pytk.
Or add manually to CLAUDE.md:
## Shell Commands
Always use `pytk <cmd>` instead of running shell commands directly.
This reduces token usage by filtering verbose output.
Examples:
pytk ls -la src/
pytk git status
pytk git diff HEAD~1
pytk pytest tests/
pytk grep 'pattern' src/ -r
pytk cat file.py
Hermes Agent
pytk init --agent hermes
Or add to your Hermes system prompt / skill:
# Use pytk for all shell commands to reduce token usage
# pytk ls, pytk git, pytk pytest, pytk grep, pytk cat
Codex / OpenAI Agents
pytk init --agent codex
Adds a section to AGENTS.md instructing Codex to use pytk for shell commands.
Any agent (generic)
The key principle: instruct your agent to prefix shell commands with pytk. The agent doesn't need to know anything about pytk internals — it just uses it like a regular command.
## Token Efficiency
Prefix all shell commands with `pytk` to reduce output verbosity:
pytk ls, pytk git status, pytk pytest, pytk grep, pytk cat
Supported Commands
| Command | Filter | What's removed | Savings |
|---|---|---|---|
ls, find, tree |
LsFilter | permissions, uid, gid, size, timestamps | ~75% |
git status |
GitFilter | hints, tracking info, usage instructions | ~80% |
git diff |
GitFilter | index xxxx..yyyy lines, keeps hunks |
~90% |
git log |
GitFilter | author, date — keeps hash + message only | ~80% |
git push/commit/merge |
GitFilter | progress lines, compressed to 1 line | ~92% |
pytest, python -m pytest |
TestFilter | passing test lines, progress bars | ~92% |
go test, cargo test, npm test |
TestFilter | passing test lines, progress bars | ~92% |
grep, rg, ag |
GrepFilter | binary matches, excess per-file results | ~82% |
cat, head, tail |
CatFilter | middle of long files, excess blank lines | ~80% |
Commands not in the list pass through unmodified — always safe to prefix with pytk.
CLI Reference
pytk <command> [args...] # Run command with filter applied
pytk gain # Show cumulative token savings
pytk init [--agent NAME] # Print agent integration snippet
pytk passthrough <cmd> [args] # Run without filtering
pytk list-filters # Show all filters + example savings
--agent options: claude, hermes, codex (default: prints all)
Contributing
git clone https://github.com/unrealandychan/pytk
cd pytk
uv sync --extra dev
pytest tests/ -v
Adding a new filter
- Create
src/pytk/filters/myfilter.pyextendingBaseFilter:
from pytk.filters.base import BaseFilter
class DockerFilter(BaseFilter):
def matches(self, cmd: list[str]) -> bool:
return bool(cmd) and cmd[0] == "docker"
def filter(self, output: str, cmd: list[str]) -> str:
# your compression logic
return output
def savings_example(self) -> dict:
return {"before": 500, "after": 100, "description": "docker ps with 10 containers"}
- Register in
src/pytk/filters/registry.py:
from pytk.filters.myfilter import DockerFilter
FILTERS = [..., DockerFilter()]
- Add tests in
tests/test_filters_myfilter.py - Open a PR 🎉
Roadmap
-
docker ps / logs / buildfilter -
kubectl get / describe / logsfilter -
npm install / yarnfilter -
curl/httpresponse filter - Shell hook mode (auto-intercept without explicit
pytkprefix) - VS Code extension
License
MIT — © 2026 unrealandychan
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytk_cli-0.2.0.tar.gz.
File metadata
- Download URL: pytk_cli-0.2.0.tar.gz
- Upload date:
- Size: 47.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
250721d8304424d19e7e9e9b8240837e7f8014eee54794ca759a3d4d7284838c
|
|
| MD5 |
69c13a060a68df19cb5c7047e81abf82
|
|
| BLAKE2b-256 |
3f2e9924c82a88cd9755f401b07204083f9f992883cd12f3f2cdfa495bd83790
|
File details
Details for the file pytk_cli-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pytk_cli-0.2.0-py3-none-any.whl
- Upload date:
- Size: 35.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1097d6977f94342beb40bed3a6a277c94fc3d887848a33e948c0e2436b66ead
|
|
| MD5 |
3efa1face896524805b8a19ca51512cd
|
|
| BLAKE2b-256 |
457df8f849f2c6948ab0cc14d04d3ed6b32185a8ba8e02f8897754e09c0b669a
|