Tooling gotcha — RTK silently corrupts some shell commands
RTK (the token-optimizing CLI proxy that auto-rewrites shell commands via a Claude Code hook) does not just filter output — for some commands it mutates the command itself before running it, producing wrong results with no obvious sign that RTK was the cause. Two failure modes confirmed:
curl <url>gets the URL corrupted, and certain pipes/find-counts return empty or zeroed output.
This was hit while trying to fetch the actionlint binary during the FKITDEV-8239 review — curl failed, python3 urllib worked. It is the same family of hazard as rtk-git-log-hides-merge-commits (RTK output-filtering hides merge commits) and the long-standing RTK pipe-count mangling note in agent memory.
Symptoms (confirmed)
curl — malformed URL
curl: (3) URL using bad/illegal format or missing URL
# (libcurl: "Malformed input to a URL function")
RTK’s Rust proxy corrupts the URL string it passes through, so even a well-formed curl https://… fails with curl error (3). wget is also unreliable through the proxy.
Pipes / counts — empty or zeroed output
ls | sortreturned empty.find … | wc -land… | grep -c …get zeroed (count comes back0even when matches exist).- A
find … -o …expression came back empty during this same session.
The danger is that a zeroed count or empty listing looks like a legitimate “no results” answer — you can draw the wrong conclusion (e.g. “no file matches”) instead of realizing the command was mangled.
Workarounds — bypass RTK with python3
python3 is not rewritten by the hook — route the real work through it
The proxy rewrites the shell command, but a
python3one-liner runs the actual logic inside the interpreter where RTK can’t touch the URL or the pipeline.
Download a file (instead of curl/wget):
python3 -c "import urllib.request,sys; urllib.request.urlretrieve(sys.argv[1], sys.argv[2])" <url> <dest>This is exactly how the actionlint binary was fetched after curl failed with error (3).
Run a multi-step CLI check (instead of a shell pipeline):
python3 - <<'EOF'
import subprocess
r = subprocess.run(["some-tool", "--flag", "arg"], capture_output=True, text=True)
print(r.returncode, r.stdout, r.stderr)
EOFUse subprocess.run([...]) with an argv list (no shell=True) so the command never round-trips through the rewriting hook. This sidesteps both the URL corruption and the pipe mangling. The vault scans in this very session (find files / grep contents) were done this way after find/grep returned empty.
Counts — cross-check two independent methods:
Don’t trust a single | wc -l / | grep -c. Compute the count two different ways (e.g. git ls-tree + a python len([...])) and confirm they agree before relying on the number. (See the agent-memory rtk-pipe-count-mangling note for the git-specific recipe.)
Escape hatch: rtk proxy <cmd> runs a command raw/unfiltered, but the user generally prefers agents avoid it — reach for the python bypass above first.
Related
- rtk-git-log-hides-merge-commits — sibling RTK gotcha: output-filtering drops merge commits from
git log --graph; use%p/rev-list --parentsplumbing instead. - RTK — the token-optimizing CLI proxy whose command rewriting causes this.
- FKITDEV-8239 — the depcheck-CI review during which the
curl-fails / python-urllib-works case was hit.